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