aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1994-03-25 22:37:55 +0000
committerIan Lance Taylor <ian@airs.com>1994-03-25 22:37:55 +0000
commita3a33af390c3a99e00b20847a102e307cfb538c7 (patch)
treeb262eb6f85a5b10fe60cdc47a0f753178e889283
parentf078dc7cf26a816ef0bb66be8b819ac549486e86 (diff)
downloadgdb-a3a33af390c3a99e00b20847a102e307cfb538c7.zip
gdb-a3a33af390c3a99e00b20847a102e307cfb538c7.tar.gz
gdb-a3a33af390c3a99e00b20847a102e307cfb538c7.tar.bz2
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.
-rw-r--r--bfd/ChangeLog30
-rw-r--r--bfd/coff-alpha.c44
-rw-r--r--bfd/coff-mips.c558
-rw-r--r--bfd/ecoff.c420
-rw-r--r--bfd/ecofflink.c128
-rw-r--r--bfd/elf32-mips.c76
-rw-r--r--bfd/libecoff.h211
7 files changed, 1247 insertions, 220 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog
index 528f826..7e657fd 100644
--- a/bfd/ChangeLog
+++ b/bfd/ChangeLog
@@ -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.
diff --git a/bfd/coff-alpha.c b/bfd/coff-alpha.c
index 64ab840..4353078 100644
--- a/bfd/coff-alpha.c
+++ b/bfd/coff-alpha.c
@@ -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 */
diff --git a/bfd/coff-mips.c b/bfd/coff-mips.c
index a9a95e5..71a0cd5 100644
--- a/bfd/coff-mips.c
+++ b/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
diff --git a/bfd/ecoff.c b/bfd/ecoff.c
index 745d46a..5665a99 100644
--- a/bfd/ecoff.c
+++ b/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);
-
- /* 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;
+ 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
+ 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);
-
- /* Get the section contents. */
- input_size = bfd_section_size (input_bfd, input_section);
- contents = (bfd_byte *) malloc (input_size);
- if (contents == NULL)
+ BFD_ASSERT (cooked_size == link_order->size);
+
+ /* 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)
+
+ if (section_tdata != (struct ecoff_section_tdata *) NULL)
+ external_relocs = section_tdata->external_relocs;
+ else
{
- bfd_set_error (bfd_error_no_memory);
- goto error_return;
- }
+ 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;
+ 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;
+}
diff --git a/bfd/ecofflink.c b/bfd/ecofflink.c
index a4507ea..4b14dcd 100644
--- a/bfd/ecofflink.c
+++ b/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;
}
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index 57734bc..15debf8 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -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"
diff --git a/bfd/libecoff.h b/bfd/libecoff.h
index 74361c5..f0f3a11 100644
--- a/bfd/libecoff.h
+++ b/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. */
+#include "bfdlink.h"
+
+#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. 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. */
+ 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) (ecoff_data (abfd)->backend_data)
+#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));