Initial revision
This commit is contained in:
parent
bdf3621b9e
commit
985fca1293
65
bfd/core.c
Normal file
65
bfd/core.c
Normal file
@ -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));
|
||||
}
|
612
bfd/reloc.c
Normal file
612
bfd/reloc.c
Normal file
@ -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;
|
||||
}
|
553
bfd/section.c
Normal file
553
bfd/section.c
Normal file
@ -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
Block a user