|
|
|
@ -1,6 +1,6 @@ |
|
|
|
/* BFD backend for s-record objects.
|
|
|
|
Copyright (C) 1990-1991 Free Software Foundation, Inc. |
|
|
|
Written by Steve Chamberlain of Cygnus Support <steve@cygnus.com>. |
|
|
|
Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>. |
|
|
|
|
|
|
|
This file is part of BFD, the Binary File Descriptor library. |
|
|
|
|
|
|
|
@ -18,83 +18,138 @@ You should have received a copy of the GNU General Public License |
|
|
|
along with this program; if not, write to the Free Software |
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ |
|
|
|
|
|
|
|
/* S-records cannot hold anything but addresses and data, so that's all
|
|
|
|
that we implement. |
|
|
|
|
|
|
|
The only interesting thing is that s-records may come out of order and |
|
|
|
there is no header, so an initial scan is required to discover the |
|
|
|
minimum and maximum addresses used to create the vma and size of the |
|
|
|
only section we create. We arbitrarily call this section ".text". |
|
|
|
|
|
|
|
When bfd_get_section_contents is called the file is read again, and |
|
|
|
this time the data is placed into a bfd_alloc'd area. |
|
|
|
/*
|
|
|
|
SUBSECTION |
|
|
|
S-record handling |
|
|
|
|
|
|
|
Any number of sections may be created for output, we just output them |
|
|
|
in the order provided to bfd_set_section_contents. */ |
|
|
|
DESCRIPTION |
|
|
|
|
|
|
|
S-records cannot hold anything but addresses and data, so |
|
|
|
that's all that we implement. |
|
|
|
|
|
|
|
The only interesting thing is that s-records may come out of |
|
|
|
order and there is no header, so an initial scan is required |
|
|
|
to discover the minimum and maximum addresses used to create |
|
|
|
the vma and size of the only section we create. We |
|
|
|
arbitrarily call this section ".text". |
|
|
|
|
|
|
|
When bfd_get_section_contents is called the file is read |
|
|
|
again, and this time the data is placed into a bfd_alloc'd |
|
|
|
area. |
|
|
|
|
|
|
|
Any number of sections may be created for output, we save them |
|
|
|
up and output them when it's time to close the bfd. |
|
|
|
|
|
|
|
An s record looks like: |
|
|
|
|
|
|
|
EXAMPLE |
|
|
|
S<length><type><address><data><checksum> |
|
|
|
|
|
|
|
DESCRIPTION |
|
|
|
Where |
|
|
|
o length |
|
|
|
is the number of bytes following upto the checksum. Note that |
|
|
|
this is not the number of chars following, since it takes two |
|
|
|
chars to represent a byte. |
|
|
|
o type |
|
|
|
is one of: |
|
|
|
0) header record |
|
|
|
1) two byte address data record |
|
|
|
2) three byte address data record |
|
|
|
3) four byte address data record |
|
|
|
7) four byte address termination record |
|
|
|
8) three byte address termination record |
|
|
|
9) two byte address termination record |
|
|
|
|
|
|
|
o address |
|
|
|
is the start address of the data following, or in the case of |
|
|
|
a termination record, the start address of the image |
|
|
|
o data |
|
|
|
is the data. |
|
|
|
o checksum |
|
|
|
is the sum of all the raw byte data in the record, from the length |
|
|
|
upwards, modulo 256 and subtracted from 255. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
#include <sysdep.h> |
|
|
|
#include "bfd.h" |
|
|
|
#include "sysdep.h" |
|
|
|
#include "libbfd.h" |
|
|
|
|
|
|
|
|
|
|
|
static char digs[] = "0123456789ABCDEF"; |
|
|
|
|
|
|
|
/* Macros for converting between hex and binary */ |
|
|
|
/* Horrible ascii dependent macros for converting between hex and
|
|
|
|
binary */ |
|
|
|
|
|
|
|
#define CHARS_IN_SET 256 |
|
|
|
static char hex_value[CHARS_IN_SET]; |
|
|
|
#define NOT_HEX 20 |
|
|
|
#define NIBBLE(x) hex_value[x] |
|
|
|
#define HEX(buffer) ((NIBBLE((buffer)[0])<<4) + NIBBLE((buffer)[1])) |
|
|
|
#define TOHEX(d,x, ch) \ |
|
|
|
d[1] = digs[(x) & 0xf]; \ |
|
|
|
d[0] = digs[((x)>>4)&0xf]; ch += (x & 0xff); |
|
|
|
#define ISHEX(x) (hex_value[x] != NOT_HEX) |
|
|
|
|
|
|
|
#define NIBBLE(x) (((x) >= '0' && (x) <= '9') ? ((x) - '0') : ((x) - 'A' + 10)) |
|
|
|
#define HEX(buffer) ((NIBBLE((buffer)->high) <<4) + NIBBLE((buffer)->low)) |
|
|
|
#define TOHEX(d,x) \ |
|
|
|
((d)->low = digs[(x) & 0xf], (d)->high = digs[((x)>>4)&0xf], (x)) |
|
|
|
#define ISHEX(x) (((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F')) |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
char high; |
|
|
|
char low; |
|
|
|
} byte_as_two_char_type; |
|
|
|
|
|
|
|
static |
|
|
|
DEFUN_VOID(srec_init) |
|
|
|
{ |
|
|
|
unsigned int i; |
|
|
|
static boolean inited = false; |
|
|
|
|
|
|
|
if (inited == false) |
|
|
|
{ |
|
|
|
|
|
|
|
inited = true; |
|
|
|
|
|
|
|
for (i = 0; i < CHARS_IN_SET; i++) |
|
|
|
{ |
|
|
|
hex_value[i] = NOT_HEX; |
|
|
|
} |
|
|
|
|
|
|
|
for (i = 0; i < 10; i++) |
|
|
|
{ |
|
|
|
hex_value[i + '0'] = i; |
|
|
|
|
|
|
|
} |
|
|
|
for (i = 0; i < 6; i++) |
|
|
|
{ |
|
|
|
hex_value[i + 'a'] = i+10; |
|
|
|
hex_value[i + 'A'] = i+10; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* The maximum number of bytes on a line is FF */ |
|
|
|
#define MAXCHUNK 0xff |
|
|
|
/* The number of bytes we fit onto a line on output */ |
|
|
|
#define CHUNK 16 |
|
|
|
#define CHUNK 21 |
|
|
|
|
|
|
|
/* We cannot output our srecords as we see them, we have to glue them
|
|
|
|
together, this is done in this structure : */ |
|
|
|
|
|
|
|
struct srec_data_list_struct |
|
|
|
{ |
|
|
|
unsigned char *data; |
|
|
|
bfd_vma where; |
|
|
|
bfd_size_type size; |
|
|
|
struct srec_data_list_struct *next; |
|
|
|
|
|
|
|
} ; |
|
|
|
typedef struct srec_data_list_struct srec_data_list_type; |
|
|
|
|
|
|
|
|
|
|
|
/* The shape of an s-record .. */ |
|
|
|
typedef struct |
|
|
|
{ |
|
|
|
char S; |
|
|
|
char type; |
|
|
|
byte_as_two_char_type size; |
|
|
|
union { |
|
|
|
struct { |
|
|
|
byte_as_two_char_type address[4]; |
|
|
|
byte_as_two_char_type data[MAXCHUNK]; |
|
|
|
/* If there isn't MAXCHUNK bytes of data then the checksum will
|
|
|
|
appear earlier */ |
|
|
|
byte_as_two_char_type checksum; |
|
|
|
char nl; |
|
|
|
} type_3; |
|
|
|
struct { |
|
|
|
byte_as_two_char_type address[4]; |
|
|
|
byte_as_two_char_type data[MAXCHUNK]; |
|
|
|
byte_as_two_char_type checksum; |
|
|
|
char nl; |
|
|
|
} type_6; |
|
|
|
|
|
|
|
struct { |
|
|
|
byte_as_two_char_type address[3]; |
|
|
|
byte_as_two_char_type data[MAXCHUNK]; |
|
|
|
byte_as_two_char_type checksum; |
|
|
|
char nl; |
|
|
|
} type_2; |
|
|
|
|
|
|
|
struct { |
|
|
|
byte_as_two_char_type address[2]; |
|
|
|
byte_as_two_char_type data[MAXCHUNK]; |
|
|
|
byte_as_two_char_type checksum; |
|
|
|
char nl; |
|
|
|
} type_1; |
|
|
|
byte_as_two_char_type data[MAXCHUNK]; |
|
|
|
} u; |
|
|
|
} srec_type; |
|
|
|
srec_data_list_type *head; |
|
|
|
unsigned int type; |
|
|
|
|
|
|
|
} tdata_type; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define enda(x) (x->vma + x->size) |
|
|
|
/*
|
|
|
|
@ -102,18 +157,19 @@ typedef struct |
|
|
|
*/ |
|
|
|
|
|
|
|
static bfd_vma low,high; |
|
|
|
|
|
|
|
static void |
|
|
|
size_srec(abfd, section, address, raw, length) |
|
|
|
bfd *abfd; |
|
|
|
asection *section; |
|
|
|
bfd_vma address; |
|
|
|
byte_as_two_char_type *raw; |
|
|
|
unsigned int length; |
|
|
|
DEFUN(size_srec,(abfd, section, address, raw, length), |
|
|
|
bfd *abfd AND |
|
|
|
asection *section AND |
|
|
|
bfd_vma address AND |
|
|
|
bfd_byte *raw AND |
|
|
|
unsigned int length) |
|
|
|
{ |
|
|
|
if (address < low) |
|
|
|
low = address; |
|
|
|
if (address + length > high) |
|
|
|
high = address + length; |
|
|
|
high = address + length -1; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -122,99 +178,112 @@ unsigned int length; |
|
|
|
*/ |
|
|
|
|
|
|
|
static void |
|
|
|
fillup(abfd, section, address, raw, length) |
|
|
|
bfd *abfd; |
|
|
|
asection *section; |
|
|
|
bfd_vma address; |
|
|
|
byte_as_two_char_type *raw; |
|
|
|
unsigned int length; |
|
|
|
DEFUN(fillup,(abfd, section, address, raw, length), |
|
|
|
bfd *abfd AND |
|
|
|
asection *section AND |
|
|
|
bfd_vma address AND |
|
|
|
bfd_byte *raw AND |
|
|
|
unsigned int length) |
|
|
|
{ |
|
|
|
unsigned int i; |
|
|
|
bfd_byte *dst = (bfd_byte *)(section->used_by_bfd) + address - section->vma; |
|
|
|
for (i = 0; i < length; i++) { |
|
|
|
*dst = HEX(raw); |
|
|
|
dst++; |
|
|
|
raw++; |
|
|
|
} |
|
|
|
unsigned int i; |
|
|
|
bfd_byte *dst = |
|
|
|
(bfd_byte *)(section->used_by_bfd) + |
|
|
|
address - section->vma; |
|
|
|
/* length -1 because we don't read in the checksum */ |
|
|
|
for (i = 0; i < length -1 ; i++) { |
|
|
|
*dst = HEX(raw); |
|
|
|
dst++; |
|
|
|
raw+=2; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/* Pass over an s-record file, calling one of the above functions on each
|
|
|
|
record. */ |
|
|
|
|
|
|
|
static void |
|
|
|
pass_over(abfd, func, section) |
|
|
|
bfd *abfd; |
|
|
|
void (*func)(); |
|
|
|
asection *section; |
|
|
|
DEFUN(pass_over,(abfd, func, section), |
|
|
|
bfd *abfd AND |
|
|
|
void (*func)() AND |
|
|
|
asection *section) |
|
|
|
{ |
|
|
|
unsigned int bytes_on_line; |
|
|
|
boolean eof = false; |
|
|
|
bfd_vma address; |
|
|
|
/* To the front of the file */ |
|
|
|
bfd_seek(abfd, (file_ptr)0, SEEK_SET); |
|
|
|
while (eof == false) |
|
|
|
unsigned int bytes_on_line; |
|
|
|
boolean eof = false; |
|
|
|
bfd_vma address; |
|
|
|
/* To the front of the file */ |
|
|
|
bfd_seek(abfd, (file_ptr)0, SEEK_SET); |
|
|
|
while (eof == false) |
|
|
|
{ |
|
|
|
srec_type buffer; |
|
|
|
|
|
|
|
/* Find first 'S' */ |
|
|
|
eof = bfd_read(&buffer.S, 1, 1, abfd) != 1; |
|
|
|
while (buffer.S != 'S' && !eof) { |
|
|
|
eof = bfd_read(&buffer.S, 1, 1, abfd) != 1; |
|
|
|
} |
|
|
|
if (eof) break; |
|
|
|
|
|
|
|
bfd_read(&buffer.type, 1, 3, abfd); |
|
|
|
|
|
|
|
if (!ISHEX (buffer.size.high) || !ISHEX (buffer.size.low)) |
|
|
|
break; |
|
|
|
bytes_on_line = HEX(&buffer.size); |
|
|
|
if (bytes_on_line > MAXCHUNK/2) |
|
|
|
break; |
|
|
|
|
|
|
|
bfd_read((PTR)buffer.u.data, 1 , bytes_on_line * 2, abfd); |
|
|
|
|
|
|
|
switch (buffer.type) { |
|
|
|
case '6': |
|
|
|
/* Prologue - ignore */ |
|
|
|
break; |
|
|
|
|
|
|
|
case '3': |
|
|
|
address = (HEX(buffer.u.type_3.address+0) << 24) |
|
|
|
+ (HEX(buffer.u.type_3.address+1) << 16) |
|
|
|
+ (HEX(buffer.u.type_3.address+2) << 8) |
|
|
|
+ (HEX(buffer.u.type_3.address+3)); |
|
|
|
func(abfd,section, address, buffer.u.type_3.data, bytes_on_line -1); |
|
|
|
break; |
|
|
|
|
|
|
|
case '2': |
|
|
|
address = (HEX(buffer.u.type_2.address+0) << 16) |
|
|
|
+ (HEX(buffer.u.type_2.address+1) << 8) |
|
|
|
+ (HEX(buffer.u.type_2.address+2)); |
|
|
|
func(abfd,section, address, buffer.u.type_2.data, bytes_on_line -1); |
|
|
|
break; |
|
|
|
|
|
|
|
case '1': |
|
|
|
address = (HEX(buffer.u.type_1.address+0) << 8) |
|
|
|
+ (HEX(buffer.u.type_1.address+1)); |
|
|
|
func(abfd, section, address, buffer.u.type_1.data, bytes_on_line -1); |
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
goto end_of_file; |
|
|
|
} |
|
|
|
char buffer[MAXCHUNK]; |
|
|
|
char *src = buffer; |
|
|
|
char type; |
|
|
|
bfd_vma address = 0; |
|
|
|
|
|
|
|
/* Find first 'S' */ |
|
|
|
eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); |
|
|
|
while (*src!= 'S' && !eof) { |
|
|
|
eof = (boolean)(bfd_read(src, 1, 1, abfd) != 1); |
|
|
|
} |
|
|
|
if (eof) break; |
|
|
|
src++; |
|
|
|
|
|
|
|
/* Fetch the type and the length */ |
|
|
|
bfd_read(src, 1, 3, abfd); |
|
|
|
|
|
|
|
type = *src++; |
|
|
|
|
|
|
|
if (!ISHEX (src[0]) || !ISHEX (src[1])) |
|
|
|
break; |
|
|
|
|
|
|
|
bytes_on_line = HEX(src); |
|
|
|
|
|
|
|
if (bytes_on_line > MAXCHUNK/2) |
|
|
|
break; |
|
|
|
src+=2 ; |
|
|
|
|
|
|
|
bfd_read(src, 1 , bytes_on_line * 2, abfd); |
|
|
|
|
|
|
|
switch (type) { |
|
|
|
case '0': |
|
|
|
case '5': |
|
|
|
/* Prologue - ignore */ |
|
|
|
break; |
|
|
|
case '3': |
|
|
|
address = HEX(src); |
|
|
|
src+=2; |
|
|
|
bytes_on_line--; |
|
|
|
|
|
|
|
case '2': |
|
|
|
address = HEX(src) | (address<<8) ; |
|
|
|
src+=2; |
|
|
|
bytes_on_line--; |
|
|
|
case '1': |
|
|
|
address = HEX(src) | (address<<8) ; |
|
|
|
src+=2; |
|
|
|
address = HEX(src) | (address<<8) ; |
|
|
|
src+=2; |
|
|
|
bytes_on_line-=2; |
|
|
|
func(abfd,section, address, src, bytes_on_line); |
|
|
|
break; |
|
|
|
default: |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
end_of_file: ; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bfd_target * |
|
|
|
srec_object_p (abfd) |
|
|
|
bfd *abfd; |
|
|
|
|
|
|
|
static bfd_target * |
|
|
|
DEFUN(srec_object_p, (abfd), |
|
|
|
bfd *abfd) |
|
|
|
{ |
|
|
|
char b[4]; |
|
|
|
asection *section; |
|
|
|
srec_init(); |
|
|
|
|
|
|
|
bfd_seek(abfd, (file_ptr)0, SEEK_SET); |
|
|
|
bfd_read(b, 1, 4, abfd); |
|
|
|
|
|
|
|
if (b[0] != 'S' || !ISHEX(b[1]) || !ISHEX(b[2]) || !ISHEX(b[3])) |
|
|
|
return (bfd_target*) NULL; |
|
|
|
|
|
|
|
@ -229,129 +298,255 @@ bfd *abfd; |
|
|
|
pass_over(abfd, size_srec, section); |
|
|
|
section->size = high - low; |
|
|
|
section->vma = low; |
|
|
|
section->flags = SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC; |
|
|
|
|
|
|
|
return abfd->xvec; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static boolean |
|
|
|
srec_get_section_contents (abfd, section, location, offset, count) |
|
|
|
bfd *abfd; |
|
|
|
sec_ptr section; |
|
|
|
void *location; |
|
|
|
file_ptr offset; |
|
|
|
unsigned int count; |
|
|
|
DEFUN(srec_get_section_contents,(abfd, section, location, offset, count), |
|
|
|
bfd *abfd AND |
|
|
|
asection *section AND |
|
|
|
PTR location AND |
|
|
|
file_ptr offset AND |
|
|
|
bfd_size_type count) |
|
|
|
{ |
|
|
|
if (section->used_by_bfd == (PTR)NULL) { |
|
|
|
section->used_by_bfd = (PTR)bfd_alloc (abfd, section->size); |
|
|
|
pass_over(abfd, fillup, section); |
|
|
|
} |
|
|
|
(void) memcpy((PTR)location, (PTR)((char *)(section->used_by_bfd) + offset), count); |
|
|
|
return true; |
|
|
|
if (section->used_by_bfd == (PTR)NULL) |
|
|
|
{ |
|
|
|
section->used_by_bfd = (PTR)bfd_alloc (abfd, section->size); |
|
|
|
pass_over(abfd, fillup, section); |
|
|
|
} |
|
|
|
(void) memcpy((PTR)location, |
|
|
|
(PTR)((char *)(section->used_by_bfd) + offset), |
|
|
|
count); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
boolean |
|
|
|
srec_set_arch_mach (abfd, arch, machine) |
|
|
|
bfd *abfd; |
|
|
|
enum bfd_architecture arch; |
|
|
|
unsigned long machine; |
|
|
|
DEFUN(srec_set_arch_mach,(abfd, arch, machine), |
|
|
|
bfd *abfd AND |
|
|
|
enum bfd_architecture arch AND |
|
|
|
unsigned long machine) |
|
|
|
{ |
|
|
|
abfd->obj_arch = arch; |
|
|
|
abfd->obj_machine = machine; |
|
|
|
return true; |
|
|
|
return bfd_default_set_arch_mach(abfd, arch, machine); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* we have to save up all the Srecords for a splurge before output,
|
|
|
|
also remember */ |
|
|
|
|
|
|
|
boolean |
|
|
|
srec_set_section_contents (abfd, section, location, offset, bytes_to_do) |
|
|
|
bfd *abfd; |
|
|
|
sec_ptr section; |
|
|
|
unsigned char *location; |
|
|
|
file_ptr offset; |
|
|
|
int bytes_to_do; |
|
|
|
static boolean |
|
|
|
DEFUN(srec_set_section_contents,(abfd, section, location, offset, bytes_to_do), |
|
|
|
bfd *abfd AND |
|
|
|
sec_ptr section AND |
|
|
|
PTR location AND |
|
|
|
file_ptr offset AND |
|
|
|
bfd_size_type bytes_to_do) |
|
|
|
{ |
|
|
|
bfd_vma address; |
|
|
|
int bytes_written; |
|
|
|
|
|
|
|
int type; |
|
|
|
unsigned int i; |
|
|
|
srec_type buffer; |
|
|
|
bytes_written = 0; |
|
|
|
if (section->vma <= 0xffff) |
|
|
|
type = 1; |
|
|
|
else if (section->vma <= 0xffffff) |
|
|
|
type = 2; |
|
|
|
else |
|
|
|
type = 3; |
|
|
|
|
|
|
|
buffer.S = 'S'; |
|
|
|
buffer.type = '0' + type; |
|
|
|
|
|
|
|
while (bytes_written < bytes_to_do) { |
|
|
|
unsigned int size; |
|
|
|
unsigned int check_sum; |
|
|
|
byte_as_two_char_type *data; |
|
|
|
unsigned int bytes_this_chunk = bytes_to_do - bytes_written; |
|
|
|
|
|
|
|
if (bytes_this_chunk > CHUNK) { |
|
|
|
bytes_this_chunk = CHUNK; |
|
|
|
tdata_type *tdata = (tdata_type *)(abfd->tdata); |
|
|
|
srec_data_list_type *entry = (srec_data_list_type *) |
|
|
|
bfd_alloc(abfd, sizeof(srec_data_list_type)); |
|
|
|
unsigned char *data = (unsigned char *) bfd_alloc(abfd, bytes_to_do); |
|
|
|
memcpy(data, location, bytes_to_do); |
|
|
|
|
|
|
|
if ((section->vma + offset + bytes_to_do) <= 0xffff) |
|
|
|
{ |
|
|
|
|
|
|
|
} |
|
|
|
else if ((section->vma + offset + bytes_to_do) <= 0xffffff |
|
|
|
&& tdata->type < 2) |
|
|
|
{ |
|
|
|
tdata->type = 2; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
tdata->type = 3; |
|
|
|
} |
|
|
|
|
|
|
|
entry->data = data; |
|
|
|
entry->where = section->vma + offset; |
|
|
|
entry->size = bytes_to_do; |
|
|
|
entry->next = tdata->head; |
|
|
|
tdata->head = entry; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Write a record of type, of the supplied number of bytes. The
|
|
|
|
supplied bytes and length don't have a checksum. That's worked out |
|
|
|
here |
|
|
|
*/ |
|
|
|
static |
|
|
|
void DEFUN(srec_write_record,(abfd, type, address, data, end), |
|
|
|
bfd *abfd AND |
|
|
|
char type AND |
|
|
|
bfd_vma address AND |
|
|
|
CONST unsigned char *data AND |
|
|
|
CONST unsigned char *end) |
|
|
|
|
|
|
|
{ |
|
|
|
char buffer[MAXCHUNK]; |
|
|
|
|
|
|
|
unsigned int check_sum = 0; |
|
|
|
unsigned CONST char *src = data; |
|
|
|
char *dst =buffer; |
|
|
|
char *length; |
|
|
|
|
|
|
|
|
|
|
|
*dst++ = 'S'; |
|
|
|
*dst++ = '0' + type; |
|
|
|
|
|
|
|
length = dst; |
|
|
|
dst+=2; /* leave room for dst*/ |
|
|
|
|
|
|
|
switch (type) |
|
|
|
{ |
|
|
|
case 3: |
|
|
|
case 7: |
|
|
|
TOHEX(dst, (address >> 24), check_sum); |
|
|
|
dst+=2; |
|
|
|
case 8: |
|
|
|
case 2: |
|
|
|
TOHEX(dst, (address >> 16), check_sum); |
|
|
|
dst+=2; |
|
|
|
case 9: |
|
|
|
case 1: |
|
|
|
case 0: |
|
|
|
TOHEX(dst, (address >> 8), check_sum); |
|
|
|
dst+=2; |
|
|
|
TOHEX(dst, (address), check_sum); |
|
|
|
dst+=2; |
|
|
|
break; |
|
|
|
|
|
|
|
address = section->vma + offset + bytes_written; |
|
|
|
|
|
|
|
switch (type) { |
|
|
|
case 3: |
|
|
|
check_sum = TOHEX(buffer.u.type_3.address, address >> 24); |
|
|
|
check_sum += TOHEX(buffer.u.type_3.address+1, address >> 16); |
|
|
|
check_sum += TOHEX(buffer.u.type_3.address+2, address >> 8); |
|
|
|
check_sum += TOHEX(buffer.u.type_3.address+3, address >> 0); |
|
|
|
size = bytes_this_chunk + 5; |
|
|
|
data = buffer.u.type_3.data; |
|
|
|
break; |
|
|
|
case 2: |
|
|
|
check_sum = TOHEX(buffer.u.type_3.address, address >> 16); |
|
|
|
check_sum += TOHEX(buffer.u.type_3.address+1, address >> 8); |
|
|
|
check_sum += TOHEX(buffer.u.type_3.address+2, address >> 0); |
|
|
|
size = bytes_this_chunk + 4; |
|
|
|
data = buffer.u.type_2.data; |
|
|
|
break; |
|
|
|
|
|
|
|
case 1: |
|
|
|
check_sum = TOHEX(buffer.u.type_3.address+0, address >> 8); |
|
|
|
check_sum += TOHEX(buffer.u.type_3.address+1, address >> 0); |
|
|
|
size = bytes_this_chunk + 3; |
|
|
|
data = buffer.u.type_1.data; |
|
|
|
break; |
|
|
|
} |
|
|
|
for (src = data; src < end; src++) |
|
|
|
{ |
|
|
|
TOHEX(dst, *src, check_sum); |
|
|
|
dst+=2; |
|
|
|
|
|
|
|
for (i = 0; i < bytes_this_chunk; i++) { |
|
|
|
check_sum += TOHEX(data, (location[i])); |
|
|
|
data++; |
|
|
|
} |
|
|
|
|
|
|
|
check_sum += TOHEX(&(buffer.size), size ); |
|
|
|
(void) TOHEX(data, ~check_sum); |
|
|
|
data++; |
|
|
|
/* Fill in the length */ |
|
|
|
TOHEX(length, (dst - length)/2, check_sum); |
|
|
|
check_sum &= 0xff; |
|
|
|
check_sum = 255 - check_sum; |
|
|
|
TOHEX(dst, check_sum, check_sum); |
|
|
|
dst+=2; |
|
|
|
|
|
|
|
*dst ++ = '\n'; |
|
|
|
bfd_write((PTR)buffer, 1, dst - buffer , abfd); |
|
|
|
} |
|
|
|
|
|
|
|
* ( (char *)(data)) = '\n'; |
|
|
|
bfd_write((PTR)&buffer, 1, (char *)data - (char *)&buffer + 1 , abfd); |
|
|
|
|
|
|
|
bytes_written += bytes_this_chunk; |
|
|
|
location += bytes_this_chunk; |
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
DEFUN(srec_write_header,(abfd), |
|
|
|
bfd *abfd) |
|
|
|
{ |
|
|
|
unsigned char buffer[MAXCHUNK]; |
|
|
|
unsigned char *dst = buffer; |
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
return true; |
|
|
|
/* I'll put an arbitary 40 char limit on header size */ |
|
|
|
for (i = 0; i < 40 && abfd->filename[i]; i++) |
|
|
|
{ |
|
|
|
*dst++ = abfd->filename[i]; |
|
|
|
} |
|
|
|
srec_write_record(abfd,0, 0, buffer, dst); |
|
|
|
} |
|
|
|
|
|
|
|
boolean |
|
|
|
srec_write_object_contents (abfd) |
|
|
|
bfd *abfd; |
|
|
|
static void |
|
|
|
DEFUN(srec_write_section,(abfd, tdata, list), |
|
|
|
bfd *abfd AND |
|
|
|
tdata_type *tdata AND |
|
|
|
srec_data_list_type *list) |
|
|
|
{ |
|
|
|
unsigned int bytes_written = 0; |
|
|
|
unsigned char *location = list->data; |
|
|
|
|
|
|
|
while (bytes_written < list->size) |
|
|
|
{ |
|
|
|
char buffer[MAXCHUNK]; |
|
|
|
char *dst = buffer; |
|
|
|
bfd_vma address; |
|
|
|
unsigned int i; |
|
|
|
|
|
|
|
unsigned int bytes_this_chunk = list->size - bytes_written; |
|
|
|
|
|
|
|
if (bytes_this_chunk > CHUNK) |
|
|
|
{ |
|
|
|
bytes_this_chunk = CHUNK; |
|
|
|
} |
|
|
|
|
|
|
|
address = list->where + bytes_written; |
|
|
|
|
|
|
|
srec_write_record(abfd, |
|
|
|
tdata->type, |
|
|
|
address, |
|
|
|
location, |
|
|
|
location + bytes_this_chunk); |
|
|
|
|
|
|
|
bytes_written += bytes_this_chunk; |
|
|
|
location += bytes_this_chunk; |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
static void |
|
|
|
DEFUN(srec_write_terminator,(abfd, tdata), |
|
|
|
bfd *abfd AND |
|
|
|
tdata_type *tdata) |
|
|
|
{ |
|
|
|
unsigned char buffer[2]; |
|
|
|
|
|
|
|
srec_write_record(abfd, 10 - tdata->type, |
|
|
|
abfd->start_address, buffer, buffer); |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
static boolean |
|
|
|
DEFUN(srec_mkobject, (abfd), |
|
|
|
bfd *abfd) |
|
|
|
{ |
|
|
|
tdata_type *tdata = (tdata_type *)bfd_alloc(abfd, sizeof(tdata_type)); |
|
|
|
abfd->tdata = (PTR)tdata; |
|
|
|
tdata->type = 1; |
|
|
|
tdata->head = (srec_data_list_type *)NULL; |
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static boolean |
|
|
|
DEFUN(srec_write_object_contents,(abfd), |
|
|
|
bfd *abfd) |
|
|
|
{ |
|
|
|
bfd_write("S9030000FC\n", 1,11,abfd); |
|
|
|
return true; |
|
|
|
bfd_vma address; |
|
|
|
int bytes_written; |
|
|
|
|
|
|
|
int type; |
|
|
|
unsigned int i; |
|
|
|
tdata_type *tdata = (tdata_type *)(abfd->tdata); |
|
|
|
srec_data_list_type *list; |
|
|
|
|
|
|
|
bytes_written = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
srec_write_header(abfd); |
|
|
|
|
|
|
|
/* Now wander though all the sections provided and output them */ |
|
|
|
list = tdata->head; |
|
|
|
|
|
|
|
while (list != (srec_data_list_type*)NULL) |
|
|
|
{ |
|
|
|
srec_write_section(abfd, tdata, list); |
|
|
|
list = list->next; |
|
|
|
} |
|
|
|
srec_write_terminator(abfd, tdata); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
static int |
|
|
|
@ -377,7 +572,7 @@ DEFUN(srec_make_empty_symbol, (abfd), |
|
|
|
#define srec_get_reloc_upper_bound (FOO(unsigned int, (*),(bfd*, asection *)))bfd_false |
|
|
|
#define srec_canonicalize_reloc (FOO(unsigned int, (*),(bfd*,asection *, arelent **, asymbol **))) bfd_0 |
|
|
|
|
|
|
|
#define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_enum_type))) bfd_void |
|
|
|
#define srec_print_symbol (FOO(void,(*),(bfd *, PTR, asymbol *, bfd_print_symbol_type))) bfd_void |
|
|
|
|
|
|
|
#define srec_openr_next_archived_file (FOO(bfd *, (*), (bfd*,bfd*))) bfd_nullvoidptr |
|
|
|
#define srec_find_nearest_line (FOO(boolean, (*),(bfd*,asection*,asymbol**,bfd_vma, CONST char**, CONST char**, unsigned int *))) bfd_false |
|
|
|
@ -390,7 +585,7 @@ DEFUN(srec_make_empty_symbol, (abfd), |
|
|
|
#define srec_slurp_armap bfd_true |
|
|
|
#define srec_slurp_extended_name_table bfd_true |
|
|
|
#define srec_truncate_arname (void (*)())bfd_nullvoidptr |
|
|
|
#define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, int, int))) bfd_nullvoidptr |
|
|
|
#define srec_write_armap (FOO( boolean, (*),(bfd *, unsigned int, struct orl *, unsigned int, int))) bfd_nullvoidptr |
|
|
|
#define srec_get_lineno (struct lineno_cache_entry *(*)())bfd_nullvoidptr |
|
|
|
#define srec_close_and_cleanup bfd_generic_close_and_cleanup |
|
|
|
#define srec_bfd_debug_info_start bfd_void |
|
|
|
@ -400,37 +595,41 @@ DEFUN(srec_make_empty_symbol, (abfd), |
|
|
|
|
|
|
|
bfd_target srec_vec = |
|
|
|
{ |
|
|
|
"srec", /* name */ |
|
|
|
bfd_target_srec_flavour_enum, |
|
|
|
true, /* target byte order */ |
|
|
|
true, /* target headers byte order */ |
|
|
|
(HAS_RELOC | EXEC_P | /* object flags */ |
|
|
|
HAS_LINENO | HAS_DEBUG | |
|
|
|
HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), |
|
|
|
(SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS |
|
|
|
|SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ |
|
|
|
' ', /* ar_pad_char */ |
|
|
|
16, /* ar_max_namelen */ |
|
|
|
"srec", /* name */ |
|
|
|
bfd_target_srec_flavour, |
|
|
|
true, /* target byte order */ |
|
|
|
true, /* target headers byte order */ |
|
|
|
(HAS_RELOC | EXEC_P | /* object flags */ |
|
|
|
HAS_LINENO | HAS_DEBUG | |
|
|
|
HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT | D_PAGED), |
|
|
|
(SEC_CODE|SEC_DATA|SEC_ROM|SEC_HAS_CONTENTS |
|
|
|
|SEC_ALLOC | SEC_LOAD | SEC_RELOC), /* section flags */ |
|
|
|
' ', /* ar_pad_char */ |
|
|
|
16, /* ar_max_namelen */ |
|
|
|
1, /* minimum alignment */ |
|
|
|
_do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* data */ |
|
|
|
_do_getb64, _do_putb64, _do_getb32, _do_putb32, _do_getb16, _do_putb16, /* hdrs */ |
|
|
|
|
|
|
|
{_bfd_dummy_target, |
|
|
|
srec_object_p, /* bfd_check_format */ |
|
|
|
(struct bfd_target *(*)()) bfd_nullvoidptr, |
|
|
|
(struct bfd_target *(*)()) bfd_nullvoidptr, |
|
|
|
}, |
|
|
|
{ |
|
|
|
_do_getb64, _do_putb64, _do_getb32, |
|
|
|
_do_putb32, _do_getb16, _do_putb16, /* data */ |
|
|
|
_do_getb64, _do_putb64, _do_getb32, |
|
|
|
_do_putb32, _do_getb16, _do_putb16, /* hdrs */ |
|
|
|
|
|
|
|
{ |
|
|
|
_bfd_dummy_target, |
|
|
|
srec_object_p, /* bfd_check_format */ |
|
|
|
(struct bfd_target *(*)()) bfd_nullvoidptr, |
|
|
|
(struct bfd_target *(*)()) bfd_nullvoidptr, |
|
|
|
}, |
|
|
|
{ |
|
|
|
bfd_false, |
|
|
|
bfd_true, /* mkobject */ |
|
|
|
srec_mkobject, |
|
|
|
_bfd_generic_mkarchive, |
|
|
|
bfd_false, |
|
|
|
}, |
|
|
|
{ /* bfd_write_contents */ |
|
|
|
}, |
|
|
|
{ /* bfd_write_contents */ |
|
|
|
bfd_false, |
|
|
|
srec_write_object_contents, |
|
|
|
_bfd_write_archive_contents, |
|
|
|
bfd_false, |
|
|
|
}, |
|
|
|
JUMP_TABLE(srec) |
|
|
|
}; |
|
|
|
}, |
|
|
|
JUMP_TABLE(srec) |
|
|
|
}; |
|
|
|
|
|
|
|
|