3 changed files with 1230 additions and 0 deletions
@ -0,0 +1,65 @@ |
|||
/*doc*
|
|||
@section Core files |
|||
Buff output this facinating topic |
|||
*/ |
|||
|
|||
#include "sysdep.h" |
|||
#include "bfd.h" |
|||
#include "libbfd.h" |
|||
|
|||
/** Some core file info commands */ |
|||
|
|||
/*proto*i bfd_core_file_failing_command
|
|||
Returns a read-only string explaining what program was running when |
|||
it failed and produced the core file being read |
|||
|
|||
*; PROTO(CONST char *, bfd_core_file_failing_command, (bfd *)); |
|||
*/ |
|||
|
|||
CONST char * |
|||
DEFUN(bfd_core_file_failing_command,(abfd), |
|||
bfd *abfd) |
|||
{ |
|||
if (abfd->format != bfd_core) { |
|||
bfd_error = invalid_operation; |
|||
return NULL; |
|||
} |
|||
return BFD_SEND (abfd, _core_file_failing_command, (abfd)); |
|||
} |
|||
|
|||
/*proto* bfd_core_file_failing_signal
|
|||
Returns the signal number which caused the core dump which generated |
|||
the file the bfd is attatched to. |
|||
|
|||
*; PROTO(int, bfd_core_file_failing_signal, (bfd *)); |
|||
*/ |
|||
int |
|||
bfd_core_file_failing_signal (abfd) |
|||
bfd *abfd; |
|||
{ |
|||
if (abfd->format != bfd_core) { |
|||
bfd_error = invalid_operation; |
|||
return 0; |
|||
} |
|||
return BFD_SEND (abfd, _core_file_failing_signal, (abfd)); |
|||
} |
|||
|
|||
|
|||
/*proto* core_file_matches_executable_p
|
|||
Returns @code{true} if the core file attatched to @var{core_bfd} was |
|||
generated by a run of the executable file attatched to @var{exec_bfd}, |
|||
or else @code{false}. |
|||
*; PROTO(boolean, core_file_matches_executable_p, |
|||
(bfd *core_bfd, bfd *exec_bfd)); |
|||
*/ |
|||
boolean |
|||
core_file_matches_executable_p (core_bfd, exec_bfd) |
|||
bfd *core_bfd, *exec_bfd; |
|||
{ |
|||
if ((core_bfd->format != bfd_core) || (exec_bfd->format != bfd_object)) { |
|||
bfd_error = wrong_format; |
|||
return false; |
|||
} |
|||
|
|||
return BFD_SEND (core_bfd, _core_file_matches_executable_p, (core_bfd, exec_bfd)); |
|||
} |
|||
@ -0,0 +1,612 @@ |
|||
/*doc*
|
|||
@section Relocations |
|||
|
|||
Bfd maintains relocations in much the same was as it maintains |
|||
symbols; they are left alone until required, then read in en-mass and |
|||
traslated into an internal form. There is a common routine |
|||
@code{bfd_perform_relocation} which acts upon the canonical form to to |
|||
the actual fixup. |
|||
|
|||
Note that relocations are maintained on a per section basis, whilst |
|||
symbols are maintained on a per bfd basis. |
|||
|
|||
All a back end has to do to fit the bfd interface is to create as many |
|||
@code{struct reloc_cache_entry} as there are relocations in a |
|||
particuar section, and fill in the right bits: |
|||
|
|||
@menu |
|||
* typedef arelent:: |
|||
* reloc handling functions:: |
|||
@end menu |
|||
|
|||
*/ |
|||
#include "sysdep.h" |
|||
#include "bfd.h" |
|||
#include "libbfd.h" |
|||
/*doc
|
|||
*node typedef arelent, Relocations, reloc handling functions, Relocations |
|||
@section typedef arelent |
|||
|
|||
|
|||
*/ |
|||
|
|||
/*proto* bfd_perform_relocation
|
|||
The relocation routine returns as a status an enumerated type: |
|||
|
|||
*+++ |
|||
|
|||
$typedef enum bfd_reloc_status { |
|||
No errors detected |
|||
|
|||
$ bfd_reloc_ok, |
|||
|
|||
The relocation was performed, but there was an overflow. |
|||
|
|||
$ bfd_reloc_overflow, |
|||
|
|||
The address to relocate was not within the section supplied |
|||
|
|||
$ bfd_reloc_outofrange, |
|||
|
|||
Used by special functions |
|||
|
|||
$ bfd_reloc_continue, |
|||
|
|||
Unused |
|||
|
|||
$ bfd_reloc_notsupported, |
|||
|
|||
Unsupported relocation size requested. |
|||
|
|||
$ bfd_reloc_other, |
|||
|
|||
The symbol to relocate against was undefined. |
|||
|
|||
$ bfd_reloc_undefined, |
|||
|
|||
The relocaction was performed, but may not be ok - presently generated |
|||
only when linking i960 coff files with i960 b.out symbols. |
|||
|
|||
$ bfd_reloc_dangerous |
|||
$ } |
|||
$ bfd_reloc_status_enum_type; |
|||
|
|||
*--- |
|||
|
|||
*/ |
|||
|
|||
/*proto*
|
|||
|
|||
*+++ |
|||
|
|||
$typedef struct reloc_cache_entry |
|||
${ |
|||
|
|||
A pointer into the canonical table of pointers |
|||
|
|||
$ struct symbol_cache_entry **sym_ptr_ptr; |
|||
|
|||
offset in section |
|||
|
|||
$ rawdata_offset address; |
|||
|
|||
addend for relocation value |
|||
|
|||
$ bfd_vma addend; |
|||
|
|||
if sym is null this is the section |
|||
|
|||
$ struct sec *section; |
|||
|
|||
Pointer to how to perform the required relocation |
|||
|
|||
$ struct reloc_howto_struct *howto; |
|||
$} arelent; |
|||
|
|||
*--- |
|||
|
|||
*/ |
|||
|
|||
/*doc*
|
|||
@table @code |
|||
@item sym_ptr_ptr |
|||
The symbol table pointer points to a pointer to the symbol ascociated with the |
|||
relocation request. This would naturaly be the pointer into the table |
|||
returned by the back end's get_symtab action. @xref{Symbols}. The |
|||
symbol is referenced through a pointer to a pointer so that tools like |
|||
the linker can fixup all the symbols of the same name by modifying |
|||
only one pointer. The relocation routine looks in the symbol and uses |
|||
the base of the section the symbol is attatched to and the value of |
|||
the symbol as the initial relocation offset. If the symbol pointer is |
|||
zero, then the section provided is looked up. |
|||
@item address |
|||
The address field gives the offset in bytes from the base of the |
|||
section data which owns the relocation record to the first byte of |
|||
relocatable information. The actual data relocated will be relative to |
|||
this point - for example, a relocation type which modifies the bottom |
|||
two bytes of a four byte word would not touch the first byte pointed |
|||
to in a big endian world. |
|||
@item addend |
|||
The addend is a value provided by the back end to be added (!) to the |
|||
relocation offset. It's interpretation is dependent upon the howto. |
|||
For example, on the 68k the code: |
|||
|
|||
*+ |
|||
char foo[]; |
|||
main() |
|||
{ |
|||
return foo[0x12345678]; |
|||
} |
|||
*- |
|||
Could be compiled into: |
|||
|
|||
*+ |
|||
linkw fp,#-4 |
|||
moveb @@#12345678,d0 |
|||
extbl d0 |
|||
unlk fp |
|||
rts |
|||
*- |
|||
|
|||
This could create a reloc pointing to foo, but leave the offset in the data |
|||
(something like) |
|||
|
|||
*+ |
|||
RELOCATION RECORDS FOR [.text]: |
|||
OFFSET TYPE VALUE |
|||
00000006 32 _foo |
|||
|
|||
00000000 4e56 fffc ; linkw fp,#-4 |
|||
00000004 1039 1234 5678 ; moveb @@#12345678,d0 |
|||
0000000a 49c0 ; extbl d0 |
|||
0000000c 4e5e ; unlk fp |
|||
0000000e 4e75 ; rts |
|||
*- |
|||
Using coff and an 88k, some instructions don't have enough space in them to |
|||
represent the full address range, and pointers have to be loaded in |
|||
two parts. So you'd get something like: |
|||
|
|||
*+ |
|||
or.u r13,r0,hi16(_foo+0x12345678) |
|||
ld.b r2,r13,lo16(_foo+0x12345678) |
|||
jmp r1 |
|||
*- |
|||
This whould create two relocs, both pointing to _foo, and with 0x12340000 |
|||
in their addend field. The data would consist of: |
|||
|
|||
*+ |
|||
|
|||
RELOCATION RECORDS FOR [.text]: |
|||
OFFSET TYPE VALUE |
|||
00000002 HVRT16 _foo+0x12340000 |
|||
00000006 LVRT16 _foo+0x12340000 |
|||
|
|||
00000000 5da05678 ; or.u r13,r0,0x5678 |
|||
00000004 1c4d5678 ; ld.b r2,r13,0x5678 |
|||
00000008 f400c001 ; jmp r1 |
|||
*- |
|||
The relocation routine digs out the value from the data, adds it to |
|||
the addend to get the original offset and then adds the value of _foo. |
|||
Note that all 32 bits have to be kept around somewhere, to cope with |
|||
carry from bit 15 to bit 16. |
|||
|
|||
On further example is the sparc and the a.out format. The sparc has a |
|||
similar problem to the 88k, in that some instructions don't have |
|||
room for an entire offset, but on the sparc the parts are created odd |
|||
sized lumps. The designers of the a.out format chose not to use the |
|||
data within the section for storing part of the offset; all the offset |
|||
is kept within the reloc. Any thing in the data should be ignored. |
|||
|
|||
*+ |
|||
save %sp,-112,%sp |
|||
sethi %hi(_foo+0x12345678),%g2 |
|||
ldsb [%g2+%lo(_foo+0x12345678)],%i0 |
|||
ret |
|||
restore |
|||
*- |
|||
Both relocs contains a pointer to foo, and the offsets would contain junk. |
|||
|
|||
*+ |
|||
RELOCATION RECORDS FOR [.text]: |
|||
OFFSET TYPE VALUE |
|||
00000004 HI22 _foo+0x12345678 |
|||
00000008 LO10 _foo+0x12345678 |
|||
|
|||
00000000 9de3bf90 ; save %sp,-112,%sp |
|||
00000004 05000000 ; sethi %hi(_foo+0),%g2 |
|||
00000008 f048a000 ; ldsb [%g2+%lo(_foo+0)],%i0 |
|||
0000000c 81c7e008 ; ret |
|||
00000010 81e80000 ; restore |
|||
*- |
|||
@item section |
|||
The section field is only used when the symbol pointer field is null. |
|||
It supplies the section into which the data should be relocated. The |
|||
field's main use comes from assemblers which do most of the symbol fixups |
|||
themselves; an assembler may take an internal reference to a label, |
|||
but since it knows where the label is, it can turn the relocation |
|||
request from a symbol lookup into a section relative relocation - the |
|||
relocation emitted has no symbol, just a section to relocate against. |
|||
|
|||
I'm not sure what it means when both a symbol pointer an a section |
|||
pointer are present. Some formats use this sort of mechanism to |
|||
describe PIC relocations, but bfd can't to that sort of thing yet. |
|||
@item howto |
|||
The howto field can be imagined as a relocation instruction. It is a |
|||
pointer to a struct which contains information on what to do with all |
|||
the other information in the reloc record and data section. A back end |
|||
would normally have a relocation instruction set and turn relocations |
|||
into pointers to the correct structure on input - but it would be |
|||
possible to create each howto field on demand. |
|||
@end table |
|||
*/ |
|||
|
|||
|
|||
/*proto* reloc_howto_type
|
|||
The @code{reloc_howto_type} is a structure which contains all the |
|||
information that bfd needs to know to tie up a back end's data. |
|||
|
|||
*+++ |
|||
|
|||
$typedef CONST struct reloc_howto_struct |
|||
${ |
|||
The type field has mainly a documetary use - the back end can to what |
|||
it wants with it, though the normally the back end's external idea of |
|||
what a reloc number would be would be stored in this field. For |
|||
example, the a PC relative word relocation in a coff environment would |
|||
have the type 023 - because that's what the outside world calls a |
|||
R_PCRWORD reloc. |
|||
|
|||
$ unsigned int type; |
|||
|
|||
The value the final relocation is shifted right by. This drops |
|||
unwanted data from the relocation. |
|||
|
|||
$ unsigned int rightshift; |
|||
|
|||
The size of the item to be relocated - 0, is one byte, 1 is 2 bytes, 3 |
|||
is four bytes. |
|||
|
|||
$ unsigned int size; |
|||
|
|||
Now obsolete |
|||
|
|||
$ unsigned int bitsize; |
|||
|
|||
Notes that the relocation is relative to the location in the data |
|||
section of the addend. The relocation function will subtract from the |
|||
relocation value the address of the location being relocated. |
|||
|
|||
$ boolean pc_relative; |
|||
|
|||
Now obsolete |
|||
|
|||
$ unsigned int bitpos; |
|||
|
|||
Now obsolete |
|||
|
|||
$ boolean absolute; |
|||
|
|||
Causes the relocation routine to return an error if overflow is |
|||
detected when relocating. |
|||
|
|||
$ boolean complain_on_overflow; |
|||
|
|||
If this field is non null, then the supplied function is called rather |
|||
than the normal function. This allows really strange relocation |
|||
methods to be accomodated (eg, i960 callj instructions). |
|||
|
|||
$ bfd_reloc_status_enum_type (*special_function)(); |
|||
|
|||
The textual name of the relocation type. |
|||
|
|||
$ char *name; |
|||
|
|||
When performing a partial link, some formats must modify the |
|||
relocations rather than the data - this flag signals this. |
|||
|
|||
$ boolean partial_inplace; |
|||
|
|||
The src_mask is used to select what parts of the read in data are to |
|||
be used in the relocation sum. Eg, if this was an 8 bit bit of data |
|||
which we read and relocated, this would be 0x000000ff. When we have |
|||
relocs which have an addend, such as sun4 extended relocs, the value |
|||
in the offset part of a relocating field is garbage so we never use |
|||
it. In this case the mask would be 0x00000000. |
|||
|
|||
$ bfd_word src_mask; |
|||
The dst_mask is what parts of the instruction are replaced into the |
|||
instruction. In most cases src_mask == dst_mask, except in the above |
|||
special case, where dst_mask would be 0x000000ff, and src_mask would |
|||
be 0x00000000. |
|||
|
|||
$ bfd_word dst_mask; |
|||
|
|||
When some formats create PC relative instructions, they leave the |
|||
value of the pc of the place being relocated in the offset slot of the |
|||
instruction, so that a PC relative relocation can be made just by |
|||
adding in an ordinary offset (eg sun3 a.out). Some formats leave the |
|||
displacement part of an instruction empty (eg m88k bcs), this flag |
|||
signals the fact. |
|||
|
|||
$ boolean pcrel_offset; |
|||
$} reloc_howto_type; |
|||
*--- |
|||
|
|||
*/ |
|||
|
|||
/*proto* HOWTO
|
|||
The HOWTO define is horrible and will go away. |
|||
*+ |
|||
#define HOWTO(C, R,S,B, P, BI, ABS, O, SF, NAME, INPLACE, MASKSRC, MASKDST, PC) \ |
|||
{(unsigned)C,R,S,B, P, BI, ABS,O,SF,NAME,INPLACE,MASKSRC,MASKDST,PC} |
|||
*- |
|||
|
|||
*/ |
|||
|
|||
/*proto* reloc_chain
|
|||
*+ |
|||
typedef unsigned char bfd_byte; |
|||
|
|||
typedef struct relent_chain { |
|||
arelent relent; |
|||
struct relent_chain *next; |
|||
} arelent_chain; |
|||
|
|||
*- |
|||
|
|||
*/ |
|||
|
|||
|
|||
|
|||
/*proto*
|
|||
If an output_bfd is supplied to this function the generated image |
|||
will be relocatable, the relocations are copied to the output file |
|||
after they have been changed to reflect the new state of the world. |
|||
There are two ways of reflecting the results of partial linkage in an |
|||
output file; by modifying the output data in place, and by modifying |
|||
the relocation record. Some native formats (eg basic a.out and basic |
|||
coff) have no way of specifying an addend in the relocation type, so |
|||
the addend has to go in the output data. This is no big deal since in |
|||
these formats the output data slot will always be big enough for the |
|||
addend. Complex reloc types with addends were invented to solve just |
|||
this problem. |
|||
*; PROTO(bfd_reloc_status_enum_type, |
|||
bfd_perform_relocation, |
|||
(bfd * abfd, |
|||
arelent *reloc_entry, |
|||
PTR data, |
|||
asection *input_section, |
|||
bfd *output_bfd)); |
|||
*/ |
|||
|
|||
|
|||
bfd_reloc_status_enum_type |
|||
DEFUN(bfd_perform_relocation,(abfd, |
|||
reloc_entry, |
|||
data, |
|||
input_section, |
|||
output_bfd), |
|||
bfd *abfd AND |
|||
arelent *reloc_entry AND |
|||
PTR data AND |
|||
asection *input_section AND |
|||
bfd *output_bfd) |
|||
{ |
|||
bfd_vma relocation; |
|||
bfd_reloc_status_enum_type flag = bfd_reloc_ok; |
|||
bfd_vma addr = reloc_entry->address ; |
|||
bfd_vma output_base = 0; |
|||
reloc_howto_type *howto = reloc_entry->howto; |
|||
asection *reloc_target_output_section; |
|||
asection *reloc_target_input_section; |
|||
asymbol *symbol; |
|||
|
|||
if (reloc_entry->sym_ptr_ptr) { |
|||
symbol = *( reloc_entry->sym_ptr_ptr); |
|||
if ((symbol->flags & BSF_UNDEFINED) && output_bfd == (bfd *)NULL) { |
|||
flag = bfd_reloc_undefined; |
|||
} |
|||
} |
|||
else { |
|||
symbol = (asymbol*)NULL; |
|||
} |
|||
|
|||
if (howto->special_function){ |
|||
bfd_reloc_status_enum_type cont; |
|||
cont = howto->special_function(abfd, |
|||
reloc_entry, |
|||
symbol, |
|||
data, |
|||
input_section); |
|||
if (cont != bfd_reloc_continue) return cont; |
|||
} |
|||
|
|||
/*
|
|||
Work out which section the relocation is targetted at and the |
|||
initial relocation command value. |
|||
*/ |
|||
|
|||
|
|||
if (symbol != (asymbol *)NULL){ |
|||
if (symbol->flags & BSF_FORT_COMM) { |
|||
relocation = 0; |
|||
} |
|||
else { |
|||
relocation = symbol->value; |
|||
} |
|||
if (symbol->section != (asection *)NULL) |
|||
{ |
|||
reloc_target_input_section = symbol->section; |
|||
} |
|||
else { |
|||
reloc_target_input_section = (asection *)NULL; |
|||
} |
|||
} |
|||
else if (reloc_entry->section != (asection *)NULL) |
|||
{ |
|||
relocation = 0; |
|||
reloc_target_input_section = reloc_entry->section; |
|||
} |
|||
else { |
|||
relocation = 0; |
|||
reloc_target_input_section = (asection *)NULL; |
|||
} |
|||
|
|||
|
|||
if (reloc_target_input_section != (asection *)NULL) { |
|||
|
|||
reloc_target_output_section = |
|||
reloc_target_input_section->output_section; |
|||
|
|||
if (output_bfd && howto->partial_inplace==false) { |
|||
output_base = 0; |
|||
} |
|||
else { |
|||
output_base = reloc_target_output_section->vma; |
|||
|
|||
} |
|||
|
|||
relocation += output_base + reloc_target_input_section->output_offset; |
|||
} |
|||
|
|||
relocation += reloc_entry->addend ; |
|||
|
|||
|
|||
if(reloc_entry->address > (bfd_vma)(input_section->size)) |
|||
{ |
|||
return bfd_reloc_outofrange; |
|||
} |
|||
|
|||
|
|||
if (howto->pc_relative == true) |
|||
{ |
|||
/*
|
|||
Anything which started out as pc relative should end up that |
|||
way too. |
|||
|
|||
There are two ways we can see a pcrel instruction. Sometimes |
|||
the pcrel displacement has been partially calculated, it |
|||
includes the distance from the start of the section to the |
|||
instruction in it (eg sun3), and sometimes the field is |
|||
totally blank - eg m88kbcs. |
|||
*/ |
|||
|
|||
|
|||
relocation -= |
|||
output_base + input_section->output_offset; |
|||
|
|||
if (howto->pcrel_offset == true) { |
|||
relocation -= reloc_entry->address; |
|||
} |
|||
|
|||
} |
|||
|
|||
if (output_bfd!= (bfd *)NULL) { |
|||
if ( howto->partial_inplace == false) { |
|||
/*
|
|||
This is a partial relocation, and we want to apply the relocation |
|||
to the reloc entry rather than the raw data. Modify the reloc |
|||
inplace to reflect what we now know. |
|||
*/ |
|||
reloc_entry->addend = relocation ; |
|||
reloc_entry->section = reloc_target_input_section; |
|||
if (reloc_target_input_section != (asection *)NULL) { |
|||
/* If we know the output section we can forget the symbol */ |
|||
reloc_entry->sym_ptr_ptr = (asymbol**)NULL; |
|||
} |
|||
reloc_entry->address += |
|||
input_section->output_offset; |
|||
return flag; |
|||
} |
|||
else |
|||
{ |
|||
/* This is a partial relocation, but inplace, so modify the
|
|||
reloc record a bit |
|||
*/ |
|||
|
|||
} |
|||
} |
|||
|
|||
reloc_entry->addend = 0; |
|||
|
|||
|
|||
/*
|
|||
Either we are relocating all the way, or we don't want to apply |
|||
the relocation to the reloc entry (probably because there isn't |
|||
any room in the output format to describe addends to relocs) |
|||
*/ |
|||
relocation >>= howto->rightshift; |
|||
|
|||
/* Shift everything up to where it's going to be used */ |
|||
|
|||
relocation <<= howto->bitpos; |
|||
|
|||
/* Wait for the day when all have the mask in them */ |
|||
|
|||
/* What we do:
|
|||
i instruction to be left alone |
|||
o offset within instruction |
|||
r relocation offset to apply |
|||
S src mask |
|||
D dst mask |
|||
N ~dst mask |
|||
A part 1 |
|||
B part 2 |
|||
R result |
|||
|
|||
Do this: |
|||
i i i i i o o o o o from bfd_get<size> |
|||
and S S S S S to get the size offset we want |
|||
+ r r r r r r r r r r to get the final value to place |
|||
and D D D D D to chop to right size |
|||
----------------------- |
|||
A A A A A |
|||
And this: |
|||
... i i i i i o o o o o from bfd_get<size> |
|||
and N N N N N get instruction |
|||
----------------------- |
|||
... B B B B B |
|||
|
|||
And then: |
|||
B B B B B |
|||
or A A A A A |
|||
----------------------- |
|||
R R R R R R R R R R put into bfd_put<size> |
|||
*/ |
|||
|
|||
#define DOIT(x) \ |
|||
x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) |
|||
|
|||
switch (howto->size) |
|||
{ |
|||
case 0: |
|||
{ |
|||
char x = bfd_get_8(abfd, (char *)data + addr); |
|||
DOIT(x); |
|||
bfd_put_8(abfd,x, (unsigned char *) data + addr); |
|||
} |
|||
break; |
|||
|
|||
case 1: |
|||
{ |
|||
short x = bfd_get_16(abfd, (bfd_byte *)data + addr); |
|||
DOIT(x); |
|||
bfd_put_16(abfd, x, (unsigned char *)data + addr); |
|||
} |
|||
break; |
|||
case 2: |
|||
{ |
|||
long x = bfd_get_32(abfd, (bfd_byte *) data + addr); |
|||
DOIT(x); |
|||
bfd_put_32(abfd,x, (bfd_byte *)data + addr); |
|||
} |
|||
break; |
|||
case 3: |
|||
/* Do nothing */ |
|||
break; |
|||
default: |
|||
return bfd_reloc_other; |
|||
} |
|||
|
|||
return flag; |
|||
} |
|||
@ -0,0 +1,553 @@ |
|||
/*doc*
|
|||
@section Sections |
|||
Sections are supported in bfd in @code{section.c}. |
|||
|
|||
The raw data contained within a bfd is maintained through the section |
|||
abstraction. A single bfd may have any number of sections, and keeps |
|||
hold of them by pointing to the first, each one points to the next in |
|||
the list. |
|||
|
|||
@menu |
|||
* Section Input:: |
|||
* Section Output:: |
|||
* typedef asection:: |
|||
* section prototypes:: |
|||
@end menu |
|||
|
|||
@node Section Input, Section Output,,Sections |
|||
@comment node-name, next, previous, up |
|||
@subsection Section Input |
|||
When a bfd is opened for reading, the section structures are created |
|||
and attatched to the bfd. |
|||
|
|||
Each section has a name which describes the section in the outside |
|||
world - for example, @code{a.out} would contain at least three |
|||
sections, called @code{.text}, @code{.data} and @code{.bss}. |
|||
|
|||
Sometimes a bfd will contain more than the 'natural' number of |
|||
sections. A back end may attatch other sections containing constructor |
|||
data, or an application may add a section (using bfd_make_section) to |
|||
the sections attatched to an already open bfd. For example, the linker |
|||
creates a supernumary section @code{COMMON} for each input file's bfd |
|||
to hold information about common storage. |
|||
|
|||
The raw data is not necessarily read in at the same time as the |
|||
section descriptor is created. Some targets may leave the data in |
|||
place until a @code{bfd_get_section_contents} call is made. Other back |
|||
ends may read in all the data at once - For example; an S-record file |
|||
has to be read once to determine the size of the data. An IEEE-695 |
|||
file doesn't contain raw data in sections, but data and relocation |
|||
expressions intermixed, so the data area has to be parsed to get out |
|||
the data and relocations. |
|||
|
|||
@node Section Output,typedef asection,Section Input,Sections |
|||
@subsection Section Output |
|||
To write a new object style bfd, the various sections to be written |
|||
have to be created. They are attatched to the bfd in the same way as |
|||
input sections, data is written to the sections using |
|||
@code{bfd_set_section_contents}. |
|||
|
|||
The linker uses the fields @code{output_section} and |
|||
@code{output_offset} to create an output file. |
|||
|
|||
The data to be written comes from input sections attatched to the |
|||
output sections. The output section structure can be considered a |
|||
filter for the input section, the output section determines the vma of |
|||
the output data and the name, but the input section determines the |
|||
offset into the output section of the data to be written. |
|||
|
|||
Eg to create a section "O", starting at 0x100, 0x123 long, containing two |
|||
subsections, "A" at offset 0x0 (ie at vma 0x100) and "B" at offset |
|||
0x20 (ie at vma 0x120) the structures would look like: |
|||
|
|||
*+ |
|||
|
|||
section name "A" |
|||
output_offset 0x00 |
|||
size 0x20 |
|||
output_section -----------> section name "O" |
|||
| vma 0x100 |
|||
section name "B" | size 0x123 |
|||
output_offset 0x20 | |
|||
size 0x103 | |
|||
output_section --------| |
|||
|
|||
*- |
|||
|
|||
*/ |
|||
|
|||
|
|||
#include "sysdep.h" |
|||
#include "bfd.h" |
|||
#include "libbfd.h" |
|||
|
|||
|
|||
/*doc*
|
|||
@node typedef asection,section prototypes,Section Output,Sections |
|||
@subsection typedef asection |
|||
*/ |
|||
|
|||
/*proto*
|
|||
The shape of a section struct: |
|||
|
|||
*+++ |
|||
|
|||
$typedef struct sec { |
|||
|
|||
The name of the section, the name isn't a copy, the pointer is |
|||
the same as that passed to bfd_make_section. |
|||
|
|||
$ CONST char *name; |
|||
|
|||
The next section in the list belonging to the bfd, or NULL. |
|||
|
|||
$ struct sec *next; |
|||
|
|||
The field flags contains attributes of the section. Some of these |
|||
flags are read in from the object file, and some are synthesized from |
|||
other information. |
|||
|
|||
$flagword flags; |
|||
|
|||
|
|||
$#define SEC_NO_FLAGS 0x000 |
|||
|
|||
Tells the OS to allocate space for this section when loaded. |
|||
This would clear for a section containing debug information only. |
|||
|
|||
$#define SEC_ALLOC 0x001 |
|||
|
|||
Tells the OS to load the section from the file when loading. |
|||
This would be clear for a .bss section |
|||
|
|||
$#define SEC_LOAD 0x002 |
|||
|
|||
The section contains data still to be relocated, so there will be some |
|||
relocation information too. |
|||
|
|||
$#define SEC_RELOC 0x004 |
|||
|
|||
Obsolete ? |
|||
|
|||
$#define SEC_BALIGN 0x008 |
|||
|
|||
A signal to the OS that the section contains read only data. |
|||
|
|||
$#define SEC_READONLY 0x010 |
|||
|
|||
The section contains code only. |
|||
|
|||
$#define SEC_CODE 0x020 |
|||
|
|||
The section contains data only. |
|||
|
|||
$#define SEC_DATA 0x040 |
|||
|
|||
The section will reside in ROM. |
|||
|
|||
$#define SEC_ROM 0x080 |
|||
|
|||
The section contains constructor information. This section type is |
|||
used by the linker to create lists of constructors and destructors |
|||
used by @code{g++}. When a back end sees a symbol which should be used |
|||
in a constructor list, it creates a new section for the type of name |
|||
(eg @code{__CTOR_LIST__}), attatches the symbol to it and builds a |
|||
relocation. To build the lists of constructors, all the linker has to |
|||
to is catenate all the sections called @code{__CTOR_LIST__} and |
|||
relocte the data contained within - exactly the operations it would |
|||
peform on standard data. |
|||
|
|||
$#define SEC_CONSTRUCTOR 0x100 |
|||
|
|||
The section has contents - a bss section could be |
|||
@code{SEC_ALLOC} | @code{SEC_HAS_CONTENTS}, a debug section could be |
|||
@code{SEC_HAS_CONTENTS} |
|||
|
|||
$#define SEC_HAS_CONTENTS 0x200 |
|||
|
|||
An instruction to the linker not to output sections containing |
|||
this flag even if they have information which would normally be written. |
|||
|
|||
$#define SEC_NEVER_LOAD 0x400 |
|||
|
|||
The base address of the section in the address space of the target. |
|||
|
|||
$ bfd_vma vma; |
|||
|
|||
The size of the section in bytes of the loaded section. This contains |
|||
a value even if the section has no contents (eg, the size of @code{.bss}). |
|||
|
|||
$ bfd_size_type size; |
|||
|
|||
If this section is going to be output, then this value is the |
|||
offset into the output section of the first byte in the input |
|||
section. Eg, if this was going to start at the 100th byte in the |
|||
output section, this value would be 100. |
|||
|
|||
$ bfd_vma output_offset; |
|||
|
|||
The output section through which to map on output. |
|||
|
|||
$ struct sec *output_section; |
|||
|
|||
The alignment requirement of the section, as an exponent - eg 3 |
|||
aligns to 2^3 (or 8) |
|||
|
|||
$ unsigned int alignment_power; |
|||
|
|||
If an input section, a pointer to a vector of relocation records for |
|||
the data in this section. |
|||
|
|||
$ struct reloc_cache_entry *relocation; |
|||
|
|||
If an output section, a pointer to a vector of pointers to |
|||
relocation records for the data in this section. |
|||
|
|||
$ struct reloc_cache_entry **orelocation; |
|||
|
|||
The number of relocation records in one of the above |
|||
|
|||
$ unsigned reloc_count; |
|||
|
|||
Which section is it 0..nth |
|||
|
|||
$ int index; |
|||
|
|||
Information below is back end specific - and not always used or |
|||
updated |
|||
|
|||
File position of section data |
|||
|
|||
$ file_ptr filepos; |
|||
File position of relocation info |
|||
|
|||
$ file_ptr rel_filepos; |
|||
|
|||
File position of line data |
|||
|
|||
$ file_ptr line_filepos; |
|||
|
|||
Pointer to data for applications |
|||
|
|||
$ PTR userdata; |
|||
|
|||
$ struct lang_output_section *otheruserdata; |
|||
|
|||
Attached line number information |
|||
|
|||
$ alent *lineno; |
|||
Number of line number records |
|||
|
|||
$ unsigned int lineno_count; |
|||
|
|||
When a section is being output, this value changes as more |
|||
linenumbers are written out |
|||
|
|||
$ file_ptr moving_line_filepos; |
|||
|
|||
what the section number is in the target world |
|||
|
|||
$ unsigned int target_index; |
|||
|
|||
$ PTR used_by_bfd; |
|||
|
|||
If this is a constructor section then here is a list of the |
|||
relocations created to relocate items within it. |
|||
|
|||
$ struct relent_chain *constructor_chain; |
|||
|
|||
The bfd which owns the section. |
|||
|
|||
$ bfd *owner; |
|||
|
|||
$} asection ; |
|||
|
|||
*--- |
|||
|
|||
*/ |
|||
|
|||
/*doc*
|
|||
@node section prototypes,Section,typedef section,Sections |
|||
@subsection section prototypes |
|||
|
|||
*/ |
|||
/*proto* bfd_get_section_by_name
|
|||
Runs through the provided @var{abfd} and returns the @code{asection} |
|||
who's name matches that provided, otherwise NULL. @xref{Sections}, for more information. |
|||
|
|||
*; PROTO(asection *, bfd_get_section_by_name, |
|||
(bfd *abfd, CONST char *name)); |
|||
*/ |
|||
asection * |
|||
DEFUN(bfd_get_section_by_name,(abfd, name), |
|||
bfd *abfd AND |
|||
CONST char *name) |
|||
{ |
|||
asection *sect; |
|||
|
|||
for (sect = abfd->sections; sect != NULL; sect = sect->next) |
|||
if (!strcmp (sect->name, name)) return sect; |
|||
return NULL; |
|||
} |
|||
|
|||
|
|||
/*proto* bfd_make_section
|
|||
This function creates a new empty section called @var{name} and attatches it |
|||
to the end of the chain of sections for @var{bfd}. An attempt to |
|||
create a section with a name which is already in use, returns the old |
|||
section by that name instead. |
|||
|
|||
Possible errors are: |
|||
@table @code |
|||
@item invalid_operation |
|||
If output has already started for this bfd. |
|||
@item no_memory |
|||
If obstack alloc fails. |
|||
@end table |
|||
|
|||
*; PROTO(asection *, bfd_make_section, (bfd *, CONST char *name)); |
|||
*/ |
|||
|
|||
|
|||
|
|||
sec_ptr |
|||
DEFUN(bfd_make_section,(abfd, name), |
|||
bfd *abfd AND |
|||
CONST char * name) |
|||
{ |
|||
asection *newsect; |
|||
asection ** prev = &abfd->sections; |
|||
asection * sect = abfd->sections; |
|||
|
|||
if (abfd->output_has_begun) { |
|||
bfd_error = invalid_operation; |
|||
return NULL; |
|||
} |
|||
|
|||
while (sect) { |
|||
if (!strcmp(sect->name, name)) return sect; |
|||
prev = §->next; |
|||
sect = sect->next; |
|||
} |
|||
|
|||
newsect = (asection *) bfd_zalloc(abfd, sizeof (asection)); |
|||
if (newsect == NULL) { |
|||
bfd_error = no_memory; |
|||
return NULL; |
|||
} |
|||
|
|||
newsect->name = name; |
|||
newsect->index = abfd->section_count++; |
|||
newsect->flags = SEC_NO_FLAGS; |
|||
|
|||
newsect->userdata = 0; |
|||
newsect->next = (asection *)NULL; |
|||
newsect->relocation = (arelent *)NULL; |
|||
newsect->reloc_count = 0; |
|||
newsect->line_filepos =0; |
|||
newsect->owner = abfd; |
|||
if (BFD_SEND (abfd, _new_section_hook, (abfd, newsect)) != true) { |
|||
free (newsect); |
|||
return NULL; |
|||
} |
|||
|
|||
*prev = newsect; |
|||
return newsect; |
|||
} |
|||
|
|||
|
|||
/*proto* bfd_set_section_flags
|
|||
Attempts to set the attributes of the section named in the bfd |
|||
supplied to the value. Returns true on success, false on error. |
|||
Possible error returns are: |
|||
@table @code |
|||
@item invalid operation |
|||
The section cannot have one or more of the attributes requested. For |
|||
example, a .bss section in @code{a.out} may not have the |
|||
@code{SEC_HAS_CONTENTS} field set. |
|||
@end table |
|||
|
|||
*; PROTO(boolean, bfd_set_section_flags, |
|||
(bfd *, asection *, flagword)); |
|||
*/ |
|||
|
|||
boolean |
|||
DEFUN(bfd_set_section_flags,(abfd, section, flags), |
|||
bfd *abfd AND |
|||
sec_ptr section AND |
|||
flagword flags) |
|||
{ |
|||
if ((flags & bfd_applicable_section_flags (abfd)) != flags) { |
|||
bfd_error = invalid_operation; |
|||
return false; |
|||
} |
|||
|
|||
section->flags = flags; |
|||
return true; |
|||
} |
|||
|
|||
|
|||
/*proto* bfd_map_over_sections
|
|||
Calls the provided function @var{func} for each section attatched to |
|||
the bfd @var{abfd}, passing @var{obj} as an argument. The function |
|||
will be called as if by |
|||
|
|||
@example |
|||
func(abfd, the_section, obj); |
|||
@end example |
|||
|
|||
|
|||
*; PROTO(void, bfd_map_over_sections, |
|||
(bfd *abfd, void (*func)(), PTR obj)); |
|||
|
|||
This is the prefered method for iterating over sections, an |
|||
alternative would be to use a loop: |
|||
|
|||
@example |
|||
section *p; |
|||
for (p = abfd->sections; p != NULL; p = p->next) |
|||
func(abfd, p, ...) |
|||
@end example |
|||
*/ |
|||
|
|||
/*VARARGS2*/ |
|||
void |
|||
DEFUN(bfd_map_over_sections,(abfd, operation, user_storage), |
|||
bfd *abfd AND |
|||
void (*operation)() AND |
|||
PTR user_storage) |
|||
{ |
|||
asection *sect; |
|||
int i = 0; |
|||
|
|||
for (sect = abfd->sections; sect != NULL; i++, sect = sect->next) |
|||
(*operation) (abfd, sect, user_storage); |
|||
|
|||
if (i != abfd->section_count) /* Debugging */ |
|||
abort(); |
|||
} |
|||
|
|||
|
|||
/*proto* bfd_set_section_size
|
|||
Sets @var{section} to the size @var{val}. If the operation is ok, then |
|||
@code{true} is returned, else @code{false}. |
|||
|
|||
Possible error returns: |
|||
@table @code |
|||
@item invalid_operation |
|||
Writing has started to the bfd, so setting the size is invalid |
|||
@end table |
|||
|
|||
*; PROTO(boolean, bfd_set_section_size, |
|||
(bfd *, asection *, bfd_size_type val)); |
|||
*/ |
|||
|
|||
boolean |
|||
DEFUN(bfd_set_section_size,(abfd, ptr, val), |
|||
bfd *abfd AND |
|||
sec_ptr ptr AND |
|||
unsigned long val) |
|||
{ |
|||
/* Once you've started writing to any section you cannot create or change
|
|||
the size of any others. */ |
|||
|
|||
if (abfd->output_has_begun) { |
|||
bfd_error = invalid_operation; |
|||
return false; |
|||
} |
|||
|
|||
ptr->size = val; |
|||
|
|||
return true; |
|||
} |
|||
|
|||
/*proto* bfd_set_section_contents
|
|||
Sets the contents of the section @var{section} in bfd @var{abfd} to |
|||
the data starting in memory at @var{data}. The data is written to the |
|||
output section starting at offset @var{offset} for @var{count} bytes. |
|||
|
|||
Normally @code{true} is returned, else @code{false}. Possible error |
|||
returns are: |
|||
@table @code |
|||
@item no_contents |
|||
The output section does not have the @code{SEC_HAS_CONTENTS} |
|||
attribute, so nothing can be written to it. |
|||
@item and some more too |
|||
@end table |
|||
This routine is front end to the back end function @code{_bfd_set_section_contents}. |
|||
|
|||
*; PROTO(boolean, bfd_set_section_contents, |
|||
(bfd *abfd, |
|||
asection *section, |
|||
PTR data, |
|||
file_ptr offset, |
|||
bfd_size_type count)); |
|||
|
|||
*/ |
|||
|
|||
boolean |
|||
DEFUN(bfd_set_section_contents,(abfd, section, location, offset, count), |
|||
bfd *abfd AND |
|||
sec_ptr section AND |
|||
PTR location AND |
|||
file_ptr offset AND |
|||
bfd_size_type count) |
|||
{ |
|||
if (!(bfd_get_section_flags(abfd, section) & SEC_HAS_CONTENTS)) |
|||
{ |
|||
bfd_error = no_contents; |
|||
return(false); |
|||
} |
|||
|
|||
if (BFD_SEND (abfd, _bfd_set_section_contents, |
|||
(abfd, section, location, offset, count))) |
|||
{ |
|||
abfd->output_has_begun = true; |
|||
return true; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/*proto* bfd_get_section_contents
|
|||
This function reads data from @var{section} in bfd @var{abfd} into |
|||
memory starting at @var{location}. The data is read at an offset of |
|||
@var{offset} from the start of the input section, and is read for |
|||
@var{count} bytes. |
|||
|
|||
If the contents of a constuctor with the @code{SEC_CONSTUCTOR} flag |
|||
set are requested, then the @var{location} is filled with zeroes. |
|||
|
|||
If no errors occur, @code{true} is returned, else @code{false}. |
|||
Possible errors are: |
|||
|
|||
@table @code |
|||
@item unknown yet |
|||
@end table |
|||
|
|||
*; PROTO(boolean, bfd_get_section_contents, |
|||
(bfd *abfd, asection *section, PTR location, |
|||
file_ptr offset, bfd_size_type count)); |
|||
|
|||
|
|||
*/ |
|||
boolean |
|||
DEFUN(bfd_get_section_contents,(abfd, section, location, offset, count), |
|||
bfd *abfd AND |
|||
sec_ptr section AND |
|||
PTR location AND |
|||
file_ptr offset AND |
|||
bfd_size_type count) |
|||
{ |
|||
if (section->flags & SEC_CONSTRUCTOR) |
|||
{ |
|||
memset(location, 0, (unsigned)count); |
|||
return true; |
|||
} |
|||
else |
|||
{ |
|||
return (BFD_SEND (abfd, _bfd_get_section_contents, |
|||
(abfd, section, location, offset, count))); |
|||
} |
|||
} |
|||
|
|||
Loading…
Reference in new issue