* Many files: change all bfd_target vectors to be const. Change
[external/binutils.git] / bfd / tekhex.c
1 /* BFD backend for Extended Tektronix Hex Format  objects.
2    Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
3
4    Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
5
6 This file is part of BFD, the Binary File Descriptor library.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
21
22 /*
23 SUBSECTION
24         Tektronix Hex Format handling
25
26 DESCRIPTION
27         
28         Tek Hex records can hold symbols and data, but not
29         relocations. Their main application is communication with
30         devices like PROM programmers and ICE equipment.
31         
32         It seems that the sections are descibed as being really big,
33         the example I have says that the text section is 0..ffffffff.
34         BFD would barf with this, many apps would try to alloc 4GB to
35         read in the file.
36
37         Tex Hex may contain many sections, but the data which comes in
38         has no tag saying which section it belongs to, so we create
39         one section for each block of data, called "blknnnn" which we
40         stick all the data into.
41
42         TekHex may come out of  order and there is no header, so an
43         initial scan is required  to discover the minimum and maximum
44         addresses used to create the vma and size of the sections we
45         create.
46         We read in the data into pages of CHUNK_MASK+1 size and read
47         them out from that whenever we need to.
48
49         Any number of sections may be created for output, we save them
50         up and output them when it's time to close the bfd.
51
52
53         A TekHex record looks like:
54 EXAMPLE
55         %<block length><type><checksum><stuff><cr>
56         
57 DESCRIPTION
58         Where
59         o length
60         is the number of bytes in the record not including the % sign.
61         o type
62         is one of:
63         3) symbol record
64         6) data record
65         8) termination record
66         
67
68 The data can come out of order, and may be discontigous. This is a
69 serial protocol, so big files are unlikely, so we keep a list of 8k chunks
70 */
71
72 #include "bfd.h"
73 #include "sysdep.h"
74 #include "libbfd.h"
75
76 typedef struct
77   {
78     bfd_vma low;
79     bfd_vma high;
80   } addr_range_type;
81
82 typedef struct tekhex_symbol_struct
83   {
84
85     asymbol symbol;
86     struct tekhex_symbol_struct *prev;
87
88   } tekhex_symbol_type;
89
90 static char digs[] = "0123456789ABCDEF";
91
92 static char sum_block[256];
93
94 /* Horrible ascii dependent macros for converting between hex and
95    binary */
96
97 #define CHARS_IN_SET 256
98 static char hex_value[CHARS_IN_SET];
99
100 #define NOT_HEX 20
101 #define NIBBLE(x) hex_value[x]
102 #define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1]))
103 #define TOHEX(d,x) \
104 (d)[1] = digs[(x) & 0xf]; \
105 (d)[0] = digs[((x)>>4)&0xf];
106 #define ISHEX(x)  (hex_value[x] != NOT_HEX)
107
108 /*
109 Here's an example
110 %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75
111 %1B3709T_SEGMENT1108FFFFFFFF
112 %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10
113 %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710
114 %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10
115 %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10
116 %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10
117 %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10
118 %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010
119 %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10
120 %2734D9T_SEGMENT8Bvoid$t15$151035_main10
121 %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110
122 %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214
123 %07 8 10 10
124
125 explanation:
126 %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75
127  ^ ^^ ^     ^-data
128  | || +------ 4 char integer 0x8000
129  | |+-------- checksum
130  | +--------- type 6 (data record)
131  +----------- length 3a chars
132  <---------------------- 3a (58 chars) ------------------->
133
134 %1B3709T_SEGMENT1108FFFFFFFF
135       ^         ^^ ^- 8 character integer 0xffffffff
136       |         |+-   1 character integer 0
137       |         +--   type 1 symbol (section definition)
138       +------------   9 char symbol T_SEGMENT
139
140 %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10
141 %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710
142 %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10
143 %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10
144 %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10
145 %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10
146 %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010
147 %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10
148 %2734D9T_SEGMENT8Bvoid$t15$151035_main10
149 %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110
150 %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214
151 %0781010
152
153 Turns into
154 sac@thepub$ ./objdump -dx -m m68k f
155
156 f:     file format tekhex
157 -----x--- 9/55728 -134219416 Sep 29 15:13 1995 f
158 architecture: UNKNOWN!, flags 0x00000010:
159 HAS_SYMS
160 start address 0x00000000
161 SECTION 0 [D00000000]   : size 00020000 vma 00000000 align 2**0
162  ALLOC, LOAD
163 SECTION 1 [D00008000]   : size 00002001 vma 00008000 align 2**0
164
165 SECTION 2 [T_SEGMENT]   : size ffffffff vma 00000000 align 2**0
166
167 SYMBOL TABLE:
168 00000000  g       T_SEGMENT gcc_compiled$
169 00000000  g       T_SEGMENT hello$c
170 00000000  g       T_SEGMENT int$t1$r1$$21474
171 00000000  g       T_SEGMENT char$t2$r2$0$127
172 00000000  g       T_SEGMENT long$int$t3$r1$$
173 00000000  g       T_SEGMENT unsigned$int$t4$
174 00000000  g       T_SEGMENT long$unsigned$in
175 00000000  g       T_SEGMENT short$int$t6$r1$
176 00000000  g       T_SEGMENT long$long$int$t7
177 00000000  g       T_SEGMENT short$unsigned$i
178 00000000  g       T_SEGMENT long$long$unsign
179 00000000  g       T_SEGMENT signed$char$t10$
180 00000000  g       T_SEGMENT unsigned$char$t1
181 00000000  g       T_SEGMENT float$t12$r1$4$0
182 00000000  g       T_SEGMENT double$t13$r1$8$
183 00000000  g       T_SEGMENT long$double$t14$
184 00000000  g       T_SEGMENT void$t15$15
185 00000000  g       T_SEGMENT _main
186 00000000  g       T_SEGMENT $
187 00000000  g       T_SEGMENT $
188 00000000  g       T_SEGMENT $
189 00000010  g       T_SEGMENT $
190 00000000  g       T_SEGMENT main$F1
191 fcffffff  g       T_SEGMENT i$1
192 00000000  g       T_SEGMENT $
193 00000010  g       T_SEGMENT $
194
195
196 RELOCATION RECORDS FOR [D00000000]: (none)
197
198 RELOCATION RECORDS FOR [D00008000]: (none)
199
200 RELOCATION RECORDS FOR [T_SEGMENT]: (none)
201
202 Disassembly of section D00000000:
203 ...
204 00008000 ($+)7ff0 linkw fp,#-4
205 00008004 ($+)7ff4 nop
206 00008006 ($+)7ff6 movel #99,d0
207 00008008 ($+)7ff8 cmpl fp@(-4),d0
208 0000800c ($+)7ffc blts 00008014 ($+)8004
209 0000800e ($+)7ffe addql #1,fp@(-4)
210 00008012 ($+)8002 bras 00008006 ($+)7ff6
211 00008014 ($+)8004 unlk fp
212 00008016 ($+)8006 rts
213 ...
214
215 */
216
217 static void
218 tekhex_init ()
219 {
220   unsigned int i;
221   static boolean inited = false;
222   int val;
223
224   if (inited == false)
225     {
226
227       inited = true;
228
229       for (i = 0; i < CHARS_IN_SET; i++)
230         {
231           hex_value[i] = NOT_HEX;
232         }
233
234       for (i = 0; i < 10; i++)
235         {
236           hex_value[i + '0'] = i;
237
238         }
239       for (i = 0; i < 6; i++)
240         {
241           hex_value[i + 'a'] = i + 10;
242           hex_value[i + 'A'] = i + 10;
243         }
244       val = 0;
245       for (i = 0; i < 10; i++)
246         {
247           sum_block[i + '0'] = val++;
248         }
249       for (i = 'A'; i <= 'Z'; i++)
250         {
251           sum_block[i] = val++;
252         }
253       sum_block['$'] = val++;
254       sum_block['%'] = val++;
255       sum_block['.'] = val++;
256       sum_block['_'] = val++;
257       for (i = 'a'; i <= 'z'; i++)
258         {
259           sum_block[i] = val++;
260         }
261     }
262 }
263
264 /* The maximum number of bytes on a line is FF */
265 #define MAXCHUNK 0xff
266 /* The number of bytes we fit onto a line on output */
267 #define CHUNK 21
268
269 /* We cannot output our tekhexords as we see them, we have to glue them
270    together, this is done in this structure : */
271
272 struct tekhex_data_list_struct
273 {
274   unsigned char *data;
275   bfd_vma where;
276   bfd_size_type size;
277   struct tekhex_data_list_struct *next;
278
279 };
280 typedef struct tekhex_data_list_struct tekhex_data_list_type;
281
282 #define CHUNK_MASK 0x1fff
283
284 struct data_struct
285   {
286     char chunk_data[CHUNK_MASK + 1];
287     char chunk_init[CHUNK_MASK + 1];
288     bfd_vma vma;
289     struct data_struct *next;
290   };
291
292 typedef struct tekhex_data_struct
293 {
294   tekhex_data_list_type *head;
295   unsigned int type;
296   struct tekhex_symbol_struct *symbols;
297   struct data_struct *data;
298 } tdata_type;
299
300 #define enda(x) (x->vma + x->size)
301
302 static bfd_vma
303 getvalue (srcp)
304      char **srcp;
305 {
306   char *src = *srcp;
307   bfd_vma value = 0;
308   unsigned int len = hex_value[*src++];
309
310   if (len == 0)
311     len = 16;
312   while (len--)
313     {
314       value = value << 4 | hex_value[*src++];
315     }
316   *srcp = src;
317   return value;
318 }
319
320 static unsigned int
321 getsym (dstp, srcp)
322      char *dstp;
323      char **srcp;
324 {
325   char *src = *srcp;
326   unsigned int i;
327   unsigned int len = hex_value[*src++];
328
329   if (len == 0)
330     len = 16;
331   for (i = 0; i < len; i++)
332     dstp[i] = src[i];
333   dstp[i] = 0;
334   *srcp = src + i;
335   return len;
336 }
337
338 struct data_struct *
339 find_chunk (abfd, vma)
340      bfd *abfd;
341      bfd_vma vma;
342 {
343   struct data_struct *d = abfd->tdata.tekhex_data->data;
344
345   vma &= ~CHUNK_MASK;
346   while (d && (d->vma) != vma)
347     {
348       d = d->next;
349     }
350   if (!d)
351     {
352       char *sname = bfd_alloc (abfd, 12);
353       asection *s;
354
355       /* No chunk for this address, so make one up */
356       d = (struct data_struct *)
357         bfd_alloc (abfd, sizeof (struct data_struct));
358
359       if (!sname || !d)
360         {
361           bfd_set_error (bfd_error_no_memory);
362           return NULL;
363         }
364
365       memset (d->chunk_init, 0, CHUNK_MASK + 1);
366       memset (d->chunk_data, 0, CHUNK_MASK + 1);
367       d->next = abfd->tdata.tekhex_data->data;
368       d->vma = vma;
369       abfd->tdata.tekhex_data->data = d;
370     }
371   return d;
372 }
373
374 static void
375 insert_byte (abfd, value, addr)
376      bfd *abfd;
377      int value;
378      bfd_vma addr;
379 {
380   /* Find the chunk that this byte needs and put it in */
381   struct data_struct *d = find_chunk (abfd, addr);
382
383   d->chunk_data[addr & CHUNK_MASK] = value;
384   d->chunk_init[addr & CHUNK_MASK] = 1;
385 }
386
387 /* The first pass is to find the names of all the sections, and see
388   how big the data is */
389 static void
390 first_phase (abfd, type, src)
391      bfd *abfd;
392      char type;
393      char *src;
394 {
395   asection *section = &bfd_abs_section;
396   int len;
397   char sym[17];                 /* A symbol can only be 16chars long */
398
399   switch (type)
400     {
401     case '6':
402       /* Data record - read it and store it */
403       {
404         bfd_vma addr = getvalue (&src);
405
406         while (*src)
407           {
408             insert_byte (abfd, HEX (src), addr);
409             src += 2;
410             addr++;
411           }
412       }
413
414       return;
415     case '3':
416       /* Symbol record, read the segment */
417       len = getsym (sym, &src);
418       section = bfd_get_section_by_name (abfd, sym);
419       if (section == (asection *) NULL)
420         {
421           char *n = bfd_alloc (abfd, len + 1);
422
423           if (!n)
424             {
425               bfd_set_error (bfd_error_no_memory);
426               abort();          /* FIXME */
427             }
428           memcpy (n, sym, len + 1);
429           section = bfd_make_section (abfd, n);
430         }
431       while (*src)
432         {
433           switch (*src)
434             {
435               asection *s;
436
437             case '1':           /* section range */
438               src++;
439               section->vma = getvalue (&src);
440               section->_raw_size = getvalue (&src) - section->vma;
441               section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC;
442               break;
443
444             case '2':
445             case '3':
446             case '4':
447             case '6':
448             case '7':
449             case '8':
450               /* Symbols, add to section */
451               {
452                 tekhex_symbol_type *new =
453                 (tekhex_symbol_type *) bfd_alloc (abfd,
454                                                sizeof (tekhex_symbol_type));
455                 char type = (*src);
456
457                 if (!new)
458                   {
459                     bfd_set_error (bfd_error_no_memory);
460                     abort();    /* FIXME */
461                   }
462                 new->symbol.the_bfd = abfd;
463                 src++;
464                 abfd->symcount++;
465                 abfd->flags |= HAS_SYMS;
466                 new->prev = abfd->tdata.tekhex_data->symbols;
467                 abfd->tdata.tekhex_data->symbols = new;
468                 len = getsym (sym, &src);
469                 new->symbol.name = bfd_alloc (abfd, len + 1);
470                 if (!new->symbol.name)
471                   {
472                     bfd_set_error (bfd_error_no_memory);
473                     abort();    /* FIXME */
474                   }
475                 memcpy ((char *) (new->symbol.name), sym, len + 1);
476                 new->symbol.section = section;
477                 if (type <= '4')
478                   new->symbol.flags = (BSF_GLOBAL | BSF_EXPORT);
479                 else
480                   new->symbol.flags = BSF_LOCAL;
481                 new->symbol.value = getvalue (&src) - section->vma;
482               }
483             }
484         }
485     }
486 }
487
488 /* Pass over an tekhex, calling one of the above functions on each
489    record.  */
490
491 static void
492  pass_over (abfd, func)
493      bfd *abfd;
494      void (*func) ();
495 {
496   unsigned int chars_on_line;
497   boolean eof = false;
498
499   /* To the front of the file */
500   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0)
501     abort ();
502   while (eof == false)
503     {
504       char buffer[MAXCHUNK];
505       char *src = buffer;
506       char type;
507       bfd_vma address = 0;
508
509       /* Find first '%' */
510       eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
511       while (*src != '%' && !eof)
512         {
513           eof = (boolean) (bfd_read (src, 1, 1, abfd) != 1);
514         }
515       if (eof)
516         break;
517       src++;
518
519       /* Fetch the type and the length and the checksum */
520       if (bfd_read (src, 1, 5, abfd) != 5)
521         abort (); /* FIXME */
522
523       type = src[2];
524
525       if (!ISHEX (src[0]) || !ISHEX (src[1]))
526         break;
527
528       chars_on_line = HEX (src) - 5;    /* Already read five char */
529
530       if (bfd_read (src, 1, chars_on_line, abfd) != chars_on_line)
531         abort (); /* FIXME */
532       src[chars_on_line] = 0;   /* put a null at the end */
533
534       func (abfd, type, src);
535     }
536
537 }
538
539 long
540 tekhex_get_symtab (abfd, table)
541      bfd *abfd;
542      asymbol **table;
543
544 {
545   tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols;
546   unsigned int c = bfd_get_symcount (abfd);
547
548   table[c] = 0;
549   while (p)
550     {
551       table[--c] = &(p->symbol);
552       p = p->prev;
553     }
554
555   return bfd_get_symcount (abfd);
556 }
557
558 long
559 tekhex_get_symtab_upper_bound (abfd)
560      bfd *abfd;
561 {
562   return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *));
563
564 }
565
566 static boolean
567 tekhex_mkobject (abfd)
568      bfd *abfd;
569 {
570   tdata_type *tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type));
571
572   if (!tdata)
573     {
574       bfd_set_error (bfd_error_no_memory);
575       return false;
576     }
577   abfd->tdata.tekhex_data = tdata;
578   tdata->type = 1;
579   tdata->head = (tekhex_data_list_type *) NULL;
580   tdata->symbols = (struct tekhex_symbol_struct *) NULL;
581   tdata->data = (struct data_struct *) NULL;
582   return true;
583 }
584
585 /*
586   Return true if the file looks like it's in TekHex format. Just look
587   for a percent sign and some hex digits */
588
589 static const bfd_target *
590 tekhex_object_p (abfd)
591      bfd *abfd;
592 {
593   char b[4];
594   asection *section;
595
596   tekhex_init ();
597
598   if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0
599       || bfd_read (b, 1, 4, abfd) != 4)
600     return NULL;
601
602   if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3]))
603     return (const bfd_target *) NULL;
604
605   tekhex_mkobject (abfd);
606
607   pass_over (abfd, first_phase);
608   return abfd->xvec;
609 }
610
611 static boolean
612 move_section_contents (abfd, section, locationp, offset, count, get)
613      bfd *abfd;
614      asection *section;
615      PTR locationp;
616      file_ptr offset;
617      bfd_size_type count;
618      boolean get;
619 {
620   bfd_vma addr;
621   char *location = (char *) locationp;
622   bfd_vma prev_number = 1;      /* Nothing can have this as a high bit*/
623   struct data_struct *d = (struct data_struct *) NULL;
624
625   for (addr = section->vma; count != 0; count--, addr++)
626     {
627
628       bfd_vma chunk_number = addr & ~CHUNK_MASK;        /* Get high bits of address */
629       bfd_vma low_bits = addr & CHUNK_MASK;
630
631       if (chunk_number != prev_number)
632         {
633           /* Different chunk, so move pointer */
634           d = find_chunk (abfd, chunk_number);
635         }
636
637       if (get)
638         {
639           if (d->chunk_init[low_bits])
640             {
641               *location = d->chunk_data[low_bits];
642             }
643           else
644             {
645               *location = 0;
646             }
647         }
648       else
649         {
650           d->chunk_data[low_bits] = *location;
651           d->chunk_init[low_bits] = (*location != 0);
652         }
653
654       location++;
655
656     }
657
658 }
659 static boolean
660 tekhex_get_section_contents (abfd, section, locationp, offset, count)
661      bfd *abfd;
662      asection *section;
663      PTR locationp;
664      file_ptr offset;
665      bfd_size_type count;
666 {
667   if (section->flags & (SEC_LOAD | SEC_ALLOC))
668     {
669       move_section_contents (abfd, section, locationp, offset, count, true);
670       return true;
671     }
672   else
673     return false;
674 }
675
676 boolean
677 tekhex_set_arch_mach (abfd, arch, machine)
678      bfd *abfd;
679      enum bfd_architecture arch;
680      unsigned long machine;
681 {
682   return bfd_default_set_arch_mach (abfd, arch, machine);
683 }
684
685 /* we have to save up all the Tekhexords for a splurge before output,
686     */
687
688 static boolean
689 tekhex_set_section_contents (abfd, section, locationp, offset, bytes_to_do)
690      bfd *abfd;
691      sec_ptr section;
692      PTR locationp;
693      file_ptr offset;
694      bfd_size_type bytes_to_do;
695 {
696
697   if (abfd->output_has_begun == false)
698     {
699       /* The first time around, allocate enough sections to hold all the chunks */
700       asection *s = abfd->sections;
701       bfd_vma vma;
702
703       for (s = abfd->sections; s; s = s->next)
704         {
705           if (s->flags & SEC_LOAD)
706             {
707               for (vma = s->vma & ~CHUNK_MASK;
708                    vma < s->vma + s->_raw_size;
709                    vma += CHUNK_MASK)
710                 find_chunk (abfd, vma);
711             }
712         }
713
714     }
715   if (section->flags & (SEC_LOAD | SEC_ALLOC))
716     {
717       move_section_contents (abfd, section, locationp, offset, bytes_to_do, false);
718       return true;
719     }
720   else
721     return false;
722
723 }
724
725 static void
726 writevalue (dst, value)
727      char **dst;
728      bfd_vma value;
729 {
730   char *p = *dst;
731   int len;
732   int shift;
733
734   for (len = 8, shift = 28; shift; shift -= 4, len--)
735     {
736       if ((value >> shift) & 0xf)
737         {
738           *p++ = len + '0';
739           while (len)
740             {
741               *p++ = digs[(value >> shift) & 0xf];
742               shift -= 4;
743               len--;
744             }
745           *dst = p;
746           return;
747
748         }
749     }
750   *p++ = '1';
751   *p++ = '0';
752   *dst = p;
753 }
754
755 static void
756 writesym (dst, sym)
757      char **dst;
758      CONST char *sym;
759 {
760   char *p = *dst;
761   int len = (sym ? strlen (sym) : 0);
762
763   if (len >= 16)
764     {
765       *p++ = '0';
766       len = 16;
767     }
768
769   else
770     {
771       if (len == 0)
772         {
773           *p++ = '1';
774           sym = "$";
775           len = 1;
776         }
777       else
778         {
779           *p++ = digs[len];
780         }
781     }
782
783   while (len--)
784     {
785       *p++ = *sym++;
786     }
787   *dst = p;
788 }
789
790 static void
791 out (abfd, type, start, end)
792      bfd *abfd;
793      char type;
794      char *start;
795      char *end;
796 {
797   int sum = 0;
798   char *s;
799   char front[6];
800
801   front[0] = '%';
802   TOHEX (front + 1, end - start + 5);
803   front[3] = type;
804
805   for (s = start; s < end; s++)
806     {
807       sum += sum_block[*s];
808     }
809
810   sum += sum_block[front[1]];   /*  length */
811   sum += sum_block[front[2]];
812   sum += sum_block[front[3]];   /* type */
813   TOHEX (front + 4, sum);
814   if (bfd_write (front, 1, 6, abfd) != 6)
815     abort ();
816   end[0] = '\n';
817   if (bfd_write (start, 1, end - start + 1, abfd) != end - start + 1)
818     abort ();
819 }
820
821 static boolean
822 tekhex_write_object_contents (abfd)
823      bfd *abfd;
824 {
825   int bytes_written;
826   char buffer[100];
827   asymbol **p;
828   tdata_type *tdata = abfd->tdata.tekhex_data;
829   tekhex_data_list_type *list;
830   asection *s;
831   struct data_struct *d;
832
833   bytes_written = 0;
834
835   /* And the raw data */
836   for (d = abfd->tdata.tekhex_data->data;
837        d != (struct data_struct *) NULL;
838        d = d->next)
839     {
840       int low;
841
842       CONST int span = 32;
843       int addr;
844
845       /* Write it in blocks of 32 bytes */
846
847       for (addr = 0; addr < CHUNK_MASK + 1; addr += span)
848         {
849           int need = 0;
850
851           /* Check to see if necessary */
852           for (low = 0; !need && low < span; low++)
853             {
854               if (d->chunk_init[addr + low])
855                 need = 1;
856             }
857           if (need)
858             {
859               char *dst = buffer;
860
861               writevalue (&dst, addr + d->vma);
862               for (low = 0; low < span; low++)
863                 {
864                   TOHEX (dst, d->chunk_data[addr + low]);
865                   dst += 2;
866                 }
867               out (abfd, '6', buffer, dst);
868             }
869         }
870     }
871   /* write all the section headers for the sections */
872   for (s = abfd->sections; s != (asection *) NULL; s = s->next)
873     {
874       char *dst = buffer;
875
876       writesym (&dst, s->name);
877       *dst++ = '1';
878       writevalue (&dst, s->vma);
879       writevalue (&dst, s->vma + s->_raw_size);
880       out (abfd, '3', buffer, dst);
881     }
882
883   /* And the symbols */
884   for (p = abfd->outsymbols; *p; p++)
885     {
886       int section_code = bfd_decode_symclass (*p);
887
888       if (section_code != '?')
889         {                       /* do not include debug symbols */
890           asymbol *s = *p;
891           char *dst = buffer;
892
893           writesym (&dst, s->section->name);
894
895           switch (section_code)
896             {
897             case 'A':
898               *dst++ = '2';
899               break;
900             case 'a':
901               *dst++ = '6';
902               break;
903             case 'D':
904             case 'B':
905             case 'O':
906               *dst++ = '4';
907               break;
908             case 'd':
909             case 'b':
910             case 'o':
911               *dst++ = '8';
912               break;
913             case 'T':
914               *dst++ = '3';
915               break;
916             case 't':
917               *dst++ = '7';
918               break;
919             case 'C':
920             case 'U':
921               bfd_set_error (bfd_error_wrong_format);
922               return false;
923             }
924
925           writesym (&dst, s->name);
926           writevalue (&dst, s->value + s->section->vma);
927           out (abfd, '3', buffer, dst);
928         }
929     }
930
931   /* And the terminator */
932   if (bfd_write ("%7081010\n", 1, 9, abfd) != 9)
933     abort ();
934   return true;
935 }
936
937 static int
938   tekhex_sizeof_headers (abfd, exec)
939      bfd *abfd;
940      boolean exec;
941
942 {
943   return 0;
944 }
945
946 static asymbol *
947 tekhex_make_empty_symbol (abfd)
948      bfd *abfd;
949 {
950   tekhex_symbol_type *new =
951   (tekhex_symbol_type *) bfd_zalloc (abfd, sizeof (struct tekhex_symbol_struct));
952
953   if (!new)
954     {
955       bfd_set_error (bfd_error_no_memory);
956       return NULL;
957     }
958   new->symbol.the_bfd = abfd;
959   new->prev = (struct tekhex_symbol_struct *) NULL;
960   return &(new->symbol);
961 }
962
963 static void
964 tekhex_get_symbol_info (ignore_abfd, symbol, ret)
965      bfd *ignore_abfd;
966      asymbol *symbol;
967      symbol_info *ret;
968 {
969   bfd_symbol_info (symbol, ret);
970 }
971
972 static void
973 tekhex_print_symbol (ignore_abfd, filep, symbol, how)
974      bfd *ignore_abfd;
975      PTR filep;
976      asymbol *symbol;
977      bfd_print_symbol_type how;
978 {
979   FILE *file = (FILE *) filep;
980
981   switch (how)
982     {
983     case bfd_print_symbol_name:
984       fprintf (file, "%s", symbol->name);
985       break;
986     case bfd_print_symbol_more:
987       break;
988
989     case bfd_print_symbol_all:
990       {
991         CONST char *section_name = symbol->section->name;
992
993         bfd_print_symbol_vandf ((PTR) file, symbol);
994
995         fprintf (file, " %-5s %s",
996                  section_name,
997                  symbol->name);
998       }
999     }
1000 }
1001
1002 #define tekhex_close_and_cleanup _bfd_generic_close_and_cleanup
1003 #define tekhex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
1004 #define tekhex_new_section_hook _bfd_generic_new_section_hook
1005
1006 #define tekhex_bfd_is_local_label bfd_generic_is_local_label
1007 #define tekhex_get_lineno _bfd_nosymbols_get_lineno
1008 #define tekhex_find_nearest_line _bfd_nosymbols_find_nearest_line
1009 #define tekhex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
1010
1011 #define tekhex_bfd_get_relocated_section_contents \
1012   bfd_generic_get_relocated_section_contents
1013 #define tekhex_bfd_relax_section bfd_generic_relax_section
1014 #define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
1015 #define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols
1016 #define tekhex_bfd_final_link _bfd_generic_final_link
1017
1018 const bfd_target tekhex_vec =
1019 {
1020   "tekhex",                     /* name */
1021   bfd_target_tekhex_flavour,
1022   true,                         /* target byte order */
1023   true,                         /* target headers byte order */
1024   (EXEC_P |                     /* object flags */
1025    HAS_SYMS | HAS_LINENO | HAS_DEBUG | HAS_RELOC | HAS_LOCALS |
1026    WP_TEXT | D_PAGED),
1027   (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
1028    | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */
1029   0,                            /* leading underscore */
1030   ' ',                          /* ar_pad_char */
1031   16,                           /* ar_max_namelen */
1032   1,                            /* minimum alignment */
1033   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1034   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1035   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* data */
1036   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
1037   bfd_getb32, bfd_getb_signed_32, bfd_putb32,
1038   bfd_getb16, bfd_getb_signed_16, bfd_putb16,   /* hdrs */
1039
1040   {
1041     _bfd_dummy_target,
1042     tekhex_object_p,            /* bfd_check_format */
1043     _bfd_dummy_target,
1044     _bfd_dummy_target,
1045   },
1046   {
1047     bfd_false,
1048     tekhex_mkobject,
1049     _bfd_generic_mkarchive,
1050     bfd_false,
1051   },
1052   {                             /* bfd_write_contents */
1053     bfd_false,
1054     tekhex_write_object_contents,
1055     _bfd_write_archive_contents,
1056     bfd_false,
1057   },
1058
1059   BFD_JUMP_TABLE_GENERIC (tekhex),
1060   BFD_JUMP_TABLE_COPY (_bfd_generic),
1061   BFD_JUMP_TABLE_CORE (_bfd_nocore),
1062   BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
1063   BFD_JUMP_TABLE_SYMBOLS (tekhex),
1064   BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
1065   BFD_JUMP_TABLE_WRITE (tekhex),
1066   BFD_JUMP_TABLE_LINK (tekhex),
1067   BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
1068
1069   (PTR) 0
1070 };