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:
Ian Lance Taylor 1994-03-25 22:37:55 +00:00
parent f078dc7cf2
commit a3a33af390
7 changed files with 1247 additions and 220 deletions

View file

@ -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.

View file

@ -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 */

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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"

View file

@ -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));