Rev 5197 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5197 | serge | 1 | /* BFD back-end for s-record objects. |
6324 | serge | 2 | Copyright (C) 1990-2015 Free Software Foundation, Inc. |
5197 | serge | 3 | Written by Steve Chamberlain of Cygnus Support |
4 | |||
5 | This file is part of BFD, the Binary File Descriptor library. |
||
6 | |||
7 | This program is free software; you can redistribute it and/or modify |
||
8 | it under the terms of the GNU General Public License as published by |
||
9 | the Free Software Foundation; either version 3 of the License, or |
||
10 | (at your option) any later version. |
||
11 | |||
12 | This program is distributed in the hope that it will be useful, |
||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
15 | GNU General Public License for more details. |
||
16 | |||
17 | You should have received a copy of the GNU General Public License |
||
18 | along with this program; if not, write to the Free Software |
||
19 | Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, |
||
20 | MA 02110-1301, USA. */ |
||
21 | |||
22 | |||
23 | /* SUBSECTION |
||
24 | S-Record handling |
||
25 | |||
26 | DESCRIPTION |
||
27 | |||
28 | Ordinary S-Records cannot hold anything but addresses and |
||
29 | data, so that's all that we implement. |
||
30 | |||
31 | The only interesting thing is that S-Records may come out of |
||
32 | order and there is no header, so an initial scan is required |
||
33 | to discover the minimum and maximum addresses used to create |
||
34 | the vma and size of the only section we create. We |
||
35 | arbitrarily call this section ".text". |
||
36 | |||
37 | When bfd_get_section_contents is called the file is read |
||
38 | again, and this time the data is placed into a bfd_alloc'd |
||
39 | area. |
||
40 | |||
41 | Any number of sections may be created for output, we save them |
||
42 | up and output them when it's time to close the bfd. |
||
43 | |||
44 | An s record looks like: |
||
45 | |||
46 | EXAMPLE |
||
47 | S |
||
48 | |||
49 | DESCRIPTION |
||
50 | Where |
||
51 | o length |
||
52 | is the number of bytes following upto the checksum. Note that |
||
53 | this is not the number of chars following, since it takes two |
||
54 | chars to represent a byte. |
||
55 | o type |
||
56 | is one of: |
||
57 | 0) header record |
||
58 | 1) two byte address data record |
||
59 | 2) three byte address data record |
||
60 | 3) four byte address data record |
||
61 | 7) four byte address termination record |
||
62 | 8) three byte address termination record |
||
63 | 9) two byte address termination record |
||
64 | |||
65 | o address |
||
66 | is the start address of the data following, or in the case of |
||
67 | a termination record, the start address of the image |
||
68 | o data |
||
69 | is the data. |
||
70 | o checksum |
||
71 | is the sum of all the raw byte data in the record, from the length |
||
72 | upwards, modulo 256 and subtracted from 255. |
||
73 | |||
74 | SUBSECTION |
||
75 | Symbol S-Record handling |
||
76 | |||
77 | DESCRIPTION |
||
78 | Some ICE equipment understands an addition to the standard |
||
79 | S-Record format; symbols and their addresses can be sent |
||
80 | before the data. |
||
81 | |||
82 | The format of this is: |
||
83 | ($$ |
||
84 | ( |
||
85 | $$ |
||
86 | |||
87 | so a short symbol table could look like: |
||
88 | |||
89 | EXAMPLE |
||
90 | $$ flash.x |
||
91 | $$ flash.c |
||
92 | _port6 $0 |
||
93 | _delay $4 |
||
94 | _start $14 |
||
95 | _etext $8036 |
||
96 | _edata $8036 |
||
97 | _end $8036 |
||
98 | $$ |
||
99 | |||
100 | DESCRIPTION |
||
101 | We allow symbols to be anywhere in the data stream - the module names |
||
102 | are always ignored. */ |
||
103 | |||
104 | #include "sysdep.h" |
||
105 | #include "bfd.h" |
||
106 | #include "libbfd.h" |
||
107 | #include "libiberty.h" |
||
108 | #include "safe-ctype.h" |
||
109 | |||
110 | |||
111 | /* Macros for converting between hex and binary. */ |
||
112 | |||
113 | static const char digs[] = "0123456789ABCDEF"; |
||
114 | |||
115 | #define NIBBLE(x) hex_value(x) |
||
116 | #define HEX(buffer) ((NIBBLE ((buffer)[0])<<4) + NIBBLE ((buffer)[1])) |
||
117 | #define TOHEX(d, x, ch) \ |
||
118 | d[1] = digs[(x) & 0xf]; \ |
||
119 | d[0] = digs[((x)>>4)&0xf]; \ |
||
120 | ch += ((x) & 0xff); |
||
121 | #define ISHEX(x) hex_p(x) |
||
122 | |||
123 | /* The maximum number of address+data+crc bytes on a line is FF. */ |
||
124 | #define MAXCHUNK 0xff |
||
125 | |||
126 | /* Default size for a CHUNK. */ |
||
127 | #define DEFAULT_CHUNK 16 |
||
128 | |||
129 | /* The number of data bytes we actually fit onto a line on output. |
||
130 | This variable can be modified by objcopy's --srec-len parameter. |
||
131 | For a 0x75 byte record you should set --srec-len=0x70. */ |
||
132 | unsigned int Chunk = DEFAULT_CHUNK; |
||
133 | |||
134 | /* The type of srec output (free or forced to S3). |
||
135 | This variable can be modified by objcopy's --srec-forceS3 |
||
136 | parameter. */ |
||
137 | bfd_boolean S3Forced = FALSE; |
||
138 | |||
139 | /* When writing an S-record file, the S-records can not be output as |
||
140 | they are seen. This structure is used to hold them in memory. */ |
||
141 | |||
142 | struct srec_data_list_struct |
||
143 | { |
||
144 | struct srec_data_list_struct *next; |
||
145 | bfd_byte *data; |
||
146 | bfd_vma where; |
||
147 | bfd_size_type size; |
||
148 | }; |
||
149 | |||
150 | typedef struct srec_data_list_struct srec_data_list_type; |
||
151 | |||
152 | /* When scanning the S-record file, a linked list of srec_symbol |
||
153 | structures is built to represent the symbol table (if there is |
||
154 | one). */ |
||
155 | |||
156 | struct srec_symbol |
||
157 | { |
||
158 | struct srec_symbol *next; |
||
159 | const char *name; |
||
160 | bfd_vma val; |
||
161 | }; |
||
162 | |||
163 | /* The S-record tdata information. */ |
||
164 | |||
165 | typedef struct srec_data_struct |
||
166 | { |
||
167 | srec_data_list_type *head; |
||
168 | srec_data_list_type *tail; |
||
169 | unsigned int type; |
||
170 | struct srec_symbol *symbols; |
||
171 | struct srec_symbol *symtail; |
||
172 | asymbol *csymbols; |
||
173 | } |
||
174 | tdata_type; |
||
175 | |||
176 | /* Initialize by filling in the hex conversion array. */ |
||
177 | |||
178 | static void |
||
179 | srec_init (void) |
||
180 | { |
||
181 | static bfd_boolean inited = FALSE; |
||
182 | |||
183 | if (! inited) |
||
184 | { |
||
185 | inited = TRUE; |
||
186 | hex_init (); |
||
187 | } |
||
188 | } |
||
189 | |||
190 | /* Set up the S-record tdata information. */ |
||
191 | |||
192 | static bfd_boolean |
||
193 | srec_mkobject (bfd *abfd) |
||
194 | { |
||
195 | tdata_type *tdata; |
||
196 | |||
197 | srec_init (); |
||
198 | |||
199 | tdata = (tdata_type *) bfd_alloc (abfd, sizeof (tdata_type)); |
||
200 | if (tdata == NULL) |
||
201 | return FALSE; |
||
202 | |||
203 | abfd->tdata.srec_data = tdata; |
||
204 | tdata->type = 1; |
||
205 | tdata->head = NULL; |
||
206 | tdata->tail = NULL; |
||
207 | tdata->symbols = NULL; |
||
208 | tdata->symtail = NULL; |
||
209 | tdata->csymbols = NULL; |
||
210 | |||
211 | return TRUE; |
||
212 | } |
||
213 | |||
214 | /* Read a byte from an S record file. Set *ERRORPTR if an error |
||
215 | occurred. Return EOF on error or end of file. */ |
||
216 | |||
217 | static int |
||
218 | srec_get_byte (bfd *abfd, bfd_boolean *errorptr) |
||
219 | { |
||
220 | bfd_byte c; |
||
221 | |||
222 | if (bfd_bread (&c, (bfd_size_type) 1, abfd) != 1) |
||
223 | { |
||
224 | if (bfd_get_error () != bfd_error_file_truncated) |
||
225 | *errorptr = TRUE; |
||
226 | return EOF; |
||
227 | } |
||
228 | |||
229 | return (int) (c & 0xff); |
||
230 | } |
||
231 | |||
232 | /* Report a problem in an S record file. FIXME: This probably should |
||
233 | not call fprintf, but we really do need some mechanism for printing |
||
234 | error messages. */ |
||
235 | |||
236 | static void |
||
237 | srec_bad_byte (bfd *abfd, |
||
238 | unsigned int lineno, |
||
239 | int c, |
||
240 | bfd_boolean error) |
||
241 | { |
||
242 | if (c == EOF) |
||
243 | { |
||
244 | if (! error) |
||
245 | bfd_set_error (bfd_error_file_truncated); |
||
246 | } |
||
247 | else |
||
248 | { |
||
6324 | serge | 249 | char buf[40]; |
5197 | serge | 250 | |
251 | if (! ISPRINT (c)) |
||
6324 | serge | 252 | sprintf (buf, "\\%03o", (unsigned int) c & 0xff); |
5197 | serge | 253 | else |
254 | { |
||
255 | buf[0] = c; |
||
256 | buf[1] = '\0'; |
||
257 | } |
||
258 | (*_bfd_error_handler) |
||
259 | (_("%B:%d: Unexpected character `%s' in S-record file\n"), |
||
260 | abfd, lineno, buf); |
||
261 | bfd_set_error (bfd_error_bad_value); |
||
262 | } |
||
263 | } |
||
264 | |||
265 | /* Add a new symbol found in an S-record file. */ |
||
266 | |||
267 | static bfd_boolean |
||
268 | srec_new_symbol (bfd *abfd, const char *name, bfd_vma val) |
||
269 | { |
||
270 | struct srec_symbol *n; |
||
271 | |||
272 | n = (struct srec_symbol *) bfd_alloc (abfd, sizeof (* n)); |
||
273 | if (n == NULL) |
||
274 | return FALSE; |
||
275 | |||
276 | n->name = name; |
||
277 | n->val = val; |
||
278 | |||
279 | if (abfd->tdata.srec_data->symbols == NULL) |
||
280 | abfd->tdata.srec_data->symbols = n; |
||
281 | else |
||
282 | abfd->tdata.srec_data->symtail->next = n; |
||
283 | abfd->tdata.srec_data->symtail = n; |
||
284 | n->next = NULL; |
||
285 | |||
286 | ++abfd->symcount; |
||
287 | |||
288 | return TRUE; |
||
289 | } |
||
290 | |||
291 | /* Read the S record file and turn it into sections. We create a new |
||
292 | section for each contiguous set of bytes. */ |
||
293 | |||
294 | static bfd_boolean |
||
295 | srec_scan (bfd *abfd) |
||
296 | { |
||
297 | int c; |
||
298 | unsigned int lineno = 1; |
||
299 | bfd_boolean error = FALSE; |
||
300 | bfd_byte *buf = NULL; |
||
301 | size_t bufsize = 0; |
||
302 | asection *sec = NULL; |
||
303 | char *symbuf = NULL; |
||
304 | |||
305 | if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0) |
||
306 | goto error_return; |
||
307 | |||
308 | while ((c = srec_get_byte (abfd, &error)) != EOF) |
||
309 | { |
||
310 | /* We only build sections from contiguous S-records, so if this |
||
311 | is not an S-record, then stop building a section. */ |
||
312 | if (c != 'S' && c != '\r' && c != '\n') |
||
313 | sec = NULL; |
||
314 | |||
315 | switch (c) |
||
316 | { |
||
317 | default: |
||
318 | srec_bad_byte (abfd, lineno, c, error); |
||
319 | goto error_return; |
||
320 | |||
321 | case '\n': |
||
322 | ++lineno; |
||
323 | break; |
||
324 | |||
325 | case '\r': |
||
326 | break; |
||
327 | |||
328 | case '$': |
||
329 | /* Starting a module name, which we ignore. */ |
||
330 | while ((c = srec_get_byte (abfd, &error)) != '\n' |
||
331 | && c != EOF) |
||
332 | ; |
||
333 | if (c == EOF) |
||
334 | { |
||
335 | srec_bad_byte (abfd, lineno, c, error); |
||
336 | goto error_return; |
||
337 | } |
||
338 | |||
339 | ++lineno; |
||
340 | break; |
||
341 | |||
342 | case ' ': |
||
343 | do |
||
344 | { |
||
345 | bfd_size_type alc; |
||
346 | char *p, *symname; |
||
347 | bfd_vma symval; |
||
348 | |||
349 | /* Starting a symbol definition. */ |
||
350 | while ((c = srec_get_byte (abfd, &error)) != EOF |
||
351 | && (c == ' ' || c == '\t')) |
||
352 | ; |
||
353 | |||
354 | if (c == '\n' || c == '\r') |
||
355 | break; |
||
356 | |||
357 | if (c == EOF) |
||
358 | { |
||
359 | srec_bad_byte (abfd, lineno, c, error); |
||
360 | goto error_return; |
||
361 | } |
||
362 | |||
363 | alc = 10; |
||
364 | symbuf = (char *) bfd_malloc (alc + 1); |
||
365 | if (symbuf == NULL) |
||
366 | goto error_return; |
||
367 | |||
368 | p = symbuf; |
||
369 | |||
370 | *p++ = c; |
||
371 | while ((c = srec_get_byte (abfd, &error)) != EOF |
||
372 | && ! ISSPACE (c)) |
||
373 | { |
||
374 | if ((bfd_size_type) (p - symbuf) >= alc) |
||
375 | { |
||
376 | char *n; |
||
377 | |||
378 | alc *= 2; |
||
379 | n = (char *) bfd_realloc (symbuf, alc + 1); |
||
380 | if (n == NULL) |
||
381 | goto error_return; |
||
382 | p = n + (p - symbuf); |
||
383 | symbuf = n; |
||
384 | } |
||
385 | |||
386 | *p++ = c; |
||
387 | } |
||
388 | |||
389 | if (c == EOF) |
||
390 | { |
||
391 | srec_bad_byte (abfd, lineno, c, error); |
||
392 | goto error_return; |
||
393 | } |
||
394 | |||
395 | *p++ = '\0'; |
||
396 | symname = (char *) bfd_alloc (abfd, (bfd_size_type) (p - symbuf)); |
||
397 | if (symname == NULL) |
||
398 | goto error_return; |
||
399 | strcpy (symname, symbuf); |
||
400 | free (symbuf); |
||
401 | symbuf = NULL; |
||
402 | |||
403 | while ((c = srec_get_byte (abfd, &error)) != EOF |
||
404 | && (c == ' ' || c == '\t')) |
||
405 | ; |
||
406 | if (c == EOF) |
||
407 | { |
||
408 | srec_bad_byte (abfd, lineno, c, error); |
||
409 | goto error_return; |
||
410 | } |
||
411 | |||
412 | /* Skip a dollar sign before the hex value. */ |
||
413 | if (c == '$') |
||
414 | { |
||
415 | c = srec_get_byte (abfd, &error); |
||
416 | if (c == EOF) |
||
417 | { |
||
418 | srec_bad_byte (abfd, lineno, c, error); |
||
419 | goto error_return; |
||
420 | } |
||
421 | } |
||
422 | |||
423 | symval = 0; |
||
424 | while (ISHEX (c)) |
||
425 | { |
||
426 | symval <<= 4; |
||
427 | symval += NIBBLE (c); |
||
428 | c = srec_get_byte (abfd, &error); |
||
429 | if (c == EOF) |
||
430 | { |
||
431 | srec_bad_byte (abfd, lineno, c, error); |
||
432 | goto error_return; |
||
433 | } |
||
434 | } |
||
435 | |||
436 | if (! srec_new_symbol (abfd, symname, symval)) |
||
437 | goto error_return; |
||
438 | } |
||
439 | while (c == ' ' || c == '\t') |
||
440 | ; |
||
441 | |||
442 | if (c == '\n') |
||
443 | ++lineno; |
||
444 | else if (c != '\r') |
||
445 | { |
||
446 | srec_bad_byte (abfd, lineno, c, error); |
||
447 | goto error_return; |
||
448 | } |
||
449 | |||
450 | break; |
||
451 | |||
452 | case 'S': |
||
453 | { |
||
454 | file_ptr pos; |
||
6324 | serge | 455 | unsigned char hdr[3]; |
456 | unsigned int bytes, min_bytes; |
||
5197 | serge | 457 | bfd_vma address; |
458 | bfd_byte *data; |
||
459 | unsigned char check_sum; |
||
460 | |||
461 | /* Starting an S-record. */ |
||
462 | |||
463 | pos = bfd_tell (abfd) - 1; |
||
464 | |||
465 | if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3) |
||
466 | goto error_return; |
||
467 | |||
468 | if (! ISHEX (hdr[1]) || ! ISHEX (hdr[2])) |
||
469 | { |
||
470 | if (! ISHEX (hdr[1])) |
||
471 | c = hdr[1]; |
||
472 | else |
||
473 | c = hdr[2]; |
||
474 | srec_bad_byte (abfd, lineno, c, error); |
||
475 | goto error_return; |
||
476 | } |
||
477 | |||
478 | check_sum = bytes = HEX (hdr + 1); |
||
6324 | serge | 479 | min_bytes = 3; |
480 | if (hdr[0] == '2' || hdr[0] == '8') |
||
481 | min_bytes = 4; |
||
482 | else if (hdr[0] == '3' || hdr[0] == '7') |
||
483 | min_bytes = 5; |
||
484 | if (bytes < min_bytes) |
||
485 | { |
||
486 | (*_bfd_error_handler) (_("%B:%d: byte count %d too small\n"), |
||
487 | abfd, lineno, bytes); |
||
488 | bfd_set_error (bfd_error_bad_value); |
||
489 | goto error_return; |
||
490 | } |
||
491 | |||
5197 | serge | 492 | if (bytes * 2 > bufsize) |
493 | { |
||
494 | if (buf != NULL) |
||
495 | free (buf); |
||
496 | buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2); |
||
497 | if (buf == NULL) |
||
498 | goto error_return; |
||
499 | bufsize = bytes * 2; |
||
500 | } |
||
501 | |||
502 | if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2) |
||
503 | goto error_return; |
||
504 | |||
505 | /* Ignore the checksum byte. */ |
||
506 | --bytes; |
||
507 | |||
508 | address = 0; |
||
509 | data = buf; |
||
510 | switch (hdr[0]) |
||
511 | { |
||
512 | case '0': |
||
513 | case '5': |
||
514 | /* Prologue--ignore the file name, but stop building a |
||
515 | section at this point. */ |
||
516 | sec = NULL; |
||
517 | break; |
||
518 | |||
519 | case '3': |
||
520 | check_sum += HEX (data); |
||
521 | address = HEX (data); |
||
522 | data += 2; |
||
523 | --bytes; |
||
524 | /* Fall through. */ |
||
525 | case '2': |
||
526 | check_sum += HEX (data); |
||
527 | address = (address << 8) | HEX (data); |
||
528 | data += 2; |
||
529 | --bytes; |
||
530 | /* Fall through. */ |
||
531 | case '1': |
||
532 | check_sum += HEX (data); |
||
533 | address = (address << 8) | HEX (data); |
||
534 | data += 2; |
||
535 | check_sum += HEX (data); |
||
536 | address = (address << 8) | HEX (data); |
||
537 | data += 2; |
||
538 | bytes -= 2; |
||
539 | |||
540 | if (sec != NULL |
||
541 | && sec->vma + sec->size == address) |
||
542 | { |
||
543 | /* This data goes at the end of the section we are |
||
544 | currently building. */ |
||
545 | sec->size += bytes; |
||
546 | } |
||
547 | else |
||
548 | { |
||
549 | char secbuf[20]; |
||
550 | char *secname; |
||
551 | bfd_size_type amt; |
||
552 | flagword flags; |
||
553 | |||
554 | sprintf (secbuf, ".sec%d", bfd_count_sections (abfd) + 1); |
||
555 | amt = strlen (secbuf) + 1; |
||
556 | secname = (char *) bfd_alloc (abfd, amt); |
||
557 | strcpy (secname, secbuf); |
||
558 | flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; |
||
559 | sec = bfd_make_section_with_flags (abfd, secname, flags); |
||
560 | if (sec == NULL) |
||
561 | goto error_return; |
||
562 | sec->vma = address; |
||
563 | sec->lma = address; |
||
564 | sec->size = bytes; |
||
565 | sec->filepos = pos; |
||
566 | } |
||
567 | |||
568 | while (bytes > 0) |
||
569 | { |
||
570 | check_sum += HEX (data); |
||
571 | data += 2; |
||
572 | bytes--; |
||
573 | } |
||
574 | check_sum = 255 - (check_sum & 0xff); |
||
575 | if (check_sum != HEX (data)) |
||
576 | { |
||
577 | (*_bfd_error_handler) |
||
578 | (_("%B:%d: Bad checksum in S-record file\n"), |
||
579 | abfd, lineno); |
||
580 | bfd_set_error (bfd_error_bad_value); |
||
581 | goto error_return; |
||
582 | } |
||
583 | |||
584 | break; |
||
585 | |||
586 | case '7': |
||
587 | check_sum += HEX (data); |
||
588 | address = HEX (data); |
||
589 | data += 2; |
||
590 | /* Fall through. */ |
||
591 | case '8': |
||
592 | check_sum += HEX (data); |
||
593 | address = (address << 8) | HEX (data); |
||
594 | data += 2; |
||
595 | /* Fall through. */ |
||
596 | case '9': |
||
597 | check_sum += HEX (data); |
||
598 | address = (address << 8) | HEX (data); |
||
599 | data += 2; |
||
600 | check_sum += HEX (data); |
||
601 | address = (address << 8) | HEX (data); |
||
602 | data += 2; |
||
603 | |||
604 | /* This is a termination record. */ |
||
605 | abfd->start_address = address; |
||
606 | |||
607 | check_sum = 255 - (check_sum & 0xff); |
||
608 | if (check_sum != HEX (data)) |
||
609 | { |
||
610 | (*_bfd_error_handler) |
||
611 | (_("%B:%d: Bad checksum in S-record file\n"), |
||
612 | abfd, lineno); |
||
613 | bfd_set_error (bfd_error_bad_value); |
||
614 | goto error_return; |
||
615 | } |
||
616 | |||
617 | if (buf != NULL) |
||
618 | free (buf); |
||
619 | |||
620 | return TRUE; |
||
621 | } |
||
622 | } |
||
623 | break; |
||
624 | } |
||
625 | } |
||
626 | |||
627 | if (error) |
||
628 | goto error_return; |
||
629 | |||
630 | if (buf != NULL) |
||
631 | free (buf); |
||
632 | |||
633 | return TRUE; |
||
634 | |||
635 | error_return: |
||
636 | if (symbuf != NULL) |
||
637 | free (symbuf); |
||
638 | if (buf != NULL) |
||
639 | free (buf); |
||
640 | return FALSE; |
||
641 | } |
||
642 | |||
643 | /* Check whether an existing file is an S-record file. */ |
||
644 | |||
645 | static const bfd_target * |
||
646 | srec_object_p (bfd *abfd) |
||
647 | { |
||
648 | void * tdata_save; |
||
649 | bfd_byte b[4]; |
||
650 | |||
651 | srec_init (); |
||
652 | |||
653 | if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
||
654 | || bfd_bread (b, (bfd_size_type) 4, abfd) != 4) |
||
655 | return NULL; |
||
656 | |||
657 | if (b[0] != 'S' || !ISHEX (b[1]) || !ISHEX (b[2]) || !ISHEX (b[3])) |
||
658 | { |
||
659 | bfd_set_error (bfd_error_wrong_format); |
||
660 | return NULL; |
||
661 | } |
||
662 | |||
663 | tdata_save = abfd->tdata.any; |
||
664 | if (! srec_mkobject (abfd) || ! srec_scan (abfd)) |
||
665 | { |
||
666 | if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) |
||
667 | bfd_release (abfd, abfd->tdata.any); |
||
668 | abfd->tdata.any = tdata_save; |
||
669 | return NULL; |
||
670 | } |
||
671 | |||
672 | if (abfd->symcount > 0) |
||
673 | abfd->flags |= HAS_SYMS; |
||
674 | |||
675 | return abfd->xvec; |
||
676 | } |
||
677 | |||
678 | /* Check whether an existing file is an S-record file with symbols. */ |
||
679 | |||
680 | static const bfd_target * |
||
681 | symbolsrec_object_p (bfd *abfd) |
||
682 | { |
||
683 | void * tdata_save; |
||
684 | char b[2]; |
||
685 | |||
686 | srec_init (); |
||
687 | |||
688 | if (bfd_seek (abfd, (file_ptr) 0, SEEK_SET) != 0 |
||
689 | || bfd_bread (b, (bfd_size_type) 2, abfd) != 2) |
||
690 | return NULL; |
||
691 | |||
692 | if (b[0] != '$' || b[1] != '$') |
||
693 | { |
||
694 | bfd_set_error (bfd_error_wrong_format); |
||
695 | return NULL; |
||
696 | } |
||
697 | |||
698 | tdata_save = abfd->tdata.any; |
||
699 | if (! srec_mkobject (abfd) || ! srec_scan (abfd)) |
||
700 | { |
||
701 | if (abfd->tdata.any != tdata_save && abfd->tdata.any != NULL) |
||
702 | bfd_release (abfd, abfd->tdata.any); |
||
703 | abfd->tdata.any = tdata_save; |
||
704 | return NULL; |
||
705 | } |
||
706 | |||
707 | if (abfd->symcount > 0) |
||
708 | abfd->flags |= HAS_SYMS; |
||
709 | |||
710 | return abfd->xvec; |
||
711 | } |
||
712 | |||
713 | /* Read in the contents of a section in an S-record file. */ |
||
714 | |||
715 | static bfd_boolean |
||
716 | srec_read_section (bfd *abfd, asection *section, bfd_byte *contents) |
||
717 | { |
||
718 | int c; |
||
719 | bfd_size_type sofar = 0; |
||
720 | bfd_boolean error = FALSE; |
||
721 | bfd_byte *buf = NULL; |
||
722 | size_t bufsize = 0; |
||
723 | |||
724 | if (bfd_seek (abfd, section->filepos, SEEK_SET) != 0) |
||
725 | goto error_return; |
||
726 | |||
727 | while ((c = srec_get_byte (abfd, &error)) != EOF) |
||
728 | { |
||
729 | bfd_byte hdr[3]; |
||
730 | unsigned int bytes; |
||
731 | bfd_vma address; |
||
732 | bfd_byte *data; |
||
733 | |||
734 | if (c == '\r' || c == '\n') |
||
735 | continue; |
||
736 | |||
737 | /* This is called after srec_scan has already been called, so we |
||
738 | ought to know the exact format. */ |
||
739 | BFD_ASSERT (c == 'S'); |
||
740 | |||
741 | if (bfd_bread (hdr, (bfd_size_type) 3, abfd) != 3) |
||
742 | goto error_return; |
||
743 | |||
744 | BFD_ASSERT (ISHEX (hdr[1]) && ISHEX (hdr[2])); |
||
745 | |||
746 | bytes = HEX (hdr + 1); |
||
747 | |||
748 | if (bytes * 2 > bufsize) |
||
749 | { |
||
750 | if (buf != NULL) |
||
751 | free (buf); |
||
752 | buf = (bfd_byte *) bfd_malloc ((bfd_size_type) bytes * 2); |
||
753 | if (buf == NULL) |
||
754 | goto error_return; |
||
755 | bufsize = bytes * 2; |
||
756 | } |
||
757 | |||
758 | if (bfd_bread (buf, (bfd_size_type) bytes * 2, abfd) != bytes * 2) |
||
759 | goto error_return; |
||
760 | |||
761 | address = 0; |
||
762 | data = buf; |
||
763 | switch (hdr[0]) |
||
764 | { |
||
765 | default: |
||
766 | BFD_ASSERT (sofar == section->size); |
||
767 | if (buf != NULL) |
||
768 | free (buf); |
||
769 | return TRUE; |
||
770 | |||
771 | case '3': |
||
772 | address = HEX (data); |
||
773 | data += 2; |
||
774 | --bytes; |
||
775 | /* Fall through. */ |
||
776 | case '2': |
||
777 | address = (address << 8) | HEX (data); |
||
778 | data += 2; |
||
779 | --bytes; |
||
780 | /* Fall through. */ |
||
781 | case '1': |
||
782 | address = (address << 8) | HEX (data); |
||
783 | data += 2; |
||
784 | address = (address << 8) | HEX (data); |
||
785 | data += 2; |
||
786 | bytes -= 2; |
||
787 | |||
788 | if (address != section->vma + sofar) |
||
789 | { |
||
790 | /* We've come to the end of this section. */ |
||
791 | BFD_ASSERT (sofar == section->size); |
||
792 | if (buf != NULL) |
||
793 | free (buf); |
||
794 | return TRUE; |
||
795 | } |
||
796 | |||
797 | /* Don't consider checksum. */ |
||
798 | --bytes; |
||
799 | |||
800 | while (bytes-- != 0) |
||
801 | { |
||
802 | contents[sofar] = HEX (data); |
||
803 | data += 2; |
||
804 | ++sofar; |
||
805 | } |
||
806 | |||
807 | break; |
||
808 | } |
||
809 | } |
||
810 | |||
811 | if (error) |
||
812 | goto error_return; |
||
813 | |||
814 | BFD_ASSERT (sofar == section->size); |
||
815 | |||
816 | if (buf != NULL) |
||
817 | free (buf); |
||
818 | |||
819 | return TRUE; |
||
820 | |||
821 | error_return: |
||
822 | if (buf != NULL) |
||
823 | free (buf); |
||
824 | return FALSE; |
||
825 | } |
||
826 | |||
827 | /* Get the contents of a section in an S-record file. */ |
||
828 | |||
829 | static bfd_boolean |
||
830 | srec_get_section_contents (bfd *abfd, |
||
831 | asection *section, |
||
832 | void * location, |
||
833 | file_ptr offset, |
||
834 | bfd_size_type count) |
||
835 | { |
||
836 | if (count == 0) |
||
837 | return TRUE; |
||
838 | |||
839 | if (offset + count < count |
||
840 | || offset + count > section->size) |
||
841 | { |
||
842 | bfd_set_error (bfd_error_invalid_operation); |
||
843 | return FALSE; |
||
844 | } |
||
845 | |||
846 | if (section->used_by_bfd == NULL) |
||
847 | { |
||
848 | section->used_by_bfd = bfd_alloc (abfd, section->size); |
||
849 | if (section->used_by_bfd == NULL) |
||
850 | return FALSE; |
||
851 | |||
852 | if (! srec_read_section (abfd, section, |
||
853 | (bfd_byte *) section->used_by_bfd)) |
||
854 | return FALSE; |
||
855 | } |
||
856 | |||
857 | memcpy (location, (bfd_byte *) section->used_by_bfd + offset, |
||
858 | (size_t) count); |
||
859 | |||
860 | return TRUE; |
||
861 | } |
||
862 | |||
863 | /* Set the architecture. We accept an unknown architecture here. */ |
||
864 | |||
865 | static bfd_boolean |
||
866 | srec_set_arch_mach (bfd *abfd, enum bfd_architecture arch, unsigned long mach) |
||
867 | { |
||
868 | if (arch != bfd_arch_unknown) |
||
869 | return bfd_default_set_arch_mach (abfd, arch, mach); |
||
870 | |||
871 | abfd->arch_info = & bfd_default_arch_struct; |
||
872 | return TRUE; |
||
873 | } |
||
874 | |||
875 | /* We have to save up all the Srecords for a splurge before output. */ |
||
876 | |||
877 | static bfd_boolean |
||
878 | srec_set_section_contents (bfd *abfd, |
||
879 | sec_ptr section, |
||
880 | const void * location, |
||
881 | file_ptr offset, |
||
882 | bfd_size_type bytes_to_do) |
||
883 | { |
||
884 | int opb = bfd_octets_per_byte (abfd); |
||
885 | tdata_type *tdata = abfd->tdata.srec_data; |
||
886 | srec_data_list_type *entry; |
||
887 | |||
888 | entry = (srec_data_list_type *) bfd_alloc (abfd, sizeof (* entry)); |
||
889 | if (entry == NULL) |
||
890 | return FALSE; |
||
891 | |||
892 | if (bytes_to_do |
||
893 | && (section->flags & SEC_ALLOC) |
||
894 | && (section->flags & SEC_LOAD)) |
||
895 | { |
||
896 | bfd_byte *data; |
||
897 | |||
898 | data = (bfd_byte *) bfd_alloc (abfd, bytes_to_do); |
||
899 | if (data == NULL) |
||
900 | return FALSE; |
||
901 | memcpy ((void *) data, location, (size_t) bytes_to_do); |
||
902 | |||
903 | /* Ff S3Forced is TRUE then always select S3 records, |
||
904 | regardless of the siez of the addresses. */ |
||
905 | if (S3Forced) |
||
906 | tdata->type = 3; |
||
907 | else if ((section->lma + (offset + bytes_to_do) / opb - 1) <= 0xffff) |
||
908 | ; /* The default, S1, is OK. */ |
||
909 | else if ((section->lma + (offset + bytes_to_do) / opb - 1) <= 0xffffff |
||
910 | && tdata->type <= 2) |
||
911 | tdata->type = 2; |
||
912 | else |
||
913 | tdata->type = 3; |
||
914 | |||
915 | entry->data = data; |
||
916 | entry->where = section->lma + offset / opb; |
||
917 | entry->size = bytes_to_do; |
||
918 | |||
919 | /* Sort the records by address. Optimize for the common case of |
||
920 | adding a record to the end of the list. */ |
||
921 | if (tdata->tail != NULL |
||
922 | && entry->where >= tdata->tail->where) |
||
923 | { |
||
924 | tdata->tail->next = entry; |
||
925 | entry->next = NULL; |
||
926 | tdata->tail = entry; |
||
927 | } |
||
928 | else |
||
929 | { |
||
930 | srec_data_list_type **look; |
||
931 | |||
932 | for (look = &tdata->head; |
||
933 | *look != NULL && (*look)->where < entry->where; |
||
934 | look = &(*look)->next) |
||
935 | ; |
||
936 | entry->next = *look; |
||
937 | *look = entry; |
||
938 | if (entry->next == NULL) |
||
939 | tdata->tail = entry; |
||
940 | } |
||
941 | } |
||
942 | return TRUE; |
||
943 | } |
||
944 | |||
945 | /* Write a record of type, of the supplied number of bytes. The |
||
946 | supplied bytes and length don't have a checksum. That's worked out |
||
947 | here. */ |
||
948 | |||
949 | static bfd_boolean |
||
950 | srec_write_record (bfd *abfd, |
||
951 | unsigned int type, |
||
952 | bfd_vma address, |
||
953 | const bfd_byte *data, |
||
954 | const bfd_byte *end) |
||
955 | { |
||
956 | char buffer[2 * MAXCHUNK + 6]; |
||
957 | unsigned int check_sum = 0; |
||
958 | const bfd_byte *src = data; |
||
959 | char *dst = buffer; |
||
960 | char *length; |
||
961 | bfd_size_type wrlen; |
||
962 | |||
963 | *dst++ = 'S'; |
||
964 | *dst++ = '0' + type; |
||
965 | |||
966 | length = dst; |
||
967 | dst += 2; /* Leave room for dst. */ |
||
968 | |||
969 | switch (type) |
||
970 | { |
||
971 | case 3: |
||
972 | case 7: |
||
973 | TOHEX (dst, (address >> 24), check_sum); |
||
974 | dst += 2; |
||
975 | case 8: |
||
976 | case 2: |
||
977 | TOHEX (dst, (address >> 16), check_sum); |
||
978 | dst += 2; |
||
979 | case 9: |
||
980 | case 1: |
||
981 | case 0: |
||
982 | TOHEX (dst, (address >> 8), check_sum); |
||
983 | dst += 2; |
||
984 | TOHEX (dst, (address), check_sum); |
||
985 | dst += 2; |
||
986 | break; |
||
987 | |||
988 | } |
||
989 | for (src = data; src < end; src++) |
||
990 | { |
||
991 | TOHEX (dst, *src, check_sum); |
||
992 | dst += 2; |
||
993 | } |
||
994 | |||
995 | /* Fill in the length. */ |
||
996 | TOHEX (length, (dst - length) / 2, check_sum); |
||
997 | check_sum &= 0xff; |
||
998 | check_sum = 255 - check_sum; |
||
999 | TOHEX (dst, check_sum, check_sum); |
||
1000 | dst += 2; |
||
1001 | |||
1002 | *dst++ = '\r'; |
||
1003 | *dst++ = '\n'; |
||
1004 | wrlen = dst - buffer; |
||
1005 | |||
1006 | return bfd_bwrite ((void *) buffer, wrlen, abfd) == wrlen; |
||
1007 | } |
||
1008 | |||
1009 | static bfd_boolean |
||
1010 | srec_write_header (bfd *abfd) |
||
1011 | { |
||
1012 | unsigned int len = strlen (abfd->filename); |
||
1013 | |||
1014 | /* I'll put an arbitrary 40 char limit on header size. */ |
||
1015 | if (len > 40) |
||
1016 | len = 40; |
||
1017 | |||
1018 | return srec_write_record (abfd, 0, (bfd_vma) 0, |
||
1019 | (bfd_byte *) abfd->filename, |
||
1020 | (bfd_byte *) abfd->filename + len); |
||
1021 | } |
||
1022 | |||
1023 | static bfd_boolean |
||
1024 | srec_write_section (bfd *abfd, |
||
1025 | tdata_type *tdata, |
||
1026 | srec_data_list_type *list) |
||
1027 | { |
||
1028 | unsigned int octets_written = 0; |
||
1029 | bfd_byte *location = list->data; |
||
1030 | |||
1031 | /* Validate number of data bytes to write. The srec length byte |
||
1032 | counts the address, data and crc bytes. S1 (tdata->type == 1) |
||
1033 | records have two address bytes, S2 (tdata->type == 2) records |
||
1034 | have three, and S3 (tdata->type == 3) records have four. |
||
1035 | The total length can't exceed 255, and a zero data length will |
||
1036 | spin for a long time. */ |
||
1037 | if (Chunk == 0) |
||
1038 | Chunk = 1; |
||
1039 | else if (Chunk > MAXCHUNK - tdata->type - 2) |
||
1040 | Chunk = MAXCHUNK - tdata->type - 2; |
||
1041 | |||
1042 | while (octets_written < list->size) |
||
1043 | { |
||
1044 | bfd_vma address; |
||
1045 | unsigned int octets_this_chunk = list->size - octets_written; |
||
1046 | |||
1047 | if (octets_this_chunk > Chunk) |
||
1048 | octets_this_chunk = Chunk; |
||
1049 | |||
1050 | address = list->where + octets_written / bfd_octets_per_byte (abfd); |
||
1051 | |||
1052 | if (! srec_write_record (abfd, |
||
1053 | tdata->type, |
||
1054 | address, |
||
1055 | location, |
||
1056 | location + octets_this_chunk)) |
||
1057 | return FALSE; |
||
1058 | |||
1059 | octets_written += octets_this_chunk; |
||
1060 | location += octets_this_chunk; |
||
1061 | } |
||
1062 | |||
1063 | return TRUE; |
||
1064 | } |
||
1065 | |||
1066 | static bfd_boolean |
||
1067 | srec_write_terminator (bfd *abfd, tdata_type *tdata) |
||
1068 | { |
||
1069 | return srec_write_record (abfd, 10 - tdata->type, |
||
1070 | abfd->start_address, NULL, NULL); |
||
1071 | } |
||
1072 | |||
1073 | static bfd_boolean |
||
1074 | srec_write_symbols (bfd *abfd) |
||
1075 | { |
||
1076 | /* Dump out the symbols of a bfd. */ |
||
1077 | int i; |
||
1078 | int count = bfd_get_symcount (abfd); |
||
1079 | |||
1080 | if (count) |
||
1081 | { |
||
1082 | bfd_size_type len; |
||
1083 | asymbol **table = bfd_get_outsymbols (abfd); |
||
1084 | |||
1085 | len = strlen (abfd->filename); |
||
1086 | if (bfd_bwrite ("$$ ", (bfd_size_type) 3, abfd) != 3 |
||
1087 | || bfd_bwrite (abfd->filename, len, abfd) != len |
||
1088 | || bfd_bwrite ("\r\n", (bfd_size_type) 2, abfd) != 2) |
||
1089 | return FALSE; |
||
1090 | |||
1091 | for (i = 0; i < count; i++) |
||
1092 | { |
||
1093 | asymbol *s = table[i]; |
||
1094 | if (! bfd_is_local_label (abfd, s) |
||
1095 | && (s->flags & BSF_DEBUGGING) == 0) |
||
1096 | { |
||
1097 | /* Just dump out non debug symbols. */ |
||
1098 | char buf[43], *p; |
||
1099 | |||
1100 | len = strlen (s->name); |
||
1101 | if (bfd_bwrite (" ", (bfd_size_type) 2, abfd) != 2 |
||
1102 | || bfd_bwrite (s->name, len, abfd) != len) |
||
1103 | return FALSE; |
||
1104 | |||
1105 | sprintf_vma (buf + 2, (s->value |
||
1106 | + s->section->output_section->lma |
||
1107 | + s->section->output_offset)); |
||
1108 | p = buf + 2; |
||
1109 | while (p[0] == '0' && p[1] != 0) |
||
1110 | p++; |
||
1111 | len = strlen (p); |
||
1112 | p[len] = '\r'; |
||
1113 | p[len + 1] = '\n'; |
||
1114 | *--p = '$'; |
||
1115 | *--p = ' '; |
||
1116 | len += 4; |
||
1117 | if (bfd_bwrite (p, len, abfd) != len) |
||
1118 | return FALSE; |
||
1119 | } |
||
1120 | } |
||
1121 | if (bfd_bwrite ("$$ \r\n", (bfd_size_type) 5, abfd) != 5) |
||
1122 | return FALSE; |
||
1123 | } |
||
1124 | |||
1125 | return TRUE; |
||
1126 | } |
||
1127 | |||
1128 | static bfd_boolean |
||
1129 | internal_srec_write_object_contents (bfd *abfd, int symbols) |
||
1130 | { |
||
1131 | tdata_type *tdata = abfd->tdata.srec_data; |
||
1132 | srec_data_list_type *list; |
||
1133 | |||
1134 | if (symbols) |
||
1135 | { |
||
1136 | if (! srec_write_symbols (abfd)) |
||
1137 | return FALSE; |
||
1138 | } |
||
1139 | |||
1140 | if (! srec_write_header (abfd)) |
||
1141 | return FALSE; |
||
1142 | |||
1143 | /* Now wander though all the sections provided and output them. */ |
||
1144 | list = tdata->head; |
||
1145 | |||
1146 | while (list != (srec_data_list_type *) NULL) |
||
1147 | { |
||
1148 | if (! srec_write_section (abfd, tdata, list)) |
||
1149 | return FALSE; |
||
1150 | list = list->next; |
||
1151 | } |
||
1152 | return srec_write_terminator (abfd, tdata); |
||
1153 | } |
||
1154 | |||
1155 | static bfd_boolean |
||
1156 | srec_write_object_contents (bfd *abfd) |
||
1157 | { |
||
1158 | return internal_srec_write_object_contents (abfd, 0); |
||
1159 | } |
||
1160 | |||
1161 | static bfd_boolean |
||
1162 | symbolsrec_write_object_contents (bfd *abfd) |
||
1163 | { |
||
1164 | return internal_srec_write_object_contents (abfd, 1); |
||
1165 | } |
||
1166 | |||
1167 | static int |
||
1168 | srec_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED, |
||
1169 | struct bfd_link_info *info ATTRIBUTE_UNUSED) |
||
1170 | { |
||
1171 | return 0; |
||
1172 | } |
||
1173 | |||
1174 | /* Return the amount of memory needed to read the symbol table. */ |
||
1175 | |||
1176 | static long |
||
1177 | srec_get_symtab_upper_bound (bfd *abfd) |
||
1178 | { |
||
1179 | return (bfd_get_symcount (abfd) + 1) * sizeof (asymbol *); |
||
1180 | } |
||
1181 | |||
1182 | /* Return the symbol table. */ |
||
1183 | |||
1184 | static long |
||
1185 | srec_canonicalize_symtab (bfd *abfd, asymbol **alocation) |
||
1186 | { |
||
1187 | bfd_size_type symcount = bfd_get_symcount (abfd); |
||
1188 | asymbol *csymbols; |
||
1189 | unsigned int i; |
||
1190 | |||
1191 | csymbols = abfd->tdata.srec_data->csymbols; |
||
1192 | if (csymbols == NULL && symcount != 0) |
||
1193 | { |
||
1194 | asymbol *c; |
||
1195 | struct srec_symbol *s; |
||
1196 | |||
1197 | csymbols = (asymbol *) bfd_alloc (abfd, symcount * sizeof (asymbol)); |
||
1198 | if (csymbols == NULL) |
||
1199 | return -1; |
||
1200 | abfd->tdata.srec_data->csymbols = csymbols; |
||
1201 | |||
1202 | for (s = abfd->tdata.srec_data->symbols, c = csymbols; |
||
1203 | s != NULL; |
||
1204 | s = s->next, ++c) |
||
1205 | { |
||
1206 | c->the_bfd = abfd; |
||
1207 | c->name = s->name; |
||
1208 | c->value = s->val; |
||
1209 | c->flags = BSF_GLOBAL; |
||
1210 | c->section = bfd_abs_section_ptr; |
||
1211 | c->udata.p = NULL; |
||
1212 | } |
||
1213 | } |
||
1214 | |||
1215 | for (i = 0; i < symcount; i++) |
||
1216 | *alocation++ = csymbols++; |
||
1217 | *alocation = NULL; |
||
1218 | |||
1219 | return symcount; |
||
1220 | } |
||
1221 | |||
1222 | static void |
||
1223 | srec_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED, |
||
1224 | asymbol *symbol, |
||
1225 | symbol_info *ret) |
||
1226 | { |
||
1227 | bfd_symbol_info (symbol, ret); |
||
1228 | } |
||
1229 | |||
1230 | static void |
||
1231 | srec_print_symbol (bfd *abfd, |
||
1232 | void * afile, |
||
1233 | asymbol *symbol, |
||
1234 | bfd_print_symbol_type how) |
||
1235 | { |
||
1236 | FILE *file = (FILE *) afile; |
||
1237 | |||
1238 | switch (how) |
||
1239 | { |
||
1240 | case bfd_print_symbol_name: |
||
1241 | fprintf (file, "%s", symbol->name); |
||
1242 | break; |
||
1243 | default: |
||
1244 | bfd_print_symbol_vandf (abfd, (void *) file, symbol); |
||
1245 | fprintf (file, " %-5s %s", |
||
1246 | symbol->section->name, |
||
1247 | symbol->name); |
||
1248 | } |
||
1249 | } |
||
1250 | |||
1251 | #define srec_close_and_cleanup _bfd_generic_close_and_cleanup |
||
1252 | #define srec_bfd_free_cached_info _bfd_generic_bfd_free_cached_info |
||
1253 | #define srec_new_section_hook _bfd_generic_new_section_hook |
||
1254 | #define srec_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false) |
||
1255 | #define srec_bfd_is_local_label_name bfd_generic_is_local_label_name |
||
1256 | #define srec_get_lineno _bfd_nosymbols_get_lineno |
||
1257 | #define srec_find_nearest_line _bfd_nosymbols_find_nearest_line |
||
6324 | serge | 1258 | #define srec_find_line _bfd_nosymbols_find_line |
5197 | serge | 1259 | #define srec_find_inliner_info _bfd_nosymbols_find_inliner_info |
1260 | #define srec_make_empty_symbol _bfd_generic_make_empty_symbol |
||
6324 | serge | 1261 | #define srec_get_symbol_version_string _bfd_nosymbols_get_symbol_version_string |
5197 | serge | 1262 | #define srec_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol |
1263 | #define srec_read_minisymbols _bfd_generic_read_minisymbols |
||
1264 | #define srec_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol |
||
1265 | #define srec_get_section_contents_in_window _bfd_generic_get_section_contents_in_window |
||
1266 | #define srec_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents |
||
1267 | #define srec_bfd_relax_section bfd_generic_relax_section |
||
1268 | #define srec_bfd_gc_sections bfd_generic_gc_sections |
||
1269 | #define srec_bfd_lookup_section_flags bfd_generic_lookup_section_flags |
||
1270 | #define srec_bfd_merge_sections bfd_generic_merge_sections |
||
1271 | #define srec_bfd_is_group_section bfd_generic_is_group_section |
||
1272 | #define srec_bfd_discard_group bfd_generic_discard_group |
||
1273 | #define srec_section_already_linked _bfd_generic_section_already_linked |
||
1274 | #define srec_bfd_define_common_symbol bfd_generic_define_common_symbol |
||
1275 | #define srec_bfd_link_hash_table_create _bfd_generic_link_hash_table_create |
||
1276 | #define srec_bfd_link_add_symbols _bfd_generic_link_add_symbols |
||
1277 | #define srec_bfd_link_just_syms _bfd_generic_link_just_syms |
||
1278 | #define srec_bfd_copy_link_hash_symbol_type \ |
||
1279 | _bfd_generic_copy_link_hash_symbol_type |
||
1280 | #define srec_bfd_final_link _bfd_generic_final_link |
||
1281 | #define srec_bfd_link_split_section _bfd_generic_link_split_section |
||
1282 | |||
1283 | const bfd_target srec_vec = |
||
1284 | { |
||
1285 | "srec", /* Name. */ |
||
1286 | bfd_target_srec_flavour, |
||
1287 | BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
||
1288 | BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
||
1289 | (HAS_RELOC | EXEC_P | /* Object flags. */ |
||
1290 | HAS_LINENO | HAS_DEBUG | |
||
1291 | HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
||
1292 | (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
||
1293 | | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
||
1294 | 0, /* Leading underscore. */ |
||
1295 | ' ', /* AR_pad_char. */ |
||
1296 | 16, /* AR_max_namelen. */ |
||
1297 | 0, /* match priority. */ |
||
1298 | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
||
1299 | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
||
1300 | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
||
1301 | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
||
1302 | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
||
1303 | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Hdrs. */ |
||
1304 | |||
1305 | { |
||
1306 | _bfd_dummy_target, |
||
1307 | srec_object_p, /* bfd_check_format. */ |
||
1308 | _bfd_dummy_target, |
||
1309 | _bfd_dummy_target, |
||
1310 | }, |
||
1311 | { |
||
1312 | bfd_false, |
||
1313 | srec_mkobject, |
||
1314 | _bfd_generic_mkarchive, |
||
1315 | bfd_false, |
||
1316 | }, |
||
1317 | { /* bfd_write_contents. */ |
||
1318 | bfd_false, |
||
1319 | srec_write_object_contents, |
||
1320 | _bfd_write_archive_contents, |
||
1321 | bfd_false, |
||
1322 | }, |
||
1323 | |||
1324 | BFD_JUMP_TABLE_GENERIC (srec), |
||
1325 | BFD_JUMP_TABLE_COPY (_bfd_generic), |
||
1326 | BFD_JUMP_TABLE_CORE (_bfd_nocore), |
||
1327 | BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
||
1328 | BFD_JUMP_TABLE_SYMBOLS (srec), |
||
1329 | BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
||
1330 | BFD_JUMP_TABLE_WRITE (srec), |
||
1331 | BFD_JUMP_TABLE_LINK (srec), |
||
1332 | BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
||
1333 | |||
1334 | NULL, |
||
1335 | |||
1336 | NULL |
||
1337 | }; |
||
1338 | |||
1339 | const bfd_target symbolsrec_vec = |
||
1340 | { |
||
1341 | "symbolsrec", /* Name. */ |
||
1342 | bfd_target_srec_flavour, |
||
1343 | BFD_ENDIAN_UNKNOWN, /* Target byte order. */ |
||
1344 | BFD_ENDIAN_UNKNOWN, /* Target headers byte order. */ |
||
1345 | (HAS_RELOC | EXEC_P | /* Object flags. */ |
||
1346 | HAS_LINENO | HAS_DEBUG | |
||
1347 | HAS_SYMS | HAS_LOCALS | WP_TEXT | D_PAGED), |
||
1348 | (SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS |
||
1349 | | SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* Section flags. */ |
||
1350 | 0, /* Leading underscore. */ |
||
1351 | ' ', /* AR_pad_char. */ |
||
1352 | 16, /* AR_max_namelen. */ |
||
1353 | 0, /* match priority. */ |
||
1354 | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
||
1355 | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
||
1356 | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Data. */ |
||
1357 | bfd_getb64, bfd_getb_signed_64, bfd_putb64, |
||
1358 | bfd_getb32, bfd_getb_signed_32, bfd_putb32, |
||
1359 | bfd_getb16, bfd_getb_signed_16, bfd_putb16, /* Headers. */ |
||
1360 | |||
1361 | { |
||
1362 | _bfd_dummy_target, |
||
1363 | symbolsrec_object_p, /* bfd_check_format. */ |
||
1364 | _bfd_dummy_target, |
||
1365 | _bfd_dummy_target, |
||
1366 | }, |
||
1367 | { |
||
1368 | bfd_false, |
||
1369 | srec_mkobject, |
||
1370 | _bfd_generic_mkarchive, |
||
1371 | bfd_false, |
||
1372 | }, |
||
1373 | { /* bfd_write_contents. */ |
||
1374 | bfd_false, |
||
1375 | symbolsrec_write_object_contents, |
||
1376 | _bfd_write_archive_contents, |
||
1377 | bfd_false, |
||
1378 | }, |
||
1379 | |||
1380 | BFD_JUMP_TABLE_GENERIC (srec), |
||
1381 | BFD_JUMP_TABLE_COPY (_bfd_generic), |
||
1382 | BFD_JUMP_TABLE_CORE (_bfd_nocore), |
||
1383 | BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive), |
||
1384 | BFD_JUMP_TABLE_SYMBOLS (srec), |
||
1385 | BFD_JUMP_TABLE_RELOCS (_bfd_norelocs), |
||
1386 | BFD_JUMP_TABLE_WRITE (srec), |
||
1387 | BFD_JUMP_TABLE_LINK (srec), |
||
1388 | BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic), |
||
1389 | |||
1390 | NULL, |
||
1391 | |||
1392 | NULL |
||
1393 | };>>>>>=>=>=>>><>><>><>><>><>><>><>><>><>>=><=>4)><4)> |