Changes to support linker relaxing of embedded MIPS PIC code to
use a five instruction sequence for funtion calls which are out of range of the bal instruction. * libecoff.h (struct ecoff_section_tdata): Define. (ecoff_section_data): Define. (ecoff_bfd_relax_section): Don't define. * ecoff.c (ecoff_final_link_debug_accumulate): Don't read or free the debugging information if it has already been read. (ecoff_indirect_link_order): Handle _cooked_size being different from _raw_size. Don't reread the contents or the relocs if they have already been read in. * coff-mips.c (mips_howto_table): Change bitsize of PCREL16 from 18 to 16. (PCREL16_EXPANSION_ADJUSTMENT): Define. (mips_relocate_refhi): Take adjust argument. (mips_relocate_section): Handle reloc offsets stored in section used_by_bfd field. Call mips_relax_pcrel16 to handle details of expanding an out of range PCREL16. Keep trace of adjustments required by expansions. Set s and unset h when converting a reloc from undefined to section. Change handling of PC relative relocs: if against a section, they are correct in the object file, if against an external symbol they are pcrel_offset. (mips_relax_section): New function. (mips_relax_pcrel16): New function. (ecoff_bfd_relax_section): Define. * coff-alpha.c (ecoff_bfd_relax_section): Define. * ecofflink.c (bfd_ecoff_debug_accumulate): Handle adjustments built by mips_relax_section when writing out addresses. * elf32-mips.c (mips_elf_read_ecoff_info): Clear adjust field.
This commit is contained in:
parent
f078dc7cf2
commit
a3a33af390
7 changed files with 1247 additions and 220 deletions
|
@ -1,5 +1,35 @@
|
|||
Fri Mar 25 17:10:45 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com)
|
||||
|
||||
Changes to support linker relaxing of embedded MIPS PIC code to
|
||||
use a five instruction sequence for funtion calls which are out of
|
||||
range of the bal instruction.
|
||||
* libecoff.h (struct ecoff_section_tdata): Define.
|
||||
(ecoff_section_data): Define.
|
||||
(ecoff_bfd_relax_section): Don't define.
|
||||
* ecoff.c (ecoff_final_link_debug_accumulate): Don't read or free
|
||||
the debugging information if it has already been read.
|
||||
(ecoff_indirect_link_order): Handle _cooked_size being different
|
||||
from _raw_size. Don't reread the contents or the relocs if they
|
||||
have already been read in.
|
||||
* coff-mips.c (mips_howto_table): Change bitsize of PCREL16 from
|
||||
18 to 16.
|
||||
(PCREL16_EXPANSION_ADJUSTMENT): Define.
|
||||
(mips_relocate_refhi): Take adjust argument.
|
||||
(mips_relocate_section): Handle reloc offsets stored in section
|
||||
used_by_bfd field. Call mips_relax_pcrel16 to handle details of
|
||||
expanding an out of range PCREL16. Keep trace of adjustments
|
||||
required by expansions. Set s and unset h when converting a reloc
|
||||
from undefined to section. Change handling of PC relative relocs:
|
||||
if against a section, they are correct in the object file, if
|
||||
against an external symbol they are pcrel_offset.
|
||||
(mips_relax_section): New function.
|
||||
(mips_relax_pcrel16): New function.
|
||||
(ecoff_bfd_relax_section): Define.
|
||||
* coff-alpha.c (ecoff_bfd_relax_section): Define.
|
||||
* ecofflink.c (bfd_ecoff_debug_accumulate): Handle adjustments
|
||||
built by mips_relax_section when writing out addresses.
|
||||
* elf32-mips.c (mips_elf_read_ecoff_info): Clear adjust field.
|
||||
|
||||
* aoutx.h (NAME(aout,find_nearest_line)): The caller expects
|
||||
functionname_ptr to be set to a symbol name, so prepend
|
||||
symbol_leading_char.
|
||||
|
|
|
@ -715,16 +715,23 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order,
|
|||
bfd *input_bfd = link_order->u.indirect.section->owner;
|
||||
asection *input_section = link_order->u.indirect.section;
|
||||
size_t reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
|
||||
arelent **reloc_vector = (arelent **) alloca (reloc_size);
|
||||
arelent **reloc_vector = NULL;
|
||||
bfd *output_bfd = relocateable ? abfd : (bfd *) NULL;
|
||||
bfd_vma gp;
|
||||
boolean gp_undefined;
|
||||
bfd_vma stack[RELOC_STACKSIZE];
|
||||
int tos = 0;
|
||||
|
||||
reloc_vector = (arelent **) malloc (reloc_size);
|
||||
if (reloc_vector == NULL && reloc_size != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (! bfd_get_section_contents (input_bfd, input_section, data,
|
||||
(file_ptr) 0, input_section->_raw_size))
|
||||
return NULL;
|
||||
goto error_return;
|
||||
|
||||
/* The section size is not going to change. */
|
||||
input_section->_cooked_size = input_section->_raw_size;
|
||||
|
@ -733,7 +740,7 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order,
|
|||
if (bfd_canonicalize_reloc (input_bfd, input_section, reloc_vector,
|
||||
symbols)
|
||||
== 0)
|
||||
return data;
|
||||
goto successful_return;
|
||||
|
||||
/* Get the GP value for the output BFD. */
|
||||
gp_undefined = false;
|
||||
|
@ -1080,20 +1087,20 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order,
|
|||
if (! ((*link_info->callbacks->undefined_symbol)
|
||||
(link_info, bfd_asymbol_name (*rel->sym_ptr_ptr),
|
||||
input_bfd, input_section, rel->address)))
|
||||
return NULL;
|
||||
goto error_return;
|
||||
break;
|
||||
case bfd_reloc_dangerous:
|
||||
if (! ((*link_info->callbacks->reloc_dangerous)
|
||||
(link_info, err, input_bfd, input_section,
|
||||
rel->address)))
|
||||
return NULL;
|
||||
goto error_return;
|
||||
break;
|
||||
case bfd_reloc_overflow:
|
||||
if (! ((*link_info->callbacks->reloc_overflow)
|
||||
(link_info, bfd_asymbol_name (*rel->sym_ptr_ptr),
|
||||
rel->howto->name, rel->addend, input_bfd,
|
||||
input_section, rel->address)))
|
||||
return NULL;
|
||||
goto error_return;
|
||||
break;
|
||||
case bfd_reloc_outofrange:
|
||||
default:
|
||||
|
@ -1106,7 +1113,15 @@ alpha_ecoff_get_relocated_section_contents (abfd, link_info, link_order,
|
|||
if (tos != 0)
|
||||
abort ();
|
||||
|
||||
successful_return:
|
||||
if (reloc_vector != NULL)
|
||||
free (reloc_vector);
|
||||
return data;
|
||||
|
||||
error_return:
|
||||
if (reloc_vector != NULL)
|
||||
free (reloc_vector);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Get the howto structure for a generic reloc type. */
|
||||
|
@ -1124,6 +1139,7 @@ alpha_bfd_reloc_type_lookup (abfd, code)
|
|||
alpha_type = ALPHA_R_REFLONG;
|
||||
break;
|
||||
case BFD_RELOC_64:
|
||||
case BFD_RELOC_CTOR:
|
||||
alpha_type = ALPHA_R_REFQUAD;
|
||||
break;
|
||||
case BFD_RELOC_GPREL32:
|
||||
|
@ -1658,17 +1674,26 @@ alpha_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
adjust the address of the reloc. */
|
||||
if (! info->relocateable)
|
||||
{
|
||||
bfd_vma mask;
|
||||
bfd_vma val;
|
||||
|
||||
if (tos == 0)
|
||||
abort ();
|
||||
|
||||
/* Get the relocation mask. The separate steps and the
|
||||
casts to bfd_vma are attempts to avoid a bug in the
|
||||
Alpha OSF 1.3 C compiler. See reloc.c for more
|
||||
details. */
|
||||
mask = 1;
|
||||
mask <<= (bfd_vma) r_size;
|
||||
mask -= 1;
|
||||
|
||||
/* FIXME: I don't know what kind of overflow checking,
|
||||
if any, should be done here. */
|
||||
val = bfd_get_64 (input_bfd,
|
||||
contents + r_vaddr - input_section->vma);
|
||||
val &=~ (((1 << r_size) - 1) << r_offset);
|
||||
val |= (stack[--tos] & ((1 << r_size) - 1)) << r_offset;
|
||||
val &=~ mask << (bfd_vma) r_offset;
|
||||
val |= (stack[--tos] & mask) << (bfd_vma) r_offset;
|
||||
bfd_put_64 (input_bfd, val,
|
||||
contents + r_vaddr - input_section->vma);
|
||||
}
|
||||
|
@ -1961,6 +1986,9 @@ static const struct ecoff_backend_data alpha_ecoff_backend_data =
|
|||
#define ecoff_bfd_get_relocated_section_contents \
|
||||
alpha_ecoff_get_relocated_section_contents
|
||||
|
||||
/* Relaxing sections is generic. */
|
||||
#define ecoff_bfd_relax_section bfd_generic_relax_section
|
||||
|
||||
bfd_target ecoffalpha_little_vec =
|
||||
{
|
||||
"ecoff-littlealpha", /* name */
|
||||
|
|
558
bfd/coff-mips.c
558
bfd/coff-mips.c
|
@ -77,10 +77,18 @@ static void mips_relocate_refhi PARAMS ((struct internal_reloc *refhi,
|
|||
bfd *input_bfd,
|
||||
asection *input_section,
|
||||
bfd_byte *contents,
|
||||
size_t adjust,
|
||||
bfd_vma relocation));
|
||||
static boolean mips_relocate_section PARAMS ((bfd *, struct bfd_link_info *,
|
||||
bfd *, asection *,
|
||||
bfd_byte *, PTR));
|
||||
static boolean mips_relax_section PARAMS ((bfd *, asection *,
|
||||
struct bfd_link_info *,
|
||||
boolean *));
|
||||
static boolean mips_relax_pcrel16 PARAMS ((struct bfd_link_info *, bfd *,
|
||||
asection *,
|
||||
struct ecoff_link_hash_entry *,
|
||||
bfd_byte *, bfd_vma));
|
||||
|
||||
/* ECOFF has COFF sections, but the debugging information is stored in
|
||||
a completely different format. ECOFF targets use some of the
|
||||
|
@ -236,11 +244,45 @@ static reloc_howto_type mips_howto_table[] =
|
|||
true, /* partial_inplace */
|
||||
0xffff, /* src_mask */
|
||||
0xffff, /* dst_mask */
|
||||
false) /* pcrel_offset */
|
||||
false), /* pcrel_offset */
|
||||
|
||||
/* This reloc is a Cygnus extension used when generating position
|
||||
independent code for embedded systems. It represents a 16 bit PC
|
||||
relative reloc rightshifted twice as used in the MIPS branch
|
||||
instructions. */
|
||||
HOWTO (MIPS_R_PCREL16, /* type */
|
||||
2, /* rightshift */
|
||||
2, /* size (0 = byte, 1 = short, 2 = long) */
|
||||
16, /* bitsize */
|
||||
true, /* pc_relative */
|
||||
0, /* bitpos */
|
||||
complain_overflow_signed, /* complain_on_overflow */
|
||||
mips_generic_reloc, /* special_function */
|
||||
"PCREL16", /* name */
|
||||
true, /* partial_inplace */
|
||||
0xffff, /* src_mask */
|
||||
0xffff, /* dst_mask */
|
||||
true) /* pcrel_offset */
|
||||
};
|
||||
|
||||
#define MIPS_HOWTO_COUNT \
|
||||
(sizeof mips_howto_table / sizeof mips_howto_table[0])
|
||||
|
||||
/* When the linker is doing relaxing, it may change a external PCREL16
|
||||
reloc. This typically represents an instruction like
|
||||
bal foo
|
||||
We change it to
|
||||
.set noreorder
|
||||
bal $L1
|
||||
lui $at,%hi(foo - $L1)
|
||||
$L1:
|
||||
addiu $at,%lo(foo - $L1)
|
||||
addu $at,$at,$31
|
||||
jalr $at
|
||||
PCREL16_EXPANSION_ADJUSTMENT is the number of bytes this changes the
|
||||
instruction by. */
|
||||
|
||||
#define PCREL16_EXPANSION_ADJUSTMENT (4 * 4)
|
||||
|
||||
/* See whether the magic number matches. */
|
||||
|
||||
|
@ -357,7 +399,7 @@ mips_adjust_reloc_in (abfd, intern, rptr)
|
|||
const struct internal_reloc *intern;
|
||||
arelent *rptr;
|
||||
{
|
||||
if (intern->r_type > MIPS_R_LITERAL)
|
||||
if (intern->r_type > MIPS_R_PCREL16)
|
||||
abort ();
|
||||
|
||||
if (! intern->r_extern
|
||||
|
@ -715,6 +757,9 @@ mips_bfd_reloc_type_lookup (abfd, code)
|
|||
case BFD_RELOC_MIPS_LITERAL:
|
||||
mips_type = MIPS_R_LITERAL;
|
||||
break;
|
||||
case BFD_RELOC_16_PCREL_S2:
|
||||
mips_type = MIPS_R_PCREL16;
|
||||
break;
|
||||
default:
|
||||
return (CONST struct reloc_howto_struct *) NULL;
|
||||
}
|
||||
|
@ -729,12 +774,13 @@ mips_bfd_reloc_type_lookup (abfd, code)
|
|||
|
||||
static void
|
||||
mips_relocate_refhi (refhi, reflo, input_bfd, input_section, contents,
|
||||
relocation)
|
||||
adjust, relocation)
|
||||
struct internal_reloc *refhi;
|
||||
struct internal_reloc *reflo;
|
||||
bfd *input_bfd;
|
||||
asection *input_section;
|
||||
bfd_byte *contents;
|
||||
size_t adjust;
|
||||
bfd_vma relocation;
|
||||
{
|
||||
unsigned long insn;
|
||||
|
@ -742,9 +788,9 @@ mips_relocate_refhi (refhi, reflo, input_bfd, input_section, contents,
|
|||
unsigned long vallo;
|
||||
|
||||
insn = bfd_get_32 (input_bfd,
|
||||
contents + refhi->r_vaddr - input_section->vma);
|
||||
contents + adjust + refhi->r_vaddr - input_section->vma);
|
||||
vallo = (bfd_get_32 (input_bfd,
|
||||
contents + reflo->r_vaddr - input_section->vma)
|
||||
contents + adjust + reflo->r_vaddr - input_section->vma)
|
||||
& 0xffff);
|
||||
val = ((insn & 0xffff) << 16) + vallo;
|
||||
val += relocation;
|
||||
|
@ -761,7 +807,7 @@ mips_relocate_refhi (refhi, reflo, input_bfd, input_section, contents,
|
|||
|
||||
insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
|
||||
bfd_put_32 (input_bfd, (bfd_vma) insn,
|
||||
contents + refhi->r_vaddr - input_section->vma);
|
||||
contents + adjust + refhi->r_vaddr - input_section->vma);
|
||||
}
|
||||
|
||||
/* Relocate a section while linking a MIPS ECOFF file. */
|
||||
|
@ -780,9 +826,13 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
struct ecoff_link_hash_entry **sym_hashes;
|
||||
bfd_vma gp;
|
||||
boolean gp_undefined;
|
||||
size_t adjust;
|
||||
long *offsets;
|
||||
struct external_reloc *ext_rel;
|
||||
struct external_reloc *ext_rel_end;
|
||||
unsigned int i;
|
||||
boolean got_reflo;
|
||||
struct internal_reloc reflo_int_rel;
|
||||
|
||||
BFD_ASSERT (input_bfd->xvec->header_byteorder_big_p
|
||||
== output_bfd->xvec->header_byteorder_big_p);
|
||||
|
@ -842,12 +892,18 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
|
||||
got_reflo = false;
|
||||
|
||||
adjust = 0;
|
||||
|
||||
if (ecoff_section_data (input_bfd, input_section) == NULL)
|
||||
offsets = NULL;
|
||||
else
|
||||
offsets = ecoff_section_data (input_bfd, input_section)->offsets;
|
||||
|
||||
ext_rel = (struct external_reloc *) external_relocs;
|
||||
ext_rel_end = ext_rel + input_section->reloc_count;
|
||||
for (; ext_rel < ext_rel_end; ext_rel++)
|
||||
for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)
|
||||
{
|
||||
struct internal_reloc int_rel;
|
||||
struct internal_reloc reflo_int_rel;
|
||||
bfd_vma addend;
|
||||
reloc_howto_type *howto;
|
||||
struct ecoff_link_hash_entry *h = NULL;
|
||||
|
@ -955,6 +1011,54 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
}
|
||||
}
|
||||
|
||||
/* If we are relaxing, mips_relax_section may have set
|
||||
offsets[i] to some value. A value of 1 means we must expand
|
||||
a PC relative branch into a multi-instruction of sequence,
|
||||
and any other value is an addend. */
|
||||
if (offsets != NULL
|
||||
&& offsets[i] != 0)
|
||||
{
|
||||
BFD_ASSERT (! info->relocateable);
|
||||
BFD_ASSERT (int_rel.r_type == MIPS_R_PCREL16);
|
||||
if (offsets[i] != 1)
|
||||
{
|
||||
BFD_ASSERT (! int_rel.r_extern);
|
||||
addend += offsets[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
bfd_byte *here;
|
||||
|
||||
BFD_ASSERT (int_rel.r_extern);
|
||||
|
||||
/* Move the rest of the instructions up. */
|
||||
here = (contents
|
||||
+ adjust
|
||||
+ int_rel.r_vaddr
|
||||
- input_section->vma);
|
||||
memmove (here + PCREL16_EXPANSION_ADJUSTMENT, here,
|
||||
(input_section->_raw_size
|
||||
- (int_rel.r_vaddr - input_section->vma)));
|
||||
|
||||
/* Generate the new instructions. */
|
||||
if (! mips_relax_pcrel16 (info, input_bfd, input_section,
|
||||
h, here,
|
||||
(input_section->output_section->vma
|
||||
+ input_section->output_offset
|
||||
+ (int_rel.r_vaddr
|
||||
- input_section->vma)
|
||||
+ adjust)))
|
||||
return false;
|
||||
|
||||
/* We must adjust everything else up a notch. */
|
||||
adjust += PCREL16_EXPANSION_ADJUSTMENT;
|
||||
|
||||
/* mips_relax_pcrel16 handles all the details of this
|
||||
relocation. */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (info->relocateable)
|
||||
{
|
||||
/* We are generating relocateable output, and must convert
|
||||
|
@ -963,7 +1067,6 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
{
|
||||
if (h->root.type == bfd_link_hash_defined)
|
||||
{
|
||||
asection *hsec;
|
||||
const char *name;
|
||||
|
||||
/* This symbol is defined in the output. Convert
|
||||
|
@ -974,9 +1077,9 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
int_rel.r_extern = 0;
|
||||
|
||||
/* Compute a new r_symndx value. */
|
||||
hsec = h->root.u.def.section;
|
||||
s = h->root.u.def.section;
|
||||
name = bfd_get_section_name (output_bfd,
|
||||
hsec->output_section);
|
||||
s->output_section);
|
||||
|
||||
int_rel.r_symndx = -1;
|
||||
switch (name[1])
|
||||
|
@ -1024,8 +1127,16 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
|
||||
/* Add the section VMA and the symbol value. */
|
||||
relocation = (h->root.u.def.value
|
||||
+ hsec->output_section->vma
|
||||
+ hsec->output_offset);
|
||||
+ s->output_section->vma
|
||||
+ s->output_offset);
|
||||
|
||||
/* For a PC relative relocation, the object file
|
||||
currently holds just the addend. We must adjust
|
||||
by the address to get the right value. */
|
||||
if (howto->pc_relative)
|
||||
relocation -= int_rel.r_vaddr - input_section->vma;
|
||||
|
||||
h = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1056,6 +1167,14 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
|
||||
relocation += addend;
|
||||
|
||||
/* Adjust a PC relative relocation by removing the reference
|
||||
to the original address in the section and including the
|
||||
reference to the new address. */
|
||||
if (howto->pc_relative)
|
||||
relocation -= (input_section->output_section->vma
|
||||
+ input_section->output_offset
|
||||
- input_section->vma);
|
||||
|
||||
/* Adjust the contents. */
|
||||
if (relocation == 0)
|
||||
r = bfd_reloc_ok;
|
||||
|
@ -1064,13 +1183,14 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
if (int_rel.r_type != MIPS_R_REFHI)
|
||||
r = _bfd_relocate_contents (howto, input_bfd, relocation,
|
||||
(contents
|
||||
+ adjust
|
||||
+ int_rel.r_vaddr
|
||||
- input_section->vma));
|
||||
else
|
||||
{
|
||||
mips_relocate_refhi (&int_rel, &reflo_int_rel,
|
||||
input_bfd, input_section, contents,
|
||||
relocation);
|
||||
adjust, relocation);
|
||||
r = bfd_reloc_ok;
|
||||
}
|
||||
}
|
||||
|
@ -1115,10 +1235,11 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
+ s->output_offset
|
||||
- s->vma);
|
||||
|
||||
/* Adjust a PC relative relocation by removing the
|
||||
reference to the original source section. */
|
||||
/* A PC relative reloc is already correct in the object
|
||||
file. Make it look like a pcrel_offset relocation by
|
||||
adding in the start address. */
|
||||
if (howto->pc_relative)
|
||||
relocation += input_section->vma;
|
||||
relocation += int_rel.r_vaddr + adjust;
|
||||
}
|
||||
|
||||
if (int_rel.r_type != MIPS_R_REFHI)
|
||||
|
@ -1126,13 +1247,16 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
input_bfd,
|
||||
input_section,
|
||||
contents,
|
||||
int_rel.r_vaddr - input_section->vma,
|
||||
(int_rel.r_vaddr
|
||||
- input_section->vma
|
||||
+ adjust),
|
||||
relocation,
|
||||
addend);
|
||||
else
|
||||
{
|
||||
mips_relocate_refhi (&int_rel, &reflo_int_rel, input_bfd,
|
||||
input_section, contents, relocation);
|
||||
input_section, contents, adjust,
|
||||
relocation);
|
||||
r = bfd_reloc_ok;
|
||||
}
|
||||
}
|
||||
|
@ -1166,6 +1290,399 @@ mips_relocate_section (output_bfd, info, input_bfd, input_section,
|
|||
return true;
|
||||
}
|
||||
|
||||
/* Relax a section when linking a MIPS ECOFF file. This is used for
|
||||
embedded PIC code, which always uses PC relative branches which
|
||||
only have an 18 bit range on MIPS. If a branch is not in range, we
|
||||
generate a long instruction sequence to compensate. Each time we
|
||||
find a branch to expand, we have to check all the others again to
|
||||
make sure they are still in range. This is slow, but it only has
|
||||
to be done when -relax is passed to the linker.
|
||||
|
||||
This routine figures out which branches need to expand; the actual
|
||||
expansion is done in mips_relocate_section when the section
|
||||
contents are relocated. The information is stored in the offsets
|
||||
field of the ecoff_section_tdata structure. An offset of 1 means
|
||||
that the branch must be expanded into a multi-instruction PC
|
||||
relative branch (such an offset will only occur for a PC relative
|
||||
branch to an external symbol). Any other offset must be a multiple
|
||||
of four, and is the amount to change the branch by (such an offset
|
||||
will only occur for a PC relative branch within the same section).
|
||||
|
||||
We do not modify the section relocs or contents themselves so that
|
||||
if memory usage becomes an issue we can discard them and read them
|
||||
again. The only information we must save in memory between this
|
||||
routine and the mips_relocate_section routine is the table of
|
||||
offsets. */
|
||||
|
||||
static boolean
|
||||
mips_relax_section (abfd, sec, info, again)
|
||||
bfd *abfd;
|
||||
asection *sec;
|
||||
struct bfd_link_info *info;
|
||||
boolean *again;
|
||||
{
|
||||
struct ecoff_section_tdata *section_tdata;
|
||||
bfd_byte *contents = NULL;
|
||||
long *offsets;
|
||||
struct external_reloc *ext_rel;
|
||||
struct external_reloc *ext_rel_end;
|
||||
unsigned int i;
|
||||
|
||||
/* Assume we are not going to need another pass. */
|
||||
*again = false;
|
||||
|
||||
/* If we are not generating an ECOFF file, this is much too
|
||||
confusing to deal with. */
|
||||
if (info->hash->creator->flavour != bfd_get_flavour (abfd))
|
||||
return true;
|
||||
|
||||
/* If there are no relocs, there is nothing to do. */
|
||||
if (sec->reloc_count == 0)
|
||||
return true;
|
||||
|
||||
/* We are only interested in PC relative relocs, and why would there
|
||||
ever be one from anything but the .text section? */
|
||||
if (strcmp (bfd_get_section_name (abfd, sec), ".text") != 0)
|
||||
return true;
|
||||
|
||||
/* Read in the relocs, if we haven't already got them. */
|
||||
section_tdata = ecoff_section_data (abfd, sec);
|
||||
if (section_tdata == (struct ecoff_section_tdata *) NULL)
|
||||
{
|
||||
bfd_size_type external_reloc_size;
|
||||
bfd_size_type external_relocs_size;
|
||||
|
||||
sec->used_by_bfd =
|
||||
(PTR) bfd_alloc_by_size_t (abfd, sizeof (struct ecoff_section_tdata));
|
||||
if (sec->used_by_bfd == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
section_tdata = ecoff_section_data (abfd, sec);
|
||||
section_tdata->contents = NULL;
|
||||
section_tdata->offsets = NULL;
|
||||
|
||||
external_reloc_size = ecoff_backend (abfd)->external_reloc_size;
|
||||
external_relocs_size = external_reloc_size * sec->reloc_count;
|
||||
|
||||
section_tdata->external_relocs =
|
||||
(PTR) bfd_alloc (abfd, external_relocs_size);
|
||||
if (section_tdata->external_relocs == NULL && external_relocs_size != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0
|
||||
|| (bfd_read (section_tdata->external_relocs, 1,
|
||||
external_relocs_size, abfd)
|
||||
!= external_relocs_size))
|
||||
goto error_return;
|
||||
|
||||
/* We must initialize _cooked_size only the first time we are
|
||||
called. */
|
||||
sec->_cooked_size = sec->_raw_size;
|
||||
}
|
||||
|
||||
contents = section_tdata->contents;
|
||||
offsets = section_tdata->offsets;
|
||||
|
||||
/* Look for any external PC relative relocs. Internal PC relative
|
||||
relocs are already correct in the object file, so they certainly
|
||||
can not overflow. */
|
||||
ext_rel = (struct external_reloc *) section_tdata->external_relocs;
|
||||
ext_rel_end = ext_rel + sec->reloc_count;
|
||||
for (i = 0; ext_rel < ext_rel_end; ext_rel++, i++)
|
||||
{
|
||||
struct internal_reloc int_rel;
|
||||
struct ecoff_link_hash_entry *h;
|
||||
asection *hsec;
|
||||
bfd_signed_vma relocation;
|
||||
struct external_reloc *adj_ext_rel;
|
||||
unsigned int adj_i;
|
||||
unsigned long ext_count;
|
||||
struct ecoff_link_hash_entry **adj_h_ptr;
|
||||
struct ecoff_link_hash_entry **adj_h_ptr_end;
|
||||
struct ecoff_value_adjust *adjust;
|
||||
|
||||
/* If we have already expanded this reloc, we certainly don't
|
||||
need to do it again. */
|
||||
if (offsets != (long *) NULL && offsets[i] == 1)
|
||||
continue;
|
||||
|
||||
/* Quickly check that this reloc is external PCREL16. */
|
||||
if (abfd->xvec->header_byteorder_big_p)
|
||||
{
|
||||
if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_BIG) == 0
|
||||
|| (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_BIG)
|
||||
>> RELOC_BITS3_TYPE_SH_BIG)
|
||||
!= MIPS_R_PCREL16))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) == 0
|
||||
|| (((ext_rel->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
|
||||
>> RELOC_BITS3_TYPE_SH_LITTLE)
|
||||
!= MIPS_R_PCREL16))
|
||||
continue;
|
||||
}
|
||||
|
||||
mips_ecoff_swap_reloc_in (abfd, (PTR) ext_rel, &int_rel);
|
||||
|
||||
h = ecoff_data (abfd)->sym_hashes[int_rel.r_symndx];
|
||||
if (h == (struct ecoff_link_hash_entry *) NULL)
|
||||
abort ();
|
||||
|
||||
if (h->root.type != bfd_link_hash_defined)
|
||||
{
|
||||
/* Just ignore undefined symbols. These will presumably
|
||||
generate an error later in the link. */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the value of the symbol. */
|
||||
hsec = h->root.u.def.section;
|
||||
relocation = (h->root.u.def.value
|
||||
+ hsec->output_section->vma
|
||||
+ hsec->output_offset);
|
||||
|
||||
/* Subtract out the current address. */
|
||||
relocation -= (sec->output_section->vma
|
||||
+ sec->output_offset
|
||||
+ (int_rel.r_vaddr - sec->vma));
|
||||
|
||||
/* The addend is stored in the object file. In the normal case
|
||||
of ``bal symbol'', the addend will be -4. It will only be
|
||||
different in the case of ``bal symbol+constant''. To avoid
|
||||
always reading in the section contents, we don't check the
|
||||
addend in the object file (we could easily check the contents
|
||||
if we happen to have already read them in, but I fear that
|
||||
this could be confusing). This means we will screw up if
|
||||
there is a branch to a symbol that is in range, but added to
|
||||
a constant which puts it out of range; in such a case the
|
||||
link will fail with a reloc overflow error. Since the
|
||||
compiler will never generate such code, it should be easy
|
||||
enough to work around it by changing the assembly code in the
|
||||
source file. */
|
||||
relocation -= 4;
|
||||
|
||||
/* Now RELOCATION is the number we want to put in the object
|
||||
file. See whether it fits. */
|
||||
if (relocation >= -0x20000 && relocation < 0x20000)
|
||||
continue;
|
||||
|
||||
/* Now that we know this reloc needs work, which will rarely
|
||||
happen, go ahead and grab the section contents. */
|
||||
if (contents == (bfd_byte *) NULL)
|
||||
{
|
||||
if (info->keep_memory)
|
||||
contents = (bfd_byte *) bfd_alloc (abfd, sec->_raw_size);
|
||||
else
|
||||
contents = (bfd_byte *) malloc (sec->_raw_size);
|
||||
if (contents == (bfd_byte *) NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
if (! bfd_get_section_contents (abfd, sec, (PTR) contents,
|
||||
(file_ptr) 0, sec->_raw_size))
|
||||
goto error_return;
|
||||
if (info->keep_memory)
|
||||
section_tdata->contents = contents;
|
||||
}
|
||||
|
||||
/* We only support changing the bal instruction. It would be
|
||||
possible to handle other PC relative branches, but some of
|
||||
them (the conditional branches) would require a different
|
||||
length instruction sequence which would complicate both this
|
||||
routine and mips_relax_pcrel16. It could be written if
|
||||
somebody felt it were important. Ignoring this reloc will
|
||||
presumably cause a reloc overflow error later on. */
|
||||
if (bfd_get_32 (abfd, contents + int_rel.r_vaddr - sec->vma)
|
||||
!= 0x0411ffff) /* bgezal $0,. == bal . */
|
||||
continue;
|
||||
|
||||
/* Bother. We need to expand this reloc, and we will need to
|
||||
make another relaxation pass since this change may put other
|
||||
relocs out of range. We need to examine the local branches
|
||||
and we need to allocate memory to hold the offsets we must
|
||||
add to them. We also need to adjust the values of all
|
||||
symbols in the object file following this location. */
|
||||
|
||||
sec->_cooked_size += PCREL16_EXPANSION_ADJUSTMENT;
|
||||
*again = true;
|
||||
|
||||
if (offsets == (long *) NULL)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
size = sec->reloc_count * sizeof (long);
|
||||
offsets = (long *) bfd_alloc_by_size_t (abfd, size);
|
||||
if (offsets == (long *) NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
memset (offsets, 0, size);
|
||||
section_tdata->offsets = offsets;
|
||||
}
|
||||
|
||||
offsets[i] = 1;
|
||||
|
||||
/* Now look for all PC relative branches that cross this reloc
|
||||
and adjust their offsets. We will turn the single branch
|
||||
instruction into a four instruction sequence. In this loop
|
||||
we are only interested in local PC relative branches. */
|
||||
adj_ext_rel = (struct external_reloc *) section_tdata->external_relocs;
|
||||
for (adj_i = 0; adj_ext_rel < ext_rel_end; adj_ext_rel++, adj_i++)
|
||||
{
|
||||
struct internal_reloc adj_int_rel;
|
||||
unsigned long insn;
|
||||
bfd_vma dst;
|
||||
|
||||
/* Quickly check that this reloc is internal PCREL16. */
|
||||
if (abfd->xvec->header_byteorder_big_p)
|
||||
{
|
||||
if ((adj_ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_BIG) != 0
|
||||
|| (((adj_ext_rel->r_bits[3] & RELOC_BITS3_TYPE_BIG)
|
||||
>> RELOC_BITS3_TYPE_SH_BIG)
|
||||
!= MIPS_R_PCREL16))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((adj_ext_rel->r_bits[3] & RELOC_BITS3_EXTERN_LITTLE) != 0
|
||||
|| (((adj_ext_rel->r_bits[3] & RELOC_BITS3_TYPE_LITTLE)
|
||||
>> RELOC_BITS3_TYPE_SH_LITTLE)
|
||||
!= MIPS_R_PCREL16))
|
||||
continue;
|
||||
}
|
||||
|
||||
mips_ecoff_swap_reloc_in (abfd, (PTR) adj_ext_rel, &adj_int_rel);
|
||||
|
||||
/* We are only interested in a PC relative reloc within this
|
||||
section. FIXME: Cross section PC relative relocs may not
|
||||
be handled correctly; does anybody care? */
|
||||
if (adj_int_rel.r_symndx != RELOC_SECTION_TEXT)
|
||||
continue;
|
||||
|
||||
/* Fetch the branch instruction. */
|
||||
insn = bfd_get_32 (abfd, contents + adj_int_rel.r_vaddr - sec->vma);
|
||||
|
||||
/* Work out the destination address. */
|
||||
dst = (insn & 0xffff) << 2;
|
||||
if ((dst & 0x20000) != 0)
|
||||
dst -= 0x40000;
|
||||
dst += adj_int_rel.r_vaddr + 4;
|
||||
|
||||
/* If this branch crosses the branch we just decided to
|
||||
expand, adjust the offset appropriately. */
|
||||
if (adj_int_rel.r_vaddr < int_rel.r_vaddr
|
||||
&& dst > int_rel.r_vaddr)
|
||||
offsets[adj_i] += PCREL16_EXPANSION_ADJUSTMENT;
|
||||
else if (adj_int_rel.r_vaddr > int_rel.r_vaddr
|
||||
&& dst <= int_rel.r_vaddr)
|
||||
offsets[adj_i] -= PCREL16_EXPANSION_ADJUSTMENT;
|
||||
}
|
||||
|
||||
/* Find all symbols in this section defined by this object file
|
||||
and adjust their values. Note that we decide whether to
|
||||
adjust the value based on the value stored in the ECOFF EXTR
|
||||
structure, because the value stored in the hash table may
|
||||
have been changed by an earlier expanded reloc and thus may
|
||||
no longer correctly indicate whether the symbol is before or
|
||||
after the expanded reloc. */
|
||||
ext_count = ecoff_data (abfd)->debug_info.symbolic_header.iextMax;
|
||||
adj_h_ptr = ecoff_data (abfd)->sym_hashes;
|
||||
adj_h_ptr_end = adj_h_ptr + ext_count;
|
||||
for (; adj_h_ptr < adj_h_ptr_end; adj_h_ptr++)
|
||||
{
|
||||
struct ecoff_link_hash_entry *adj_h;
|
||||
|
||||
adj_h = *adj_h_ptr;
|
||||
if (adj_h != (struct ecoff_link_hash_entry *) NULL
|
||||
&& adj_h->root.type == bfd_link_hash_defined
|
||||
&& adj_h->root.u.def.section == sec
|
||||
&& adj_h->esym.asym.value > int_rel.r_vaddr)
|
||||
adj_h->root.u.def.value += PCREL16_EXPANSION_ADJUSTMENT;
|
||||
}
|
||||
|
||||
/* Add an entry to the symbol value adjust list. This is used
|
||||
by bfd_ecoff_debug_accumulate to adjust the values of
|
||||
internal symbols and FDR's. */
|
||||
adjust = ((struct ecoff_value_adjust *)
|
||||
bfd_alloc (abfd, sizeof (struct ecoff_value_adjust)));
|
||||
if (adjust == (struct ecoff_value_adjust *) NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
adjust->start = int_rel.r_vaddr;
|
||||
adjust->end = sec->vma + sec->_raw_size;
|
||||
adjust->adjust = PCREL16_EXPANSION_ADJUSTMENT;
|
||||
|
||||
adjust->next = ecoff_data (abfd)->debug_info.adjust;
|
||||
ecoff_data (abfd)->debug_info.adjust = adjust;
|
||||
}
|
||||
|
||||
if (contents != (bfd_byte *) NULL && ! info->keep_memory)
|
||||
free (contents);
|
||||
|
||||
return true;
|
||||
|
||||
error_return:
|
||||
if (contents != (bfd_byte *) NULL && ! info->keep_memory)
|
||||
free (contents);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This routine is called from mips_relocate_section when a PC
|
||||
relative reloc must be expanded into the five instruction sequence.
|
||||
It handles all the details of the expansion, including resolving
|
||||
the reloc. */
|
||||
|
||||
static boolean
|
||||
mips_relax_pcrel16 (info, input_bfd, input_section, h, location, address)
|
||||
struct bfd_link_info *info;
|
||||
bfd *input_bfd;
|
||||
asection *input_section;
|
||||
struct ecoff_link_hash_entry *h;
|
||||
bfd_byte *location;
|
||||
bfd_vma address;
|
||||
{
|
||||
bfd_vma relocation;
|
||||
|
||||
/* 0x0411ffff is bgezal $0,. == bal . */
|
||||
BFD_ASSERT (bfd_get_32 (input_bfd, location) == 0x0411ffff);
|
||||
|
||||
/* We need to compute the distance between the symbol and the
|
||||
current address plus eight. */
|
||||
relocation = (h->root.u.def.value
|
||||
+ h->root.u.def.section->output_section->vma
|
||||
+ h->root.u.def.section->output_offset);
|
||||
relocation -= address + 8;
|
||||
|
||||
/* If the lower half is negative, increment the upper 16 half. */
|
||||
if ((relocation & 0x8000) != 0)
|
||||
relocation += 0x10000;
|
||||
|
||||
bfd_put_32 (input_bfd, 0x04110001, location); /* bal .+8 */
|
||||
bfd_put_32 (input_bfd,
|
||||
0x3c010000 | ((relocation >> 16) & 0xffff), /* lui $at,XX */
|
||||
location + 4);
|
||||
bfd_put_32 (input_bfd,
|
||||
0x24210000 | (relocation & 0xffff), /* addiu $at,$at,XX */
|
||||
location + 8);
|
||||
bfd_put_32 (input_bfd, 0x003f0821, location + 12); /* addu $at,$at,$ra */
|
||||
bfd_put_32 (input_bfd, 0x0020f809, location + 16); /* jalr $at */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* This is the ECOFF backend structure. The backend field of the
|
||||
target vector points to this. */
|
||||
|
||||
|
@ -1256,6 +1773,9 @@ static const struct ecoff_backend_data mips_ecoff_backend_data =
|
|||
#define ecoff_bfd_get_relocated_section_contents \
|
||||
bfd_generic_get_relocated_section_contents
|
||||
|
||||
/* Relaxing sections is MIPS specific. */
|
||||
#define ecoff_bfd_relax_section mips_relax_section
|
||||
|
||||
/* Core file support is usually traditional (but note that Irix uses
|
||||
irix-core.c). */
|
||||
#define ecoff_core_file_p _bfd_dummy_target
|
||||
|
|
418
bfd/ecoff.c
418
bfd/ecoff.c
|
@ -371,13 +371,16 @@ ecoff_styp_to_sec_flags (abfd, hdr)
|
|||
}
|
||||
else if ((styp_flags & STYP_DATA)
|
||||
|| (styp_flags & STYP_RDATA)
|
||||
|| (styp_flags & STYP_SDATA))
|
||||
|| (styp_flags & STYP_SDATA)
|
||||
|| styp_flags == STYP_PDATA
|
||||
|| styp_flags == STYP_XDATA)
|
||||
{
|
||||
if (sec_flags & SEC_NEVER_LOAD)
|
||||
sec_flags |= SEC_DATA | SEC_SHARED_LIBRARY;
|
||||
else
|
||||
sec_flags |= SEC_DATA | SEC_LOAD | SEC_ALLOC;
|
||||
if (styp_flags & STYP_RDATA)
|
||||
if ((styp_flags & STYP_RDATA)
|
||||
|| styp_flags == STYP_PDATA)
|
||||
sec_flags |= SEC_READONLY;
|
||||
}
|
||||
else if ((styp_flags & STYP_BSS)
|
||||
|
@ -385,7 +388,7 @@ ecoff_styp_to_sec_flags (abfd, hdr)
|
|||
{
|
||||
sec_flags |= SEC_ALLOC;
|
||||
}
|
||||
else if (styp_flags & STYP_INFO)
|
||||
else if ((styp_flags & STYP_INFO) || styp_flags == STYP_COMMENT)
|
||||
{
|
||||
sec_flags |= SEC_NEVER_LOAD;
|
||||
}
|
||||
|
@ -3650,7 +3653,7 @@ ecoff_link_check_archive_element (abfd, info, pneeded)
|
|||
external_ext_size = backend->debug_swap.external_ext_size;
|
||||
esize = symhdr->iextMax * external_ext_size;
|
||||
external_ext = (PTR) malloc (esize);
|
||||
if (external_ext == NULL)
|
||||
if (external_ext == NULL && esize != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
|
@ -3661,7 +3664,7 @@ ecoff_link_check_archive_element (abfd, info, pneeded)
|
|||
goto error_return;
|
||||
|
||||
ssext = (char *) malloc (symhdr->issExtMax);
|
||||
if (ssext == NULL)
|
||||
if (ssext == NULL && symhdr->issExtMax != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
|
@ -3774,7 +3777,7 @@ ecoff_link_add_object_symbols (abfd, info)
|
|||
external_ext_size = ecoff_backend (abfd)->debug_swap.external_ext_size;
|
||||
esize = symhdr->iextMax * external_ext_size;
|
||||
external_ext = (PTR) malloc (esize);
|
||||
if (external_ext == NULL)
|
||||
if (external_ext == NULL && esize != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
|
@ -3785,7 +3788,7 @@ ecoff_link_add_object_symbols (abfd, info)
|
|||
goto error_return;
|
||||
|
||||
ssext = (char *) malloc (symhdr->issExtMax);
|
||||
if (ssext == NULL)
|
||||
if (ssext == NULL && symhdr->issExtMax != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
|
@ -3972,7 +3975,7 @@ ecoff_link_add_externals (abfd, info, external_ext, ssext)
|
|||
|
||||
if (! (_bfd_generic_link_add_one_symbol
|
||||
(info, abfd, name, BSF_GLOBAL, section, value,
|
||||
(const char *) NULL, true, true, backend->constructor_bitsize,
|
||||
(const char *) NULL, true, true,
|
||||
(struct bfd_link_hash_entry **) &h)))
|
||||
return false;
|
||||
|
||||
|
@ -4006,6 +4009,9 @@ static boolean ecoff_link_write_external
|
|||
static boolean ecoff_indirect_link_order
|
||||
PARAMS ((bfd *, struct bfd_link_info *, asection *,
|
||||
struct bfd_link_order *));
|
||||
static boolean ecoff_reloc_link_order
|
||||
PARAMS ((bfd *, struct bfd_link_info *, asection *,
|
||||
struct bfd_link_order *));
|
||||
|
||||
/* ECOFF final link routine. This looks through all the input BFDs
|
||||
and gathers together all the debugging information, and then
|
||||
|
@ -4111,6 +4117,9 @@ ecoff_bfd_final_link (abfd, info)
|
|||
p = p->next)
|
||||
if (p->type == bfd_indirect_link_order)
|
||||
o->reloc_count += p->u.indirect.section->reloc_count;
|
||||
else if (p->type == bfd_section_reloc_link_order
|
||||
|| p->type == bfd_symbol_reloc_link_order)
|
||||
++o->reloc_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4189,6 +4198,12 @@ ecoff_bfd_final_link (abfd, info)
|
|||
if (! ecoff_indirect_link_order (abfd, info, o, p))
|
||||
return false;
|
||||
}
|
||||
else if (p->type == bfd_section_reloc_link_order
|
||||
|| p->type == bfd_symbol_reloc_link_order)
|
||||
{
|
||||
if (! ecoff_reloc_link_order (abfd, info, o, p))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! _bfd_default_link_order (abfd, info, o, p))
|
||||
|
@ -4241,16 +4256,22 @@ ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle)
|
|||
} \
|
||||
}
|
||||
|
||||
READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
|
||||
READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
|
||||
READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
|
||||
READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
|
||||
READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
|
||||
READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
|
||||
union aux_ext *);
|
||||
READ (ss, cbSsOffset, issMax, sizeof (char), char *);
|
||||
READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
|
||||
READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
|
||||
/* If raw_syments is not NULL, then the data was already by read by
|
||||
ecoff_slurp_symbolic_info. */
|
||||
if (ecoff_data (input_bfd)->raw_syments == NULL)
|
||||
{
|
||||
READ (line, cbLineOffset, cbLine, sizeof (unsigned char),
|
||||
unsigned char *);
|
||||
READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
|
||||
READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
|
||||
READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
|
||||
READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
|
||||
READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
|
||||
union aux_ext *);
|
||||
READ (ss, cbSsOffset, issMax, sizeof (char), char *);
|
||||
READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
|
||||
READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
|
||||
}
|
||||
#undef READ
|
||||
|
||||
/* We do not read the external strings or the external symbols. */
|
||||
|
@ -4261,36 +4282,39 @@ ecoff_final_link_debug_accumulate (output_bfd, input_bfd, info, handle)
|
|||
input_bfd, debug, swap, info));
|
||||
|
||||
return_something:
|
||||
if (debug->line != NULL)
|
||||
free (debug->line);
|
||||
if (debug->external_dnr != NULL)
|
||||
free (debug->external_dnr);
|
||||
if (debug->external_pdr != NULL)
|
||||
free (debug->external_pdr);
|
||||
if (debug->external_sym != NULL)
|
||||
free (debug->external_sym);
|
||||
if (debug->external_opt != NULL)
|
||||
free (debug->external_opt);
|
||||
if (debug->external_aux != NULL)
|
||||
free (debug->external_aux);
|
||||
if (debug->ss != NULL)
|
||||
free (debug->ss);
|
||||
if (debug->external_fdr != NULL)
|
||||
free (debug->external_fdr);
|
||||
if (debug->external_rfd != NULL)
|
||||
free (debug->external_rfd);
|
||||
if (ecoff_data (input_bfd)->raw_syments == NULL)
|
||||
{
|
||||
if (debug->line != NULL)
|
||||
free (debug->line);
|
||||
if (debug->external_dnr != NULL)
|
||||
free (debug->external_dnr);
|
||||
if (debug->external_pdr != NULL)
|
||||
free (debug->external_pdr);
|
||||
if (debug->external_sym != NULL)
|
||||
free (debug->external_sym);
|
||||
if (debug->external_opt != NULL)
|
||||
free (debug->external_opt);
|
||||
if (debug->external_aux != NULL)
|
||||
free (debug->external_aux);
|
||||
if (debug->ss != NULL)
|
||||
free (debug->ss);
|
||||
if (debug->external_fdr != NULL)
|
||||
free (debug->external_fdr);
|
||||
if (debug->external_rfd != NULL)
|
||||
free (debug->external_rfd);
|
||||
|
||||
/* Make sure we don't accidentally follow one of these pointers on
|
||||
to the stack. */
|
||||
debug->line = NULL;
|
||||
debug->external_dnr = NULL;
|
||||
debug->external_pdr = NULL;
|
||||
debug->external_sym = NULL;
|
||||
debug->external_opt = NULL;
|
||||
debug->external_aux = NULL;
|
||||
debug->ss = NULL;
|
||||
debug->external_fdr = NULL;
|
||||
debug->external_rfd = NULL;
|
||||
/* Make sure we don't accidentally follow one of these pointers
|
||||
into freed memory. */
|
||||
debug->line = NULL;
|
||||
debug->external_dnr = NULL;
|
||||
debug->external_pdr = NULL;
|
||||
debug->external_sym = NULL;
|
||||
debug->external_opt = NULL;
|
||||
debug->external_aux = NULL;
|
||||
debug->ss = NULL;
|
||||
debug->external_fdr = NULL;
|
||||
debug->external_rfd = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -4318,9 +4342,42 @@ ecoff_link_write_external (h, data)
|
|||
h->esym.reserved = 0;
|
||||
h->esym.ifd = ifdNil;
|
||||
h->esym.asym.value = 0;
|
||||
/* FIXME: we can do better than this for st and sc. */
|
||||
h->esym.asym.st = stGlobal;
|
||||
h->esym.asym.sc = scAbs;
|
||||
|
||||
if (h->root.type != bfd_link_hash_defined)
|
||||
h->esym.asym.sc = scAbs;
|
||||
else
|
||||
{
|
||||
asection *output_section;
|
||||
const char *name;
|
||||
|
||||
output_section = h->root.u.def.section->output_section;
|
||||
name = bfd_section_name (output_section->owner, output_section);
|
||||
|
||||
if (strcmp (name, _TEXT) == 0)
|
||||
h->esym.asym.sc = scText;
|
||||
else if (strcmp (name, _DATA) == 0)
|
||||
h->esym.asym.sc = scData;
|
||||
else if (strcmp (name, _SDATA) == 0)
|
||||
h->esym.asym.sc = scSData;
|
||||
else if (strcmp (name, _RDATA) == 0)
|
||||
h->esym.asym.sc = scRData;
|
||||
else if (strcmp (name, _BSS) == 0)
|
||||
h->esym.asym.sc = scBss;
|
||||
else if (strcmp (name, _SBSS) == 0)
|
||||
h->esym.asym.sc = scSBss;
|
||||
else if (strcmp (name, _INIT) == 0)
|
||||
h->esym.asym.sc = scInit;
|
||||
else if (strcmp (name, _FINI) == 0)
|
||||
h->esym.asym.sc = scFini;
|
||||
else if (strcmp (name, _PDATA) == 0)
|
||||
h->esym.asym.sc = scPData;
|
||||
else if (strcmp (name, _XDATA) == 0)
|
||||
h->esym.asym.sc = scXData;
|
||||
else
|
||||
h->esym.asym.sc = scAbs;
|
||||
}
|
||||
|
||||
h->esym.asym.reserved = 0;
|
||||
h->esym.asym.index = indexNil;
|
||||
}
|
||||
|
@ -4343,9 +4400,9 @@ ecoff_link_write_external (h, data)
|
|||
abort ();
|
||||
case bfd_link_hash_undefined:
|
||||
case bfd_link_hash_weak:
|
||||
if (h->esym.asym.st != scUndefined
|
||||
&& h->esym.asym.st != scSUndefined)
|
||||
h->esym.asym.st = scUndefined;
|
||||
if (h->esym.asym.sc != scUndefined
|
||||
&& h->esym.asym.sc != scSUndefined)
|
||||
h->esym.asym.sc = scUndefined;
|
||||
break;
|
||||
case bfd_link_hash_defined:
|
||||
if (h->esym.asym.sc == scUndefined
|
||||
|
@ -4394,7 +4451,9 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
|
|||
{
|
||||
asection *input_section;
|
||||
bfd *input_bfd;
|
||||
bfd_size_type input_size;
|
||||
struct ecoff_section_tdata *section_tdata;
|
||||
bfd_size_type raw_size;
|
||||
bfd_size_type cooked_size;
|
||||
bfd_byte *contents = NULL;
|
||||
bfd_size_type external_reloc_size;
|
||||
bfd_size_type external_relocs_size;
|
||||
|
@ -4407,37 +4466,63 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
|
|||
|
||||
input_section = link_order->u.indirect.section;
|
||||
input_bfd = input_section->owner;
|
||||
section_tdata = ecoff_section_data (input_bfd, input_section);
|
||||
|
||||
raw_size = input_section->_raw_size;
|
||||
cooked_size = input_section->_cooked_size;
|
||||
if (cooked_size == 0)
|
||||
cooked_size = raw_size;
|
||||
|
||||
BFD_ASSERT (input_section->output_section == output_section);
|
||||
BFD_ASSERT (input_section->output_offset == link_order->offset);
|
||||
BFD_ASSERT (bfd_section_size (input_bfd, input_section) == link_order->size);
|
||||
BFD_ASSERT (cooked_size == link_order->size);
|
||||
|
||||
/* Get the section contents. */
|
||||
input_size = bfd_section_size (input_bfd, input_section);
|
||||
contents = (bfd_byte *) malloc (input_size);
|
||||
if (contents == NULL)
|
||||
/* Get the section contents. We allocate memory for the larger of
|
||||
the size before relocating and the size after relocating. */
|
||||
contents = (bfd_byte *) malloc (raw_size >= cooked_size
|
||||
? raw_size
|
||||
: cooked_size);
|
||||
if (contents == NULL && raw_size != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
if (! bfd_get_section_contents (input_bfd, input_section, (PTR) contents,
|
||||
(file_ptr) 0, input_size))
|
||||
goto error_return;
|
||||
|
||||
/* Get the relocs. */
|
||||
/* If we are relaxing, the contents may have already been read into
|
||||
memory, in which case we copy them into our new buffer. We don't
|
||||
simply reuse the old buffer in case cooked_size > raw_size. */
|
||||
if (section_tdata != (struct ecoff_section_tdata *) NULL
|
||||
&& section_tdata->contents != (bfd_byte *) NULL)
|
||||
memcpy (contents, section_tdata->contents, raw_size);
|
||||
else
|
||||
{
|
||||
if (! bfd_get_section_contents (input_bfd, input_section,
|
||||
(PTR) contents,
|
||||
(file_ptr) 0, raw_size))
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Get the relocs. If we are relaxing MIPS code, they will already
|
||||
have been read in. Otherwise, we read them in now. */
|
||||
external_reloc_size = ecoff_backend (input_bfd)->external_reloc_size;
|
||||
external_relocs_size = external_reloc_size * input_section->reloc_count;
|
||||
external_relocs = (PTR) malloc (external_relocs_size);
|
||||
if (external_relocs == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
|
||||
|| (bfd_read (external_relocs, 1, external_relocs_size, input_bfd)
|
||||
!= external_relocs_size))
|
||||
goto error_return;
|
||||
if (section_tdata != (struct ecoff_section_tdata *) NULL)
|
||||
external_relocs = section_tdata->external_relocs;
|
||||
else
|
||||
{
|
||||
external_relocs = (PTR) malloc (external_relocs_size);
|
||||
if (external_relocs == NULL && external_relocs_size != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (bfd_seek (input_bfd, input_section->rel_filepos, SEEK_SET) != 0
|
||||
|| (bfd_read (external_relocs, 1, external_relocs_size, input_bfd)
|
||||
!= external_relocs_size))
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* Relocate the section contents. */
|
||||
if (! ((*ecoff_backend (input_bfd)->relocate_section)
|
||||
|
@ -4450,7 +4535,7 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
|
|||
output_section,
|
||||
(PTR) contents,
|
||||
input_section->output_offset,
|
||||
input_size))
|
||||
cooked_size))
|
||||
goto error_return;
|
||||
|
||||
/* If we are producing relocateable output, the relocs were
|
||||
|
@ -4471,14 +4556,197 @@ ecoff_indirect_link_order (output_bfd, info, output_section, link_order)
|
|||
|
||||
if (contents != NULL)
|
||||
free (contents);
|
||||
if (external_relocs != NULL)
|
||||
if (external_relocs != NULL && section_tdata == NULL)
|
||||
free (external_relocs);
|
||||
return true;
|
||||
|
||||
error_return:
|
||||
if (contents != NULL)
|
||||
free (contents);
|
||||
if (external_relocs != NULL)
|
||||
if (external_relocs != NULL && section_tdata == NULL)
|
||||
free (external_relocs);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Generate a reloc when linking an ECOFF file. This is a reloc
|
||||
requested by the linker, and does come from any input file. This
|
||||
is used to build constructor and destructor tables when linking
|
||||
with -Ur. */
|
||||
|
||||
static boolean
|
||||
ecoff_reloc_link_order (output_bfd, info, output_section, link_order)
|
||||
bfd *output_bfd;
|
||||
struct bfd_link_info *info;
|
||||
asection *output_section;
|
||||
struct bfd_link_order *link_order;
|
||||
{
|
||||
arelent rel;
|
||||
struct internal_reloc in;
|
||||
bfd_size_type external_reloc_size;
|
||||
bfd_byte *rbuf;
|
||||
boolean ok;
|
||||
|
||||
/* We set up an arelent to pass to the backend adjust_reloc_out
|
||||
routine. */
|
||||
rel.address = link_order->offset;
|
||||
|
||||
rel.howto = bfd_reloc_type_lookup (output_bfd, link_order->u.reloc.p->reloc);
|
||||
if (rel.howto == (const reloc_howto_type *) NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (link_order->type == bfd_section_reloc_link_order)
|
||||
rel.sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
|
||||
else
|
||||
{
|
||||
/* We can't set up a reloc against a symbol correctly, because
|
||||
we have no asymbol structure. Currently no adjust_reloc_out
|
||||
routine cases. */
|
||||
rel.sym_ptr_ptr = (asymbol **) NULL;
|
||||
}
|
||||
|
||||
/* All ECOFF relocs are in-place. Put the addend into the object
|
||||
file. */
|
||||
|
||||
BFD_ASSERT (rel.howto->partial_inplace);
|
||||
if (link_order->u.reloc.p->addend != 0)
|
||||
{
|
||||
bfd_size_type size;
|
||||
bfd_reloc_status_type rstat;
|
||||
bfd_byte *buf;
|
||||
boolean ok;
|
||||
|
||||
size = bfd_get_reloc_size (rel.howto);
|
||||
buf = (bfd_byte *) bfd_zmalloc (size);
|
||||
if (buf == (bfd_byte *) NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return false;
|
||||
}
|
||||
rstat = _bfd_relocate_contents (rel.howto, output_bfd,
|
||||
link_order->u.reloc.p->addend, buf);
|
||||
switch (rstat)
|
||||
{
|
||||
case bfd_reloc_ok:
|
||||
break;
|
||||
default:
|
||||
case bfd_reloc_outofrange:
|
||||
abort ();
|
||||
case bfd_reloc_overflow:
|
||||
if (! ((*info->callbacks->reloc_overflow)
|
||||
(info,
|
||||
(link_order->type == bfd_section_reloc_link_order
|
||||
? bfd_section_name (output_bfd,
|
||||
link_order->u.reloc.p->u.section)
|
||||
: link_order->u.reloc.p->u.name),
|
||||
rel.howto->name, link_order->u.reloc.p->addend,
|
||||
(bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
|
||||
{
|
||||
free (buf);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
ok = bfd_set_section_contents (output_bfd, output_section, (PTR) buf,
|
||||
(file_ptr) link_order->offset, size);
|
||||
free (buf);
|
||||
if (! ok)
|
||||
return false;
|
||||
}
|
||||
|
||||
rel.addend = 0;
|
||||
|
||||
/* Move the information into a internal_reloc structure. */
|
||||
in.r_vaddr = (rel.address
|
||||
+ bfd_get_section_vma (output_bfd, output_section));
|
||||
in.r_type = rel.howto->type;
|
||||
|
||||
if (link_order->type == bfd_symbol_reloc_link_order)
|
||||
{
|
||||
struct ecoff_link_hash_entry *h;
|
||||
|
||||
h = ecoff_link_hash_lookup (ecoff_hash_table (info),
|
||||
link_order->u.reloc.p->u.name,
|
||||
false, false, true);
|
||||
if (h != (struct ecoff_link_hash_entry *) NULL
|
||||
&& h->indx != -1)
|
||||
in.r_symndx = h->indx;
|
||||
else
|
||||
{
|
||||
if (! ((*info->callbacks->unattached_reloc)
|
||||
(info, link_order->u.reloc.p->u.name, (bfd *) NULL,
|
||||
(asection *) NULL, (bfd_vma) 0)))
|
||||
return false;
|
||||
in.r_symndx = 0;
|
||||
}
|
||||
in.r_extern = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
CONST char *name;
|
||||
|
||||
name = bfd_get_section_name (output_bfd,
|
||||
link_order->u.reloc.p->u.section);
|
||||
if (strcmp (name, ".text") == 0)
|
||||
in.r_symndx = RELOC_SECTION_TEXT;
|
||||
else if (strcmp (name, ".rdata") == 0)
|
||||
in.r_symndx = RELOC_SECTION_RDATA;
|
||||
else if (strcmp (name, ".data") == 0)
|
||||
in.r_symndx = RELOC_SECTION_DATA;
|
||||
else if (strcmp (name, ".sdata") == 0)
|
||||
in.r_symndx = RELOC_SECTION_SDATA;
|
||||
else if (strcmp (name, ".sbss") == 0)
|
||||
in.r_symndx = RELOC_SECTION_SBSS;
|
||||
else if (strcmp (name, ".bss") == 0)
|
||||
in.r_symndx = RELOC_SECTION_BSS;
|
||||
else if (strcmp (name, ".init") == 0)
|
||||
in.r_symndx = RELOC_SECTION_INIT;
|
||||
else if (strcmp (name, ".lit8") == 0)
|
||||
in.r_symndx = RELOC_SECTION_LIT8;
|
||||
else if (strcmp (name, ".lit4") == 0)
|
||||
in.r_symndx = RELOC_SECTION_LIT4;
|
||||
else if (strcmp (name, ".xdata") == 0)
|
||||
in.r_symndx = RELOC_SECTION_XDATA;
|
||||
else if (strcmp (name, ".pdata") == 0)
|
||||
in.r_symndx = RELOC_SECTION_PDATA;
|
||||
else if (strcmp (name, ".fini") == 0)
|
||||
in.r_symndx = RELOC_SECTION_FINI;
|
||||
else if (strcmp (name, ".lita") == 0)
|
||||
in.r_symndx = RELOC_SECTION_LITA;
|
||||
else if (strcmp (name, "*ABS*") == 0)
|
||||
in.r_symndx = RELOC_SECTION_ABS;
|
||||
else
|
||||
abort ();
|
||||
in.r_extern = 0;
|
||||
}
|
||||
|
||||
/* Let the BFD backend adjust the reloc. */
|
||||
(*ecoff_backend (output_bfd)->adjust_reloc_out) (output_bfd, &rel, &in);
|
||||
|
||||
/* Get some memory and swap out the reloc. */
|
||||
external_reloc_size = ecoff_backend (output_bfd)->external_reloc_size;
|
||||
rbuf = (bfd_byte *) malloc (external_reloc_size);
|
||||
if (rbuf == (bfd_byte *) NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return false;
|
||||
}
|
||||
|
||||
(*ecoff_backend (output_bfd)->swap_reloc_out) (output_bfd, &in, (PTR) rbuf);
|
||||
|
||||
ok = (bfd_seek (output_bfd,
|
||||
(output_section->rel_filepos +
|
||||
output_section->reloc_count * external_reloc_size),
|
||||
SEEK_SET) == 0
|
||||
&& (bfd_write ((PTR) rbuf, 1, external_reloc_size, output_bfd)
|
||||
== external_reloc_size));
|
||||
|
||||
if (ok)
|
||||
++output_section->reloc_count;
|
||||
|
||||
free (rbuf);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
|
128
bfd/ecofflink.c
128
bfd/ecofflink.c
|
@ -519,10 +519,17 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
|
|||
hash reduces the chance that we will merge symbol
|
||||
information that should not be merged. */
|
||||
name = input_debug->ss + fdr.issBase + fdr.rss;
|
||||
lookup = (char *) alloca (strlen (name) + 20);
|
||||
|
||||
lookup = (char *) malloc (strlen (name) + 20);
|
||||
if (lookup == NULL)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return false;
|
||||
}
|
||||
sprintf (lookup, "%s %lx", name, fdr.csym);
|
||||
|
||||
fh = string_hash_lookup (&ainfo->fdr_hash, lookup, true, true);
|
||||
free (lookup);
|
||||
if (fh == (struct string_hash_entry *) NULL)
|
||||
return false;
|
||||
|
||||
|
@ -600,6 +607,22 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
|
|||
else
|
||||
(*input_swap->swap_fdr_in) (input_bfd, (PTR) fdr_ptr, &fdr);
|
||||
|
||||
/* Adjust the FDR address for any changes that may have been
|
||||
made by relaxing. */
|
||||
if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
|
||||
{
|
||||
bfd_vma adr;
|
||||
struct ecoff_value_adjust *adjust;
|
||||
|
||||
adr = fdr.adr;
|
||||
for (adjust = input_debug->adjust;
|
||||
adjust != (struct ecoff_value_adjust *) NULL;
|
||||
adjust = adjust->next)
|
||||
if (adr >= adjust->start
|
||||
&& adr < adjust->end)
|
||||
fdr.adr += adjust->adjust;
|
||||
}
|
||||
|
||||
/* FIXME: It is conceivable that this FDR points to the .init or
|
||||
.fini section, in which case this will not do the right
|
||||
thing. */
|
||||
|
@ -641,6 +664,19 @@ bfd_ecoff_debug_accumulate (handle, output_bfd, output_debug, output_swap,
|
|||
case stLabel:
|
||||
case stProc:
|
||||
case stStaticProc:
|
||||
if (input_debug->adjust != (struct ecoff_value_adjust *) NULL)
|
||||
{
|
||||
bfd_vma value;
|
||||
struct ecoff_value_adjust *adjust;
|
||||
|
||||
value = internal_sym.value;
|
||||
for (adjust = input_debug->adjust;
|
||||
adjust != (struct ecoff_value_adjust *) NULL;
|
||||
adjust = adjust->next)
|
||||
if (value >= adjust->start
|
||||
&& value < adjust->end)
|
||||
internal_sym.value += adjust->adjust;
|
||||
}
|
||||
internal_sym.value += section_adjust[internal_sym.sc];
|
||||
break;
|
||||
|
||||
|
@ -1253,7 +1289,7 @@ ecoff_write_symhdr (abfd, debug, swap, where)
|
|||
file_ptr where;
|
||||
{
|
||||
HDRR * const symhdr = &debug->symbolic_header;
|
||||
char *buff;
|
||||
char *buff = NULL;
|
||||
|
||||
ecoff_align_debug (abfd, debug, swap);
|
||||
|
||||
|
@ -1288,13 +1324,25 @@ ecoff_write_symhdr (abfd, debug, swap, where)
|
|||
SET (cbExtOffset, iextMax, swap->external_ext_size);
|
||||
#undef SET
|
||||
|
||||
buff = (PTR) alloca (swap->external_hdr_size);
|
||||
buff = (PTR) malloc (swap->external_hdr_size);
|
||||
if (buff == NULL && swap->external_hdr_size != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
(*swap->swap_hdr_out) (abfd, symhdr, buff);
|
||||
if (bfd_write (buff, 1, swap->external_hdr_size, abfd)
|
||||
!= swap->external_hdr_size)
|
||||
return false;
|
||||
goto error_return;
|
||||
|
||||
if (buff != NULL)
|
||||
free (buff);
|
||||
return true;
|
||||
error_return:
|
||||
if (buff != NULL)
|
||||
free (buff);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Write out the ECOFF debugging information. This function assumes
|
||||
|
@ -1377,10 +1425,20 @@ ecoff_write_shuffle (abfd, swap, shuffle, space)
|
|||
bfd_byte *s;
|
||||
|
||||
i = swap->debug_align - (total & (swap->debug_align - 1));
|
||||
s = (bfd_byte *) alloca (i);
|
||||
s = (bfd_byte *) malloc (i);
|
||||
if (s == NULL && i != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return false;
|
||||
}
|
||||
|
||||
memset ((PTR) s, 0, i);
|
||||
if (bfd_write ((PTR) s, 1, i, abfd) != i)
|
||||
return false;
|
||||
{
|
||||
free (s);
|
||||
return false;
|
||||
}
|
||||
free (s);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1399,19 +1457,24 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
file_ptr where;
|
||||
{
|
||||
struct accumulate *ainfo = (struct accumulate *) handle;
|
||||
PTR space;
|
||||
PTR space = NULL;
|
||||
|
||||
if (! ecoff_write_symhdr (abfd, debug, swap, where))
|
||||
return false;
|
||||
goto error_return;
|
||||
|
||||
space = (PTR) alloca (ainfo->largest_file_shuffle);
|
||||
space = (PTR) malloc (ainfo->largest_file_shuffle);
|
||||
if (space == NULL && ainfo->largest_file_shuffle != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (! ecoff_write_shuffle (abfd, swap, ainfo->line, space)
|
||||
|| ! ecoff_write_shuffle (abfd, swap, ainfo->pdr, space)
|
||||
|| ! ecoff_write_shuffle (abfd, swap, ainfo->sym, space)
|
||||
|| ! ecoff_write_shuffle (abfd, swap, ainfo->opt, space)
|
||||
|| ! ecoff_write_shuffle (abfd, swap, ainfo->aux, space))
|
||||
return false;
|
||||
goto error_return;
|
||||
|
||||
/* The string table is written out from the hash table if this is a
|
||||
final link. */
|
||||
|
@ -1419,7 +1482,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
{
|
||||
BFD_ASSERT (ainfo->ss_hash == (struct string_hash_entry *) NULL);
|
||||
if (! ecoff_write_shuffle (abfd, swap, ainfo->ss, space))
|
||||
return false;
|
||||
goto error_return;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1430,7 +1493,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
BFD_ASSERT (ainfo->ss == (struct shuffle *) NULL);
|
||||
null = 0;
|
||||
if (bfd_write ((PTR) &null, 1, 1, abfd) != 1)
|
||||
return false;
|
||||
goto error_return;
|
||||
total = 1;
|
||||
BFD_ASSERT (ainfo->ss_hash == NULL || ainfo->ss_hash->val == 1);
|
||||
for (sh = ainfo->ss_hash;
|
||||
|
@ -1441,7 +1504,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
|
||||
len = strlen (sh->root.string);
|
||||
if (bfd_write ((PTR) sh->root.string, 1, len + 1, abfd) != len + 1)
|
||||
return false;
|
||||
goto error_return;
|
||||
total += len + 1;
|
||||
}
|
||||
|
||||
|
@ -1451,10 +1514,19 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
bfd_byte *s;
|
||||
|
||||
i = swap->debug_align - (total & (swap->debug_align - 1));
|
||||
s = (bfd_byte *) alloca (i);
|
||||
s = (bfd_byte *) malloc (i);
|
||||
if (s == NULL && i != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
memset ((PTR) s, 0, i);
|
||||
if (bfd_write ((PTR) s, 1, i, abfd) != i)
|
||||
return false;
|
||||
{
|
||||
free (s);
|
||||
goto error_return;
|
||||
}
|
||||
free (s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1462,7 +1534,7 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
shuffles. FIXME: They probably should be. */
|
||||
if (bfd_write (debug->ssext, 1, debug->symbolic_header.issExtMax, abfd)
|
||||
!= debug->symbolic_header.issExtMax)
|
||||
return false;
|
||||
goto error_return;
|
||||
if ((debug->symbolic_header.issExtMax & (swap->debug_align - 1)) != 0)
|
||||
{
|
||||
int i;
|
||||
|
@ -1470,15 +1542,24 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
|
||||
i = (swap->debug_align
|
||||
- (debug->symbolic_header.issExtMax & (swap->debug_align - 1)));
|
||||
s = (bfd_byte *) alloca (i);
|
||||
s = (bfd_byte *) malloc (i);
|
||||
if (s == NULL && i != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
memset ((PTR) s, 0, i);
|
||||
if (bfd_write ((PTR) s, 1, i, abfd) != i)
|
||||
return false;
|
||||
{
|
||||
free (s);
|
||||
goto error_return;
|
||||
}
|
||||
free (s);
|
||||
}
|
||||
|
||||
if (! ecoff_write_shuffle (abfd, swap, ainfo->fdr, space)
|
||||
|| ! ecoff_write_shuffle (abfd, swap, ainfo->rfd, space))
|
||||
return false;
|
||||
goto error_return;
|
||||
|
||||
BFD_ASSERT (debug->symbolic_header.cbExtOffset == 0
|
||||
|| debug->symbolic_header.cbExtOffset == bfd_tell (abfd));
|
||||
|
@ -1486,7 +1567,14 @@ bfd_ecoff_write_accumulated_debug (handle, abfd, debug, swap, info, where)
|
|||
if (bfd_write (debug->external_ext, swap->external_ext_size,
|
||||
debug->symbolic_header.iextMax, abfd)
|
||||
!= debug->symbolic_header.iextMax * swap->external_ext_size)
|
||||
return false;
|
||||
goto error_return;
|
||||
|
||||
if (space != NULL)
|
||||
free (space);
|
||||
return true;
|
||||
|
||||
error_return:
|
||||
if (space != NULL)
|
||||
free (space);
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1028,16 +1028,21 @@ mips_elf_read_ecoff_info (abfd, section, debug)
|
|||
{
|
||||
HDRR *symhdr;
|
||||
const struct ecoff_debug_swap *swap;
|
||||
char *ext_hdr;
|
||||
char *ext_hdr = NULL;
|
||||
|
||||
swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
|
||||
|
||||
ext_hdr = (char *) alloca (swap->external_hdr_size);
|
||||
ext_hdr = (char *) malloc (swap->external_hdr_size);
|
||||
if (ext_hdr == NULL && swap->external_hdr_size != 0)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
if (bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0,
|
||||
swap->external_hdr_size)
|
||||
== false)
|
||||
return false;
|
||||
goto error_return;
|
||||
|
||||
symhdr = &debug->symbolic_header;
|
||||
(*swap->swap_hdr_in) (abfd, ext_hdr, symhdr);
|
||||
|
@ -1052,13 +1057,13 @@ mips_elf_read_ecoff_info (abfd, section, debug)
|
|||
debug->ptr = (type) malloc (size * symhdr->count); \
|
||||
if (debug->ptr == NULL) \
|
||||
{ \
|
||||
bfd_error = no_memory; \
|
||||
return false; \
|
||||
bfd_set_error (bfd_error_no_memory); \
|
||||
goto error_return; \
|
||||
} \
|
||||
if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \
|
||||
|| (bfd_read (debug->ptr, size, symhdr->count, \
|
||||
abfd) != size * symhdr->count)) \
|
||||
return false; \
|
||||
goto error_return; \
|
||||
}
|
||||
|
||||
READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR);
|
||||
|
@ -1075,8 +1080,36 @@ mips_elf_read_ecoff_info (abfd, section, debug)
|
|||
READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
|
||||
|
||||
debug->fdr = NULL;
|
||||
debug->adjust = NULL;
|
||||
|
||||
return true;
|
||||
|
||||
error_return:
|
||||
if (ext_hdr != NULL)
|
||||
free (ext_hdr);
|
||||
if (debug->external_ext != NULL)
|
||||
free (debug->external_ext);
|
||||
if (debug->line != NULL)
|
||||
free (debug->line);
|
||||
if (debug->external_dnr != NULL)
|
||||
free (debug->external_dnr);
|
||||
if (debug->external_pdr != NULL)
|
||||
free (debug->external_pdr);
|
||||
if (debug->external_sym != NULL)
|
||||
free (debug->external_sym);
|
||||
if (debug->external_opt != NULL)
|
||||
free (debug->external_opt);
|
||||
if (debug->external_aux != NULL)
|
||||
free (debug->external_aux);
|
||||
if (debug->ss != NULL)
|
||||
free (debug->ss);
|
||||
if (debug->ssext != NULL)
|
||||
free (debug->ssext);
|
||||
if (debug->external_fdr != NULL)
|
||||
free (debug->external_fdr);
|
||||
if (debug->external_rfd != NULL)
|
||||
free (debug->external_rfd);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get EXTR information for a symbol. */
|
||||
|
@ -1301,10 +1334,6 @@ mips_elf_final_link (abfd, info)
|
|||
if (p->type != bfd_indirect_link_order)
|
||||
continue;
|
||||
|
||||
#ifndef alloca
|
||||
alloca (0);
|
||||
#endif
|
||||
|
||||
input_section = p->u.indirect.section;
|
||||
input_bfd = input_section->owner;
|
||||
|
||||
|
@ -1433,7 +1462,10 @@ mips_elf_final_link (abfd, info)
|
|||
p != (struct bfd_link_order *) NULL;
|
||||
p = p->next)
|
||||
{
|
||||
if (p->type == bfd_indirect_link_order)
|
||||
if (p->type == bfd_section_reloc_link_order
|
||||
|| p->type == bfd_symbol_reloc_link_order)
|
||||
++o->reloc_count;
|
||||
else if (p->type == bfd_indirect_link_order)
|
||||
{
|
||||
asection *input_section;
|
||||
bfd *input_bfd;
|
||||
|
@ -1446,9 +1478,9 @@ mips_elf_final_link (abfd, info)
|
|||
relsize = bfd_get_reloc_upper_bound (input_bfd,
|
||||
input_section);
|
||||
relocs = (arelent **) malloc (relsize);
|
||||
if (!relocs)
|
||||
if (!relocs && relsize != 0)
|
||||
{
|
||||
bfd_error = no_memory;
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return false;
|
||||
}
|
||||
reloc_count =
|
||||
|
@ -1468,9 +1500,10 @@ mips_elf_final_link (abfd, info)
|
|||
* sizeof (arelent *))));
|
||||
if (!o->orelocation)
|
||||
{
|
||||
bfd_error = no_memory;
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return false;
|
||||
}
|
||||
o->flags |= SEC_RELOC;
|
||||
/* Reset the count so that it can be used as an index
|
||||
when putting in the output relocs. */
|
||||
o->reloc_count = 0;
|
||||
|
@ -1515,8 +1548,18 @@ mips_elf_final_link (abfd, info)
|
|||
p != (struct bfd_link_order *) NULL;
|
||||
p = p->next)
|
||||
{
|
||||
if (! _bfd_default_link_order (abfd, info, o, p))
|
||||
return false;
|
||||
switch (p->type)
|
||||
{
|
||||
case bfd_section_reloc_link_order:
|
||||
case bfd_symbol_reloc_link_order:
|
||||
if (! _bfd_generic_reloc_link_order (abfd, info, o, p))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
if (! _bfd_default_link_order (abfd, info, o, p))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1661,6 +1704,7 @@ static const struct ecoff_debug_swap mips_elf_ecoff_debug_swap =
|
|||
mips_elf_final_write_processing
|
||||
#define elf_backend_ecoff_debug_swap &mips_elf_ecoff_debug_swap
|
||||
|
||||
#define bfd_elf32_bfd_link_add_symbols _bfd_generic_link_add_symbols_collect
|
||||
#define bfd_elf32_bfd_final_link mips_elf_final_link
|
||||
|
||||
#include "elf32-target.h"
|
||||
|
|
213
bfd/libecoff.h
213
bfd/libecoff.h
|
@ -18,65 +18,56 @@ 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. */
|
||||
|
||||
/* This is the backend information kept for ECOFF files. This
|
||||
structure is constant for a particular backend. ECOFF already
|
||||
keeps a bfd_coff_backend_data structure in the bfd_target
|
||||
backend_data field, so a pointer to this backend structure is kept
|
||||
in the tdata field. */
|
||||
#include "bfdlink.h"
|
||||
|
||||
#define ecoff_backend(abfd) (ecoff_data (abfd)->backend_data)
|
||||
#ifndef ECOFF_H
|
||||
#include "coff/ecoff.h"
|
||||
#endif
|
||||
|
||||
/* This is the backend information kept for ECOFF files. This
|
||||
structure is constant for a particular backend. The first element
|
||||
is the COFF backend data structure, so that ECOFF targets can use
|
||||
the generic COFF code. */
|
||||
|
||||
#define ecoff_backend(abfd) \
|
||||
((struct ecoff_backend_data *) (abfd)->xvec->backend_data)
|
||||
|
||||
struct ecoff_backend_data
|
||||
{
|
||||
/* COFF backend information. This must be the first field. */
|
||||
bfd_coff_backend_data coff;
|
||||
/* Supported architecture. */
|
||||
enum bfd_architecture arch;
|
||||
/* Big endian magic number. */
|
||||
int big_magic;
|
||||
/* Little endian magic number. */
|
||||
int little_magic;
|
||||
/* Alignment of debugging information. E.g., 4. */
|
||||
bfd_size_type debug_align;
|
||||
/* Initial portion of armap string. */
|
||||
const char *armap_start;
|
||||
/* The page boundary used to align sections in a demand-paged
|
||||
executable file. E.g., 0x1000. */
|
||||
bfd_vma round;
|
||||
/* True if the .rdata section is part of the text segment, as on the
|
||||
Alpha. False if .rdata is part of the data segment, as on the
|
||||
MIPS. */
|
||||
boolean rdata_in_text;
|
||||
/* Bitsize of constructor entries. */
|
||||
unsigned int constructor_bitsize;
|
||||
/* Sizes of external symbolic information. */
|
||||
bfd_size_type external_hdr_size;
|
||||
bfd_size_type external_dnr_size;
|
||||
bfd_size_type external_pdr_size;
|
||||
bfd_size_type external_sym_size;
|
||||
bfd_size_type external_opt_size;
|
||||
bfd_size_type external_fdr_size;
|
||||
bfd_size_type external_rfd_size;
|
||||
bfd_size_type external_ext_size;
|
||||
/* Functions to swap in external symbolic data. */
|
||||
void (*swap_hdr_in) PARAMS ((bfd *, PTR, HDRR *));
|
||||
void (*swap_dnr_in) PARAMS ((bfd *, PTR, DNR *));
|
||||
void (*swap_pdr_in) PARAMS ((bfd *, PTR, PDR *));
|
||||
void (*swap_sym_in) PARAMS ((bfd *, PTR, SYMR *));
|
||||
void (*swap_opt_in) PARAMS ((bfd *, PTR, OPTR *));
|
||||
void (*swap_fdr_in) PARAMS ((bfd *, PTR, FDR *));
|
||||
void (*swap_rfd_in) PARAMS ((bfd *, PTR, RFDT *));
|
||||
void (*swap_ext_in) PARAMS ((bfd *, PTR, EXTR *));
|
||||
/* Functions to swap out external symbolic data. */
|
||||
void (*swap_hdr_out) PARAMS ((bfd *, const HDRR *, PTR));
|
||||
void (*swap_dnr_out) PARAMS ((bfd *, const DNR *, PTR));
|
||||
void (*swap_pdr_out) PARAMS ((bfd *, const PDR *, PTR));
|
||||
void (*swap_sym_out) PARAMS ((bfd *, const SYMR *, PTR));
|
||||
void (*swap_opt_out) PARAMS ((bfd *, const OPTR *, PTR));
|
||||
void (*swap_fdr_out) PARAMS ((bfd *, const FDR *, PTR));
|
||||
void (*swap_rfd_out) PARAMS ((bfd *, const RFDT *, PTR));
|
||||
void (*swap_ext_out) PARAMS ((bfd *, const EXTR *, PTR));
|
||||
/* It so happens that the auxiliary type information has the same
|
||||
type and format for all known ECOFF targets. I don't see any
|
||||
reason that that should change, so at least for now the auxiliary
|
||||
swapping information is not in this table. */
|
||||
/* Reloc to use for constructor entries. */
|
||||
CONST struct reloc_howto_struct *constructor_reloc;
|
||||
/* How to swap debugging information. */
|
||||
struct ecoff_debug_swap debug_swap;
|
||||
/* External reloc size. */
|
||||
bfd_size_type external_reloc_size;
|
||||
/* Reloc swapping functions. */
|
||||
void (*swap_reloc_in) PARAMS ((bfd *, PTR, struct internal_reloc *));
|
||||
void (*swap_reloc_out) PARAMS ((bfd *, const struct internal_reloc *, PTR));
|
||||
/* Backend reloc tweaking. */
|
||||
void (*adjust_reloc_in) PARAMS ((bfd *, const struct internal_reloc *,
|
||||
arelent *));
|
||||
void (*adjust_reloc_out) PARAMS ((bfd *, const arelent *,
|
||||
struct internal_reloc *));
|
||||
/* Relocate section contents while linking. */
|
||||
boolean (*relocate_section) PARAMS ((bfd *output_bfd, struct bfd_link_info *,
|
||||
bfd *input_bfd, asection *input_section,
|
||||
bfd_byte *contents,
|
||||
PTR external_relocs));
|
||||
};
|
||||
|
||||
/* This is the target specific information kept for ECOFF files. */
|
||||
|
@ -85,9 +76,6 @@ struct ecoff_backend_data
|
|||
|
||||
typedef struct ecoff_tdata
|
||||
{
|
||||
/* Constant backend information. */
|
||||
const struct ecoff_backend_data *backend_data;
|
||||
|
||||
/* The reloc file position, set by
|
||||
ecoff_compute_section_file_positions. */
|
||||
file_ptr reloc_filepos;
|
||||
|
@ -109,42 +97,30 @@ typedef struct ecoff_tdata
|
|||
int gp_size;
|
||||
|
||||
/* The register masks. When linking, all the masks found in the
|
||||
input files are combined into the masks of the output file. */
|
||||
input files are combined into the masks of the output file.
|
||||
These are not all used for all targets, but that's OK, because
|
||||
the relevant ones are the only ones swapped in and out. */
|
||||
unsigned long gprmask;
|
||||
unsigned long fprmask;
|
||||
unsigned long cprmask[4];
|
||||
|
||||
/* The size of the unswapped ECOFF symbolic information. */
|
||||
bfd_size_type raw_size;
|
||||
/* The ECOFF symbolic debugging information. */
|
||||
struct ecoff_debug_info debug_info;
|
||||
|
||||
/* The unswapped ECOFF symbolic information. */
|
||||
PTR raw_syments;
|
||||
|
||||
/* The swapped ECOFF symbolic header. */
|
||||
HDRR symbolic_header;
|
||||
|
||||
/* Pointers to the unswapped symbolic information. */
|
||||
unsigned char *line;
|
||||
PTR external_dnr; /* struct dnr_ext */
|
||||
PTR external_pdr; /* struct pdr_ext */
|
||||
PTR external_sym; /* struct sym_ext */
|
||||
PTR external_opt; /* struct opt_ext */
|
||||
union aux_ext *external_aux;
|
||||
char *ss;
|
||||
char *ssext;
|
||||
PTR external_fdr; /* struct fdr_ext */
|
||||
PTR external_rfd; /* struct rfd_ext */
|
||||
PTR external_ext; /* struct ext_ext */
|
||||
|
||||
/* The swapped FDR information. */
|
||||
FDR *fdr;
|
||||
|
||||
/* The FDR index. This is set for an input BFD to a link so that
|
||||
the external symbols can set their FDR index correctly. */
|
||||
unsigned int ifdbase;
|
||||
|
||||
/* The canonical BFD symbols. */
|
||||
struct ecoff_symbol_struct *canonical_symbols;
|
||||
|
||||
/* A mapping from external symbol numbers to entries in the linker
|
||||
hash table, used when linking. */
|
||||
struct ecoff_link_hash_entry **sym_hashes;
|
||||
|
||||
/* A mapping from reloc symbol indices to sections, used when
|
||||
linking. */
|
||||
asection **symndx_to_section;
|
||||
|
||||
} ecoff_data_type;
|
||||
|
||||
/* Each canonical asymbol really looks like this. */
|
||||
|
@ -176,13 +152,71 @@ typedef struct ecoff_symbol_struct
|
|||
#define ecoff_get_sym_index(symbol) ((unsigned long) (symbol)->udata)
|
||||
#define ecoff_set_sym_index(symbol, idx) ((symbol)->udata = (PTR) (idx))
|
||||
|
||||
/* Make an empty ECOFF symbol. */
|
||||
extern asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd));
|
||||
/* When generating MIPS embedded PIC code, the linker relaxes the code
|
||||
to turn PC relative branches into longer code sequences when the PC
|
||||
relative branch is out of range. This involves reading the relocs
|
||||
in bfd_relax_section as well as in bfd_final_link, and requires the
|
||||
code to keep track of which relocs have been expanded. A pointer
|
||||
to this structure is put in the used_by_bfd pointer of a section to
|
||||
keep track of this information. The user_by_bfd pointer will be
|
||||
NULL if the information was not needed. */
|
||||
|
||||
struct ecoff_section_tdata
|
||||
{
|
||||
/* The unswapped relocs for this section. These are stored in
|
||||
memory so the input file does not have to be read twice. */
|
||||
PTR external_relocs;
|
||||
|
||||
/* The contents of the section. These bytes may or may not be saved
|
||||
in memory, but if it is this is a pointer to them. */
|
||||
bfd_byte *contents;
|
||||
|
||||
/* Offset adjustments for PC relative branches. A number other than
|
||||
1 is an addend for a PC relative branch; this addend arises because
|
||||
it crosses one or more branches which were expanded into a larger
|
||||
code sequence. A 1 means that this branch was itself expanded into
|
||||
a larger code sequence. 1 is not a possible offset, since all
|
||||
offsets must be multiples of the instruction size, which is 4;
|
||||
also, the only relocs with non-zero offsets will be PC relative
|
||||
branches within the same object file. If this field is NULL, no
|
||||
branches were expanded and no offsets are required. Otherwise
|
||||
there are as many entries as there are relocs in the section, and
|
||||
the entry for any reloc that is not PC relative is zero. */
|
||||
long *offsets;
|
||||
};
|
||||
|
||||
/* An accessor macro for the ecoff_section_tdata structure. */
|
||||
#define ecoff_section_data(abfd, sec) \
|
||||
((struct ecoff_section_tdata *) (sec)->used_by_bfd)
|
||||
|
||||
/* ECOFF linker hash table entries. */
|
||||
|
||||
struct ecoff_link_hash_entry
|
||||
{
|
||||
struct bfd_link_hash_entry root;
|
||||
/* Symbol index in output file. */
|
||||
long indx;
|
||||
/* BFD that ext field value came from. */
|
||||
bfd *abfd;
|
||||
/* ECOFF external symbol information. */
|
||||
EXTR esym;
|
||||
};
|
||||
|
||||
/* ECOFF linker hash table. */
|
||||
|
||||
struct ecoff_link_hash_table
|
||||
{
|
||||
struct bfd_link_hash_table root;
|
||||
};
|
||||
|
||||
/* Make an ECOFF object. */
|
||||
extern boolean ecoff_mkobject PARAMS ((bfd *));
|
||||
|
||||
/* Read in the ECOFF symbolic debugging information. */
|
||||
extern boolean ecoff_slurp_symbolic_info PARAMS ((bfd *));
|
||||
|
||||
/* Generic ECOFF BFD backend vectors. */
|
||||
extern asymbol *ecoff_make_empty_symbol PARAMS ((bfd *abfd));
|
||||
extern unsigned int ecoff_get_symtab_upper_bound PARAMS ((bfd *abfd));
|
||||
extern unsigned int ecoff_get_symtab PARAMS ((bfd *abfd,
|
||||
asymbol **alocation));
|
||||
|
@ -196,8 +230,6 @@ extern unsigned int ecoff_canonicalize_reloc PARAMS ((bfd *abfd,
|
|||
asection *section,
|
||||
arelent **relptr,
|
||||
asymbol **symbols));
|
||||
extern CONST struct reloc_howto_struct *ecoff_bfd_reloc_type_lookup
|
||||
PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
|
||||
extern boolean ecoff_find_nearest_line PARAMS ((bfd *abfd,
|
||||
asection *section,
|
||||
asymbol **symbols,
|
||||
|
@ -205,8 +237,6 @@ extern boolean ecoff_find_nearest_line PARAMS ((bfd *abfd,
|
|||
CONST char **filename_ptr,
|
||||
CONST char **fnname_ptr,
|
||||
unsigned int *retline_ptr));
|
||||
extern boolean ecoff_bfd_seclet_link PARAMS ((bfd *abfd, PTR data,
|
||||
boolean relocateable));
|
||||
extern boolean ecoff_set_arch_mach PARAMS ((bfd *abfd,
|
||||
enum bfd_architecture arch,
|
||||
unsigned long machine));
|
||||
|
@ -216,6 +246,11 @@ extern boolean ecoff_set_section_contents PARAMS ((bfd *abfd,
|
|||
PTR location,
|
||||
file_ptr offset,
|
||||
bfd_size_type count));
|
||||
extern boolean ecoff_get_section_contents PARAMS ((bfd *abfd,
|
||||
asection *section,
|
||||
PTR location,
|
||||
file_ptr offset,
|
||||
bfd_size_type count));
|
||||
extern boolean ecoff_write_object_contents PARAMS ((bfd *abfd));
|
||||
extern boolean ecoff_slurp_armap PARAMS ((bfd *abfd));
|
||||
extern boolean ecoff_write_armap PARAMS ((bfd *abfd, unsigned int elength,
|
||||
|
@ -229,20 +264,34 @@ extern bfd_target *ecoff_archive_p PARAMS ((bfd *abfd));
|
|||
#define ecoff_truncate_arname bfd_dont_truncate_arname
|
||||
#define ecoff_openr_next_archived_file bfd_generic_openr_next_archived_file
|
||||
#define ecoff_generic_stat_arch_elt bfd_generic_stat_arch_elt
|
||||
#define ecoff_get_section_contents bfd_generic_get_section_contents
|
||||
#define ecoff_get_reloc_upper_bound coff_get_reloc_upper_bound
|
||||
#define ecoff_close_and_cleanup bfd_generic_close_and_cleanup
|
||||
#define ecoff_bfd_debug_info_start bfd_void
|
||||
#define ecoff_bfd_debug_info_end bfd_void
|
||||
#define ecoff_bfd_debug_info_accumulate \
|
||||
((void (*) PARAMS ((bfd *, struct sec *))) bfd_void)
|
||||
#define ecoff_bfd_get_relocated_section_contents \
|
||||
bfd_generic_get_relocated_section_contents
|
||||
#define ecoff_bfd_relax_section bfd_generic_relax_section
|
||||
#define ecoff_bfd_make_debug_symbol \
|
||||
((asymbol *(*) PARAMS ((bfd *, void *, unsigned long))) bfd_nullvoidptr)
|
||||
extern struct bfd_link_hash_table *ecoff_bfd_link_hash_table_create
|
||||
PARAMS ((bfd *));
|
||||
extern boolean ecoff_bfd_link_add_symbols
|
||||
PARAMS ((bfd *, struct bfd_link_info *));
|
||||
extern boolean ecoff_bfd_final_link PARAMS ((bfd *, struct bfd_link_info *));
|
||||
|
||||
#ifndef ecoff_bfd_copy_private_section_data
|
||||
#define ecoff_bfd_copy_private_section_data \
|
||||
((boolean (*) PARAMS ((bfd *, asection *, bfd *, asection *))) bfd_true)
|
||||
#endif
|
||||
#ifndef ecoff_bfd_copy_private_bfd_data
|
||||
#define ecoff_bfd_copy_private_bfd_data \
|
||||
((boolean (*) PARAMS ((bfd *, bfd *))) bfd_true)
|
||||
#endif
|
||||
#ifndef ecoff_bfd_is_local_label
|
||||
#define ecoff_bfd_is_local_label bfd_generic_is_local_label
|
||||
#endif
|
||||
|
||||
/* Hook functions for the generic COFF section reading code. */
|
||||
extern PTR ecoff_mkobject_hook PARAMS ((bfd *, PTR filehdr, PTR aouthdr));
|
||||
extern asection *ecoff_make_section_hook PARAMS ((bfd *abfd, char *name));
|
||||
extern boolean ecoff_new_section_hook PARAMS ((bfd *abfd,
|
||||
asection *section));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue