133965Sjdp/* BFD backend for Extended Tektronix Hex Format objects. 2218822Sdim Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 3218822Sdim 2003, 2004, 2007 Free Software Foundation, Inc. 433965Sjdp Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. 533965Sjdp 6218822Sdim This file is part of BFD, the Binary File Descriptor library. 733965Sjdp 8218822Sdim This program is free software; you can redistribute it and/or modify 9218822Sdim it under the terms of the GNU General Public License as published by 10218822Sdim the Free Software Foundation; either version 2 of the License, or 11218822Sdim (at your option) any later version. 1233965Sjdp 13218822Sdim This program is distributed in the hope that it will be useful, 14218822Sdim but WITHOUT ANY WARRANTY; without even the implied warranty of 15218822Sdim MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16218822Sdim GNU General Public License for more details. 1733965Sjdp 18218822Sdim You should have received a copy of the GNU General Public License 19218822Sdim along with this program; if not, write to the Free Software 20218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2133965Sjdp 22218822Sdim/* SUBSECTION 2333965Sjdp Tektronix Hex Format handling 2433965Sjdp 25218822Sdim DESCRIPTION 2677298Sobrien 2733965Sjdp Tek Hex records can hold symbols and data, but not 2833965Sjdp relocations. Their main application is communication with 2933965Sjdp devices like PROM programmers and ICE equipment. 3077298Sobrien 31130561Sobrien It seems that the sections are described as being really big, 3233965Sjdp the example I have says that the text section is 0..ffffffff. 3333965Sjdp BFD would barf with this, many apps would try to alloc 4GB to 3433965Sjdp read in the file. 3533965Sjdp 3633965Sjdp Tex Hex may contain many sections, but the data which comes in 3733965Sjdp has no tag saying which section it belongs to, so we create 3833965Sjdp one section for each block of data, called "blknnnn" which we 3933965Sjdp stick all the data into. 4033965Sjdp 4133965Sjdp TekHex may come out of order and there is no header, so an 4233965Sjdp initial scan is required to discover the minimum and maximum 4333965Sjdp addresses used to create the vma and size of the sections we 4433965Sjdp create. 4533965Sjdp We read in the data into pages of CHUNK_MASK+1 size and read 4633965Sjdp them out from that whenever we need to. 4733965Sjdp 4833965Sjdp Any number of sections may be created for output, we save them 4933965Sjdp up and output them when it's time to close the bfd. 5033965Sjdp 5133965Sjdp A TekHex record looks like: 52218822Sdim EXAMPLE 5333965Sjdp %<block length><type><checksum><stuff><cr> 5477298Sobrien 55218822Sdim DESCRIPTION 5633965Sjdp Where 5733965Sjdp o length 5833965Sjdp is the number of bytes in the record not including the % sign. 5933965Sjdp o type 6033965Sjdp is one of: 6133965Sjdp 3) symbol record 6233965Sjdp 6) data record 6333965Sjdp 8) termination record 6433965Sjdp 65218822Sdim The data can come out of order, and may be discontigous. This is a 66218822Sdim serial protocol, so big files are unlikely, so we keep a list of 8k chunks. */ 6733965Sjdp 68218822Sdim#include "sysdep.h" 6933965Sjdp#include "bfd.h" 7033965Sjdp#include "libbfd.h" 7133965Sjdp#include "libiberty.h" 7233965Sjdp 7333965Sjdptypedef struct 74218822Sdim{ 75218822Sdim bfd_vma low; 76218822Sdim bfd_vma high; 77218822Sdim} addr_range_type; 7833965Sjdp 7933965Sjdptypedef struct tekhex_symbol_struct 80218822Sdim{ 81218822Sdim asymbol symbol; 82218822Sdim struct tekhex_symbol_struct *prev; 83218822Sdim} tekhex_symbol_type; 8433965Sjdp 8533965Sjdpstatic const char digs[] = "0123456789ABCDEF"; 8633965Sjdp 8733965Sjdpstatic char sum_block[256]; 8833965Sjdp 89218822Sdim#define NOT_HEX 20 90218822Sdim#define NIBBLE(x) hex_value(x) 91218822Sdim#define HEX(buffer) ((NIBBLE ((buffer)[0]) << 4) + NIBBLE ((buffer)[1])) 92218822Sdim#define ISHEX(x) hex_p(x) 93218822Sdim#define TOHEX(d, x) \ 94218822Sdim (d)[1] = digs[(x) & 0xf]; \ 95218822Sdim (d)[0] = digs[((x)>>4)&0xf]; 9633965Sjdp 97218822Sdim/* Here's an example 98218822Sdim %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 99218822Sdim %1B3709T_SEGMENT1108FFFFFFFF 100218822Sdim %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 101218822Sdim %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 102218822Sdim %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 103218822Sdim %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 104218822Sdim %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 105218822Sdim %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 106218822Sdim %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 107218822Sdim %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 108218822Sdim %2734D9T_SEGMENT8Bvoid$t15$151035_main10 109218822Sdim %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 110218822Sdim %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 111218822Sdim %07 8 10 10 11233965Sjdp 113218822Sdim explanation: 114218822Sdim %3A6C6480004E56FFFC4E717063B0AEFFFC6D0652AEFFFC60F24E5E4E75 115218822Sdim ^ ^^ ^ ^-data 116218822Sdim | || +------ 4 char integer 0x8000 117218822Sdim | |+-------- checksum 118218822Sdim | +--------- type 6 (data record) 119218822Sdim +----------- length 3a chars 120218822Sdim <---------------------- 3a (58 chars) -------------------> 12133965Sjdp 122218822Sdim %1B3709T_SEGMENT1108FFFFFFFF 123218822Sdim ^ ^^ ^- 8 character integer 0xffffffff 124218822Sdim | |+- 1 character integer 0 125218822Sdim | +-- type 1 symbol (section definition) 126218822Sdim +------------ 9 char symbol T_SEGMENT 12733965Sjdp 128218822Sdim %2B3AB9T_SEGMENT7Dgcc_compiled$1087hello$c10 129218822Sdim %373829T_SEGMENT80int$t1$r1$$214741080char$t2$r2$0$12710 130218822Sdim %373769T_SEGMENT80long$int$t3$r1$$1080unsigned$int$t4$10 131218822Sdim %373CA9T_SEGMENT80long$unsigned$in1080short$int$t6$r1$10 132218822Sdim %373049T_SEGMENT80long$long$int$t71080short$unsigned$i10 133218822Sdim %373A29T_SEGMENT80long$long$unsign1080signed$char$t10$10 134218822Sdim %373D69T_SEGMENT80unsigned$char$t11080float$t12$r1$4$010 135218822Sdim %373D19T_SEGMENT80double$t13$r1$8$1080long$double$t14$10 136218822Sdim %2734D9T_SEGMENT8Bvoid$t15$151035_main10 137218822Sdim %2F3CA9T_SEGMENT81$1081$1681$1E81$21487main$F110 138218822Sdim %2832F9T_SEGMENT83i$18FFFFFFFC81$1481$214 139218822Sdim %0781010 14033965Sjdp 141218822Sdim Turns into 142218822Sdim sac@thepub$ ./objdump -dx -m m68k f 14333965Sjdp 144218822Sdim f: file format tekhex 145218822Sdim -----x--- 9/55728 -134219416 Sep 29 15:13 1995 f 146218822Sdim architecture: UNKNOWN!, flags 0x00000010: 147218822Sdim HAS_SYMS 148218822Sdim start address 0x00000000 149218822Sdim SECTION 0 [D00000000] : size 00020000 vma 00000000 align 2**0 150218822Sdim ALLOC, LOAD 151218822Sdim SECTION 1 [D00008000] : size 00002001 vma 00008000 align 2**0 15233965Sjdp 153218822Sdim SECTION 2 [T_SEGMENT] : size ffffffff vma 00000000 align 2**0 15433965Sjdp 155218822Sdim SYMBOL TABLE: 156218822Sdim 00000000 g T_SEGMENT gcc_compiled$ 157218822Sdim 00000000 g T_SEGMENT hello$c 158218822Sdim 00000000 g T_SEGMENT int$t1$r1$$21474 159218822Sdim 00000000 g T_SEGMENT char$t2$r2$0$127 160218822Sdim 00000000 g T_SEGMENT long$int$t3$r1$$ 161218822Sdim 00000000 g T_SEGMENT unsigned$int$t4$ 162218822Sdim 00000000 g T_SEGMENT long$unsigned$in 163218822Sdim 00000000 g T_SEGMENT short$int$t6$r1$ 164218822Sdim 00000000 g T_SEGMENT long$long$int$t7 165218822Sdim 00000000 g T_SEGMENT short$unsigned$i 166218822Sdim 00000000 g T_SEGMENT long$long$unsign 167218822Sdim 00000000 g T_SEGMENT signed$char$t10$ 168218822Sdim 00000000 g T_SEGMENT unsigned$char$t1 169218822Sdim 00000000 g T_SEGMENT float$t12$r1$4$0 170218822Sdim 00000000 g T_SEGMENT double$t13$r1$8$ 171218822Sdim 00000000 g T_SEGMENT long$double$t14$ 172218822Sdim 00000000 g T_SEGMENT void$t15$15 173218822Sdim 00000000 g T_SEGMENT _main 174218822Sdim 00000000 g T_SEGMENT $ 175218822Sdim 00000000 g T_SEGMENT $ 176218822Sdim 00000000 g T_SEGMENT $ 177218822Sdim 00000010 g T_SEGMENT $ 178218822Sdim 00000000 g T_SEGMENT main$F1 179218822Sdim fcffffff g T_SEGMENT i$1 180218822Sdim 00000000 g T_SEGMENT $ 181218822Sdim 00000010 g T_SEGMENT $ 18233965Sjdp 183218822Sdim RELOCATION RECORDS FOR [D00000000]: (none) 18433965Sjdp 185218822Sdim RELOCATION RECORDS FOR [D00008000]: (none) 18633965Sjdp 187218822Sdim RELOCATION RECORDS FOR [T_SEGMENT]: (none) 18833965Sjdp 189218822Sdim Disassembly of section D00000000: 190218822Sdim ... 191218822Sdim 00008000 ($+)7ff0 linkw fp,#-4 192218822Sdim 00008004 ($+)7ff4 nop 193218822Sdim 00008006 ($+)7ff6 movel #99,d0 194218822Sdim 00008008 ($+)7ff8 cmpl fp@(-4),d0 195218822Sdim 0000800c ($+)7ffc blts 00008014 ($+)8004 196218822Sdim 0000800e ($+)7ffe addql #1,fp@(-4) 197218822Sdim 00008012 ($+)8002 bras 00008006 ($+)7ff6 198218822Sdim 00008014 ($+)8004 unlk fp 199218822Sdim 00008016 ($+)8006 rts 200218822Sdim ... */ 20133965Sjdp 20233965Sjdpstatic void 203218822Sdimtekhex_init (void) 20433965Sjdp{ 20533965Sjdp unsigned int i; 206130561Sobrien static bfd_boolean inited = FALSE; 20733965Sjdp int val; 20833965Sjdp 209104834Sobrien if (! inited) 21033965Sjdp { 211130561Sobrien inited = TRUE; 21233965Sjdp hex_init (); 21333965Sjdp val = 0; 21433965Sjdp for (i = 0; i < 10; i++) 215218822Sdim sum_block[i + '0'] = val++; 216218822Sdim 21733965Sjdp for (i = 'A'; i <= 'Z'; i++) 218218822Sdim sum_block[i] = val++; 219218822Sdim 22033965Sjdp sum_block['$'] = val++; 22133965Sjdp sum_block['%'] = val++; 22233965Sjdp sum_block['.'] = val++; 22333965Sjdp sum_block['_'] = val++; 22433965Sjdp for (i = 'a'; i <= 'z'; i++) 225218822Sdim sum_block[i] = val++; 22633965Sjdp } 22733965Sjdp} 22833965Sjdp 229218822Sdim/* The maximum number of bytes on a line is FF. */ 23033965Sjdp#define MAXCHUNK 0xff 231218822Sdim/* The number of bytes we fit onto a line on output. */ 23233965Sjdp#define CHUNK 21 23333965Sjdp 23433965Sjdp/* We cannot output our tekhexords as we see them, we have to glue them 23533965Sjdp together, this is done in this structure : */ 23633965Sjdp 23733965Sjdpstruct tekhex_data_list_struct 23833965Sjdp{ 23933965Sjdp unsigned char *data; 24033965Sjdp bfd_vma where; 24133965Sjdp bfd_size_type size; 24233965Sjdp struct tekhex_data_list_struct *next; 24333965Sjdp 24433965Sjdp}; 24533965Sjdptypedef struct tekhex_data_list_struct tekhex_data_list_type; 24633965Sjdp 24733965Sjdp#define CHUNK_MASK 0x1fff 24833965Sjdp 24933965Sjdpstruct data_struct 250218822Sdim{ 251218822Sdim char chunk_data[CHUNK_MASK + 1]; 252218822Sdim char chunk_init[CHUNK_MASK + 1]; 253218822Sdim bfd_vma vma; 254218822Sdim struct data_struct *next; 255218822Sdim}; 25633965Sjdp 25733965Sjdptypedef struct tekhex_data_struct 25833965Sjdp{ 25933965Sjdp tekhex_data_list_type *head; 26033965Sjdp unsigned int type; 26133965Sjdp struct tekhex_symbol_struct *symbols; 26233965Sjdp struct data_struct *data; 26333965Sjdp} tdata_type; 26433965Sjdp 26533965Sjdp#define enda(x) (x->vma + x->size) 26633965Sjdp 267218822Sdimstatic bfd_boolean 268218822Sdimgetvalue (char **srcp, bfd_vma *valuep) 26933965Sjdp{ 27033965Sjdp char *src = *srcp; 27133965Sjdp bfd_vma value = 0; 272218822Sdim unsigned int len; 27333965Sjdp 274218822Sdim if (!ISHEX (*src)) 275218822Sdim return FALSE; 276218822Sdim 277218822Sdim len = hex_value (*src++); 27833965Sjdp if (len == 0) 27933965Sjdp len = 16; 28033965Sjdp while (len--) 28133965Sjdp { 282218822Sdim if (!ISHEX (*src)) 283218822Sdim return FALSE; 284218822Sdim value = value << 4 | hex_value (*src++); 28533965Sjdp } 286218822Sdim 28733965Sjdp *srcp = src; 288218822Sdim *valuep = value; 289218822Sdim return TRUE; 29033965Sjdp} 29133965Sjdp 292218822Sdimstatic bfd_boolean 293218822Sdimgetsym (char *dstp, char **srcp, unsigned int *lenp) 29433965Sjdp{ 29533965Sjdp char *src = *srcp; 29633965Sjdp unsigned int i; 297218822Sdim unsigned int len; 298218822Sdim 299218822Sdim if (!ISHEX (*src)) 300218822Sdim return FALSE; 30133965Sjdp 302218822Sdim len = hex_value (*src++); 30333965Sjdp if (len == 0) 30433965Sjdp len = 16; 30533965Sjdp for (i = 0; i < len; i++) 30633965Sjdp dstp[i] = src[i]; 30733965Sjdp dstp[i] = 0; 30833965Sjdp *srcp = src + i; 309218822Sdim *lenp = len; 310218822Sdim return TRUE; 31133965Sjdp} 31233965Sjdp 31333965Sjdpstatic struct data_struct * 314218822Sdimfind_chunk (bfd *abfd, bfd_vma vma) 31533965Sjdp{ 31633965Sjdp struct data_struct *d = abfd->tdata.tekhex_data->data; 31733965Sjdp 31833965Sjdp vma &= ~CHUNK_MASK; 31933965Sjdp while (d && (d->vma) != vma) 320218822Sdim d = d->next; 321218822Sdim 32233965Sjdp if (!d) 32333965Sjdp { 324218822Sdim /* No chunk for this address, so make one up. */ 325218822Sdim d = bfd_zalloc (abfd, (bfd_size_type) sizeof (struct data_struct)); 32633965Sjdp 327104834Sobrien if (!d) 32833965Sjdp return NULL; 32933965Sjdp 33033965Sjdp d->next = abfd->tdata.tekhex_data->data; 33133965Sjdp d->vma = vma; 33233965Sjdp abfd->tdata.tekhex_data->data = d; 33333965Sjdp } 33433965Sjdp return d; 33533965Sjdp} 33633965Sjdp 33733965Sjdpstatic void 338218822Sdiminsert_byte (bfd *abfd, int value, bfd_vma addr) 33933965Sjdp{ 340218822Sdim /* Find the chunk that this byte needs and put it in. */ 34133965Sjdp struct data_struct *d = find_chunk (abfd, addr); 34233965Sjdp 34333965Sjdp d->chunk_data[addr & CHUNK_MASK] = value; 34433965Sjdp d->chunk_init[addr & CHUNK_MASK] = 1; 34533965Sjdp} 34633965Sjdp 34733965Sjdp/* The first pass is to find the names of all the sections, and see 348218822Sdim how big the data is. */ 349218822Sdim 350218822Sdimstatic bfd_boolean 351218822Sdimfirst_phase (bfd *abfd, int type, char *src) 35233965Sjdp{ 35333965Sjdp asection *section = bfd_abs_section_ptr; 35489857Sobrien unsigned int len; 355218822Sdim bfd_vma val; 356218822Sdim char sym[17]; /* A symbol can only be 16chars long. */ 35733965Sjdp 35833965Sjdp switch (type) 35933965Sjdp { 36033965Sjdp case '6': 361218822Sdim /* Data record - read it and store it. */ 36233965Sjdp { 363218822Sdim bfd_vma addr; 36433965Sjdp 365218822Sdim if (!getvalue (&src, &addr)) 366218822Sdim return FALSE; 367218822Sdim 36833965Sjdp while (*src) 36933965Sjdp { 37033965Sjdp insert_byte (abfd, HEX (src), addr); 37133965Sjdp src += 2; 37233965Sjdp addr++; 37333965Sjdp } 37433965Sjdp } 37533965Sjdp 376218822Sdim return TRUE; 37733965Sjdp case '3': 378218822Sdim /* Symbol record, read the segment. */ 379218822Sdim if (!getsym (sym, &src, &len)) 380218822Sdim return FALSE; 38133965Sjdp section = bfd_get_section_by_name (abfd, sym); 382218822Sdim if (section == NULL) 38333965Sjdp { 38489857Sobrien char *n = bfd_alloc (abfd, (bfd_size_type) len + 1); 38533965Sjdp 38633965Sjdp if (!n) 387218822Sdim return FALSE; 38833965Sjdp memcpy (n, sym, len + 1); 38933965Sjdp section = bfd_make_section (abfd, n); 39033965Sjdp } 39133965Sjdp while (*src) 39233965Sjdp { 39333965Sjdp switch (*src) 39433965Sjdp { 395218822Sdim case '1': /* Section range. */ 39633965Sjdp src++; 397218822Sdim if (!getvalue (&src, §ion->vma)) 398218822Sdim return FALSE; 399218822Sdim if (!getvalue (&src, &val)) 400218822Sdim return FALSE; 401218822Sdim section->size = val - section->vma; 40233965Sjdp section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; 40333965Sjdp break; 40433965Sjdp case '0': 40533965Sjdp case '2': 40633965Sjdp case '3': 40733965Sjdp case '4': 40833965Sjdp case '6': 40933965Sjdp case '7': 41033965Sjdp case '8': 411218822Sdim /* Symbols, add to section. */ 41233965Sjdp { 41389857Sobrien bfd_size_type amt = sizeof (tekhex_symbol_type); 414218822Sdim tekhex_symbol_type *new = bfd_alloc (abfd, amt); 41589857Sobrien char stype = (*src); 41633965Sjdp 41733965Sjdp if (!new) 418218822Sdim return FALSE; 41933965Sjdp new->symbol.the_bfd = abfd; 42033965Sjdp src++; 42133965Sjdp abfd->symcount++; 42233965Sjdp abfd->flags |= HAS_SYMS; 42333965Sjdp new->prev = abfd->tdata.tekhex_data->symbols; 42433965Sjdp abfd->tdata.tekhex_data->symbols = new; 425218822Sdim if (!getsym (sym, &src, &len)) 426218822Sdim return FALSE; 42789857Sobrien new->symbol.name = bfd_alloc (abfd, (bfd_size_type) len + 1); 42833965Sjdp if (!new->symbol.name) 429218822Sdim return FALSE; 43033965Sjdp memcpy ((char *) (new->symbol.name), sym, len + 1); 43133965Sjdp new->symbol.section = section; 43289857Sobrien if (stype <= '4') 43333965Sjdp new->symbol.flags = (BSF_GLOBAL | BSF_EXPORT); 43433965Sjdp else 43533965Sjdp new->symbol.flags = BSF_LOCAL; 436218822Sdim if (!getvalue (&src, &val)) 437218822Sdim return FALSE; 438218822Sdim new->symbol.value = val - section->vma; 439218822Sdim break; 44033965Sjdp } 441218822Sdim default: 442218822Sdim return FALSE; 44333965Sjdp } 44433965Sjdp } 44533965Sjdp } 446218822Sdim 447218822Sdim return TRUE; 44833965Sjdp} 44933965Sjdp 450130561Sobrien/* Pass over a tekhex, calling one of the above functions on each 45133965Sjdp record. */ 45233965Sjdp 453218822Sdimstatic bfd_boolean 454218822Sdimpass_over (bfd *abfd, bfd_boolean (*func) (bfd *, int, char *)) 45533965Sjdp{ 45633965Sjdp unsigned int chars_on_line; 457130561Sobrien bfd_boolean eof = FALSE; 45833965Sjdp 459218822Sdim /* To the front of the file. */ 46033965Sjdp if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) 461218822Sdim return FALSE; 462104834Sobrien while (! eof) 46333965Sjdp { 464218822Sdim char src[MAXCHUNK]; 46533965Sjdp char type; 46633965Sjdp 467218822Sdim /* Find first '%'. */ 468130561Sobrien eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1); 46933965Sjdp while (*src != '%' && !eof) 470218822Sdim eof = (bfd_boolean) (bfd_bread (src, (bfd_size_type) 1, abfd) != 1); 471218822Sdim 47233965Sjdp if (eof) 47333965Sjdp break; 47433965Sjdp 475218822Sdim /* Fetch the type and the length and the checksum. */ 47689857Sobrien if (bfd_bread (src, (bfd_size_type) 5, abfd) != 5) 477218822Sdim return FALSE; 47833965Sjdp 47933965Sjdp type = src[2]; 48033965Sjdp 48133965Sjdp if (!ISHEX (src[0]) || !ISHEX (src[1])) 48233965Sjdp break; 48333965Sjdp 484218822Sdim /* Already read five chars. */ 485218822Sdim chars_on_line = HEX (src) - 5; 48633965Sjdp 487218822Sdim if (chars_on_line >= MAXCHUNK) 488218822Sdim return FALSE; 489218822Sdim 49089857Sobrien if (bfd_bread (src, (bfd_size_type) chars_on_line, abfd) != chars_on_line) 491218822Sdim return FALSE; 49233965Sjdp 493218822Sdim /* Put a null at the end. */ 494218822Sdim src[chars_on_line] = 0; 495218822Sdim 496218822Sdim if (!func (abfd, type, src)) 497218822Sdim return FALSE; 49833965Sjdp } 49933965Sjdp 500218822Sdim return TRUE; 50133965Sjdp} 50233965Sjdp 50333965Sjdpstatic long 504218822Sdimtekhex_canonicalize_symtab (bfd *abfd, asymbol **table) 50533965Sjdp{ 50633965Sjdp tekhex_symbol_type *p = abfd->tdata.tekhex_data->symbols; 50733965Sjdp unsigned int c = bfd_get_symcount (abfd); 50833965Sjdp 50933965Sjdp table[c] = 0; 51033965Sjdp while (p) 51133965Sjdp { 51233965Sjdp table[--c] = &(p->symbol); 51333965Sjdp p = p->prev; 51433965Sjdp } 51533965Sjdp 51633965Sjdp return bfd_get_symcount (abfd); 51733965Sjdp} 51833965Sjdp 51933965Sjdpstatic long 520218822Sdimtekhex_get_symtab_upper_bound (bfd *abfd) 52133965Sjdp{ 52233965Sjdp return (abfd->symcount + 1) * (sizeof (struct tekhex_asymbol_struct *)); 52333965Sjdp 52433965Sjdp} 52533965Sjdp 526130561Sobrienstatic bfd_boolean 527218822Sdimtekhex_mkobject (bfd *abfd) 52833965Sjdp{ 52989857Sobrien tdata_type *tdata; 53033965Sjdp 531218822Sdim tdata = bfd_alloc (abfd, (bfd_size_type) sizeof (tdata_type)); 53233965Sjdp if (!tdata) 533130561Sobrien return FALSE; 53433965Sjdp abfd->tdata.tekhex_data = tdata; 53533965Sjdp tdata->type = 1; 536218822Sdim tdata->head = NULL; 537218822Sdim tdata->symbols = NULL; 538218822Sdim tdata->data = NULL; 539130561Sobrien return TRUE; 54033965Sjdp} 54133965Sjdp 542218822Sdim/* Return TRUE if the file looks like it's in TekHex format. Just look 543218822Sdim for a percent sign and some hex digits. */ 54433965Sjdp 54533965Sjdpstatic const bfd_target * 546218822Sdimtekhex_object_p (bfd *abfd) 54733965Sjdp{ 54833965Sjdp char b[4]; 54933965Sjdp 55033965Sjdp tekhex_init (); 55133965Sjdp 55233965Sjdp if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 55389857Sobrien || bfd_bread (b, (bfd_size_type) 4, abfd) != 4) 55433965Sjdp return NULL; 55533965Sjdp 55633965Sjdp if (b[0] != '%' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) 557218822Sdim return NULL; 55833965Sjdp 55933965Sjdp tekhex_mkobject (abfd); 56033965Sjdp 561218822Sdim if (!pass_over (abfd, first_phase)) 562218822Sdim return NULL; 563218822Sdim 56433965Sjdp return abfd->xvec; 56533965Sjdp} 56633965Sjdp 56733965Sjdpstatic void 568218822Sdimmove_section_contents (bfd *abfd, 569218822Sdim asection *section, 570218822Sdim const void * locationp, 571218822Sdim file_ptr offset, 572218822Sdim bfd_size_type count, 573218822Sdim bfd_boolean get) 57433965Sjdp{ 57533965Sjdp bfd_vma addr; 57633965Sjdp char *location = (char *) locationp; 577218822Sdim bfd_vma prev_number = 1; /* Nothing can have this as a high bit. */ 578218822Sdim struct data_struct *d = NULL; 57933965Sjdp 58089857Sobrien BFD_ASSERT (offset == 0); 58133965Sjdp for (addr = section->vma; count != 0; count--, addr++) 58233965Sjdp { 58389857Sobrien /* Get high bits of address. */ 58489857Sobrien bfd_vma chunk_number = addr & ~(bfd_vma) CHUNK_MASK; 58533965Sjdp bfd_vma low_bits = addr & CHUNK_MASK; 58633965Sjdp 58733965Sjdp if (chunk_number != prev_number) 588218822Sdim /* Different chunk, so move pointer. */ 589218822Sdim d = find_chunk (abfd, chunk_number); 59033965Sjdp 59133965Sjdp if (get) 59233965Sjdp { 59333965Sjdp if (d->chunk_init[low_bits]) 594218822Sdim *location = d->chunk_data[low_bits]; 59533965Sjdp else 596218822Sdim *location = 0; 59733965Sjdp } 59833965Sjdp else 59933965Sjdp { 60033965Sjdp d->chunk_data[low_bits] = *location; 60133965Sjdp d->chunk_init[low_bits] = (*location != 0); 60233965Sjdp } 60333965Sjdp 60433965Sjdp location++; 60533965Sjdp } 60633965Sjdp} 60733965Sjdp 608130561Sobrienstatic bfd_boolean 609218822Sdimtekhex_get_section_contents (bfd *abfd, 610218822Sdim asection *section, 611218822Sdim void * locationp, 612218822Sdim file_ptr offset, 613218822Sdim bfd_size_type count) 61433965Sjdp{ 61533965Sjdp if (section->flags & (SEC_LOAD | SEC_ALLOC)) 61633965Sjdp { 617130561Sobrien move_section_contents (abfd, section, locationp, offset, count, TRUE); 618130561Sobrien return TRUE; 61933965Sjdp } 620218822Sdim 621218822Sdim return FALSE; 62233965Sjdp} 62333965Sjdp 624130561Sobrienstatic bfd_boolean 625218822Sdimtekhex_set_arch_mach (bfd *abfd, 626218822Sdim enum bfd_architecture arch, 627218822Sdim unsigned long machine) 62833965Sjdp{ 62933965Sjdp return bfd_default_set_arch_mach (abfd, arch, machine); 63033965Sjdp} 63133965Sjdp 632218822Sdim/* We have to save up all the Tekhexords for a splurge before output. */ 63333965Sjdp 634130561Sobrienstatic bfd_boolean 635218822Sdimtekhex_set_section_contents (bfd *abfd, 636218822Sdim sec_ptr section, 637218822Sdim const void * locationp, 638218822Sdim file_ptr offset, 639218822Sdim bfd_size_type bytes_to_do) 64033965Sjdp{ 641104834Sobrien if (! abfd->output_has_begun) 64233965Sjdp { 643218822Sdim /* The first time around, allocate enough sections to hold all the chunks. */ 64433965Sjdp asection *s = abfd->sections; 64533965Sjdp bfd_vma vma; 64633965Sjdp 64733965Sjdp for (s = abfd->sections; s; s = s->next) 64833965Sjdp { 64933965Sjdp if (s->flags & SEC_LOAD) 65033965Sjdp { 65189857Sobrien for (vma = s->vma & ~(bfd_vma) CHUNK_MASK; 652218822Sdim vma < s->vma + s->size; 65333965Sjdp vma += CHUNK_MASK) 65433965Sjdp find_chunk (abfd, vma); 65533965Sjdp } 65633965Sjdp } 657218822Sdim } 65833965Sjdp 65933965Sjdp if (section->flags & (SEC_LOAD | SEC_ALLOC)) 66033965Sjdp { 66189857Sobrien move_section_contents (abfd, section, locationp, offset, bytes_to_do, 662130561Sobrien FALSE); 663130561Sobrien return TRUE; 66433965Sjdp } 66533965Sjdp 666218822Sdim return FALSE; 66733965Sjdp} 66833965Sjdp 66933965Sjdpstatic void 670218822Sdimwritevalue (char **dst, bfd_vma value) 67133965Sjdp{ 67233965Sjdp char *p = *dst; 67333965Sjdp int len; 67433965Sjdp int shift; 67533965Sjdp 67633965Sjdp for (len = 8, shift = 28; shift; shift -= 4, len--) 67733965Sjdp { 67833965Sjdp if ((value >> shift) & 0xf) 67933965Sjdp { 68033965Sjdp *p++ = len + '0'; 68133965Sjdp while (len) 68233965Sjdp { 68333965Sjdp *p++ = digs[(value >> shift) & 0xf]; 68433965Sjdp shift -= 4; 68533965Sjdp len--; 68633965Sjdp } 68733965Sjdp *dst = p; 68833965Sjdp return; 68933965Sjdp 69033965Sjdp } 69133965Sjdp } 69233965Sjdp *p++ = '1'; 69333965Sjdp *p++ = '0'; 69433965Sjdp *dst = p; 69533965Sjdp} 69633965Sjdp 69733965Sjdpstatic void 698218822Sdimwritesym (char **dst, const char *sym) 69933965Sjdp{ 70033965Sjdp char *p = *dst; 70133965Sjdp int len = (sym ? strlen (sym) : 0); 70233965Sjdp 70333965Sjdp if (len >= 16) 70433965Sjdp { 70533965Sjdp *p++ = '0'; 70633965Sjdp len = 16; 70733965Sjdp } 70833965Sjdp else 70933965Sjdp { 71033965Sjdp if (len == 0) 71133965Sjdp { 71233965Sjdp *p++ = '1'; 71333965Sjdp sym = "$"; 71433965Sjdp len = 1; 71533965Sjdp } 71633965Sjdp else 717218822Sdim *p++ = digs[len]; 71833965Sjdp } 71933965Sjdp 72033965Sjdp while (len--) 721218822Sdim *p++ = *sym++; 722218822Sdim 72333965Sjdp *dst = p; 72433965Sjdp} 72533965Sjdp 72633965Sjdpstatic void 727218822Sdimout (bfd *abfd, int type, char *start, char *end) 72833965Sjdp{ 72933965Sjdp int sum = 0; 73033965Sjdp char *s; 73133965Sjdp char front[6]; 73233965Sjdp bfd_size_type wrlen; 73333965Sjdp 73433965Sjdp front[0] = '%'; 73533965Sjdp TOHEX (front + 1, end - start + 5); 73633965Sjdp front[3] = type; 73733965Sjdp 73833965Sjdp for (s = start; s < end; s++) 739218822Sdim sum += sum_block[(unsigned char) *s]; 74033965Sjdp 741218822Sdim sum += sum_block[(unsigned char) front[1]]; /* Length. */ 74233965Sjdp sum += sum_block[(unsigned char) front[2]]; 743218822Sdim sum += sum_block[(unsigned char) front[3]]; /* Type. */ 74433965Sjdp TOHEX (front + 4, sum); 74589857Sobrien if (bfd_bwrite (front, (bfd_size_type) 6, abfd) != 6) 74633965Sjdp abort (); 74733965Sjdp end[0] = '\n'; 74833965Sjdp wrlen = end - start + 1; 74989857Sobrien if (bfd_bwrite (start, wrlen, abfd) != wrlen) 75033965Sjdp abort (); 75133965Sjdp} 75233965Sjdp 753130561Sobrienstatic bfd_boolean 754218822Sdimtekhex_write_object_contents (bfd *abfd) 75533965Sjdp{ 75633965Sjdp char buffer[100]; 75733965Sjdp asymbol **p; 75833965Sjdp asection *s; 75933965Sjdp struct data_struct *d; 76033965Sjdp 76138889Sjdp tekhex_init (); 76238889Sjdp 763218822Sdim /* And the raw data. */ 76433965Sjdp for (d = abfd->tdata.tekhex_data->data; 765218822Sdim d != NULL; 76633965Sjdp d = d->next) 76733965Sjdp { 76833965Sjdp int low; 76933965Sjdp 77089857Sobrien const int span = 32; 77133965Sjdp int addr; 77233965Sjdp 773218822Sdim /* Write it in blocks of 32 bytes. */ 77433965Sjdp for (addr = 0; addr < CHUNK_MASK + 1; addr += span) 77533965Sjdp { 77633965Sjdp int need = 0; 77733965Sjdp 778218822Sdim /* Check to see if necessary. */ 77933965Sjdp for (low = 0; !need && low < span; low++) 780218822Sdim if (d->chunk_init[addr + low]) 781218822Sdim need = 1; 782218822Sdim 78333965Sjdp if (need) 78433965Sjdp { 78533965Sjdp char *dst = buffer; 78633965Sjdp 78733965Sjdp writevalue (&dst, addr + d->vma); 78833965Sjdp for (low = 0; low < span; low++) 78933965Sjdp { 79033965Sjdp TOHEX (dst, d->chunk_data[addr + low]); 79133965Sjdp dst += 2; 79233965Sjdp } 79333965Sjdp out (abfd, '6', buffer, dst); 79433965Sjdp } 79533965Sjdp } 79633965Sjdp } 797218822Sdim 798218822Sdim /* Write all the section headers for the sections. */ 799218822Sdim for (s = abfd->sections; s != NULL; s = s->next) 80033965Sjdp { 80133965Sjdp char *dst = buffer; 80233965Sjdp 80333965Sjdp writesym (&dst, s->name); 80433965Sjdp *dst++ = '1'; 80533965Sjdp writevalue (&dst, s->vma); 806218822Sdim writevalue (&dst, s->vma + s->size); 80733965Sjdp out (abfd, '3', buffer, dst); 80833965Sjdp } 80933965Sjdp 810218822Sdim /* And the symbols. */ 81138889Sjdp if (abfd->outsymbols) 81233965Sjdp { 81338889Sjdp for (p = abfd->outsymbols; *p; p++) 81438889Sjdp { 81538889Sjdp int section_code = bfd_decode_symclass (*p); 81633965Sjdp 81738889Sjdp if (section_code != '?') 818218822Sdim { 819218822Sdim /* Do not include debug symbols. */ 82089857Sobrien asymbol *sym = *p; 82138889Sjdp char *dst = buffer; 82233965Sjdp 82389857Sobrien writesym (&dst, sym->section->name); 82433965Sjdp 82538889Sjdp switch (section_code) 82638889Sjdp { 82738889Sjdp case 'A': 82838889Sjdp *dst++ = '2'; 82938889Sjdp break; 83038889Sjdp case 'a': 83138889Sjdp *dst++ = '6'; 83238889Sjdp break; 83338889Sjdp case 'D': 83438889Sjdp case 'B': 83538889Sjdp case 'O': 83638889Sjdp *dst++ = '4'; 83738889Sjdp break; 83838889Sjdp case 'd': 83938889Sjdp case 'b': 84038889Sjdp case 'o': 84138889Sjdp *dst++ = '8'; 84238889Sjdp break; 84338889Sjdp case 'T': 84438889Sjdp *dst++ = '3'; 84538889Sjdp break; 84638889Sjdp case 't': 84738889Sjdp *dst++ = '7'; 84838889Sjdp break; 84938889Sjdp case 'C': 85038889Sjdp case 'U': 85138889Sjdp bfd_set_error (bfd_error_wrong_format); 852130561Sobrien return FALSE; 85338889Sjdp } 85438889Sjdp 85589857Sobrien writesym (&dst, sym->name); 85689857Sobrien writevalue (&dst, sym->value + sym->section->vma); 85738889Sjdp out (abfd, '3', buffer, dst); 85833965Sjdp } 85933965Sjdp } 86033965Sjdp } 86133965Sjdp 862218822Sdim /* And the terminator. */ 86389857Sobrien if (bfd_bwrite ("%0781010\n", (bfd_size_type) 9, abfd) != 9) 86433965Sjdp abort (); 865130561Sobrien return TRUE; 86633965Sjdp} 86733965Sjdp 86833965Sjdpstatic int 869218822Sdimtekhex_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, 870218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED) 87133965Sjdp{ 87233965Sjdp return 0; 87333965Sjdp} 87433965Sjdp 87533965Sjdpstatic asymbol * 876218822Sdimtekhex_make_empty_symbol (bfd *abfd) 87733965Sjdp{ 87889857Sobrien bfd_size_type amt = sizeof (struct tekhex_symbol_struct); 879218822Sdim tekhex_symbol_type *new = bfd_zalloc (abfd, amt); 88033965Sjdp 88133965Sjdp if (!new) 88233965Sjdp return NULL; 88333965Sjdp new->symbol.the_bfd = abfd; 884218822Sdim new->prev = NULL; 88533965Sjdp return &(new->symbol); 88633965Sjdp} 88733965Sjdp 88833965Sjdpstatic void 889218822Sdimtekhex_get_symbol_info (bfd *abfd ATTRIBUTE_UNUSED, 890218822Sdim asymbol *symbol, 891218822Sdim symbol_info *ret) 89233965Sjdp{ 89333965Sjdp bfd_symbol_info (symbol, ret); 89433965Sjdp} 89533965Sjdp 89633965Sjdpstatic void 897218822Sdimtekhex_print_symbol (bfd *abfd, 898218822Sdim void * filep, 899218822Sdim asymbol *symbol, 900218822Sdim bfd_print_symbol_type how) 90133965Sjdp{ 90233965Sjdp FILE *file = (FILE *) filep; 90333965Sjdp 90433965Sjdp switch (how) 90533965Sjdp { 90633965Sjdp case bfd_print_symbol_name: 90733965Sjdp fprintf (file, "%s", symbol->name); 90833965Sjdp break; 90933965Sjdp case bfd_print_symbol_more: 91033965Sjdp break; 91133965Sjdp 91233965Sjdp case bfd_print_symbol_all: 91333965Sjdp { 91489857Sobrien const char *section_name = symbol->section->name; 91533965Sjdp 916218822Sdim bfd_print_symbol_vandf (abfd, (void *) file, symbol); 91733965Sjdp 91833965Sjdp fprintf (file, " %-5s %s", 919218822Sdim section_name, symbol->name); 92033965Sjdp } 92133965Sjdp } 92233965Sjdp} 92333965Sjdp 924218822Sdim#define tekhex_close_and_cleanup _bfd_generic_close_and_cleanup 925218822Sdim#define tekhex_bfd_free_cached_info _bfd_generic_bfd_free_cached_info 926218822Sdim#define tekhex_new_section_hook _bfd_generic_new_section_hook 927218822Sdim#define tekhex_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) 928218822Sdim#define tekhex_bfd_is_local_label_name bfd_generic_is_local_label_name 929218822Sdim#define tekhex_get_lineno _bfd_nosymbols_get_lineno 930218822Sdim#define tekhex_find_nearest_line _bfd_nosymbols_find_nearest_line 931218822Sdim#define tekhex_find_inliner_info _bfd_nosymbols_find_inliner_info 932218822Sdim#define tekhex_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol 933218822Sdim#define tekhex_read_minisymbols _bfd_generic_read_minisymbols 934218822Sdim#define tekhex_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol 935218822Sdim#define tekhex_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents 936218822Sdim#define tekhex_bfd_relax_section bfd_generic_relax_section 937218822Sdim#define tekhex_bfd_gc_sections bfd_generic_gc_sections 938218822Sdim#define tekhex_bfd_merge_sections bfd_generic_merge_sections 939218822Sdim#define tekhex_bfd_is_group_section bfd_generic_is_group_section 940218822Sdim#define tekhex_bfd_discard_group bfd_generic_discard_group 941218822Sdim#define tekhex_section_already_linked _bfd_generic_section_already_linked 942218822Sdim#define tekhex_bfd_link_hash_table_create _bfd_generic_link_hash_table_create 943218822Sdim#define tekhex_bfd_link_hash_table_free _bfd_generic_link_hash_table_free 944218822Sdim#define tekhex_bfd_link_add_symbols _bfd_generic_link_add_symbols 945218822Sdim#define tekhex_bfd_link_just_syms _bfd_generic_link_just_syms 946218822Sdim#define tekhex_bfd_final_link _bfd_generic_final_link 947218822Sdim#define tekhex_bfd_link_split_section _bfd_generic_link_split_section 948218822Sdim#define tekhex_get_section_contents_in_window _bfd_generic_get_section_contents_in_window 94933965Sjdp 95033965Sjdpconst bfd_target tekhex_vec = 95133965Sjdp{ 952218822Sdim "tekhex", /* Name. */ 95333965Sjdp bfd_target_tekhex_flavour, 954218822Sdim BFD_ENDIAN_UNKNOWN, /* Target byte order. */ 955218822Sdim BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ 956218822Sdim (EXEC_P | /* Object flags. */ 957218822Sdim HAS_SYMS | HAS_LINENO | HAS_DEBUG | 958218822Sdim HAS_RELOC | HAS_LOCALS | WP_TEXT | D_PAGED), 95933965Sjdp (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS 960218822Sdim | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ 961218822Sdim 0, /* Leading underscore. */ 962218822Sdim ' ', /* AR_pad_char. */ 963218822Sdim 16, /* AR_max_namelen. */ 96433965Sjdp bfd_getb64, bfd_getb_signed_64, bfd_putb64, 96533965Sjdp bfd_getb32, bfd_getb_signed_32, bfd_putb32, 966218822Sdim bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ 96733965Sjdp bfd_getb64, bfd_getb_signed_64, bfd_putb64, 96833965Sjdp bfd_getb32, bfd_getb_signed_32, bfd_putb32, 969218822Sdim bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ 97033965Sjdp 97133965Sjdp { 97233965Sjdp _bfd_dummy_target, 973218822Sdim tekhex_object_p, /* bfd_check_format. */ 97433965Sjdp _bfd_dummy_target, 97533965Sjdp _bfd_dummy_target, 97633965Sjdp }, 97733965Sjdp { 97833965Sjdp bfd_false, 97933965Sjdp tekhex_mkobject, 98033965Sjdp _bfd_generic_mkarchive, 98133965Sjdp bfd_false, 98233965Sjdp }, 983218822Sdim { /* bfd_write_contents. */ 98433965Sjdp bfd_false, 98533965Sjdp tekhex_write_object_contents, 98633965Sjdp _bfd_write_archive_contents, 98733965Sjdp bfd_false, 98833965Sjdp }, 98933965Sjdp 99033965Sjdp BFD_JUMP_TABLE_GENERIC (tekhex), 99133965Sjdp BFD_JUMP_TABLE_COPY (_bfd_generic), 99233965Sjdp BFD_JUMP_TABLE_CORE (_bfd_nocore), 99333965Sjdp BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), 99433965Sjdp BFD_JUMP_TABLE_SYMBOLS (tekhex), 99533965Sjdp BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), 99633965Sjdp BFD_JUMP_TABLE_WRITE (tekhex), 99733965Sjdp BFD_JUMP_TABLE_LINK (tekhex), 99833965Sjdp BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), 99933965Sjdp 100060484Sobrien NULL, 100177298Sobrien 1002218822Sdim NULL 100333965Sjdp}; 1004