aboutsummaryrefslogtreecommitdiff
path: root/bfd
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@airs.com>1994-01-06 20:01:42 +0000
committerIan Lance Taylor <ian@airs.com>1994-01-06 20:01:42 +0000
commit6e07e54f1b347f885cc6c021c3fd912c79bdaf55 (patch)
treee1340a7ec9dff41a85458d9111e59250258182fa /bfd
parenteae04238574c99672f29fbe7e5fb88d41087a3ea (diff)
downloadfsf-binutils-gdb-6e07e54f1b347f885cc6c021c3fd912c79bdaf55.zip
fsf-binutils-gdb-6e07e54f1b347f885cc6c021c3fd912c79bdaf55.tar.gz
fsf-binutils-gdb-6e07e54f1b347f885cc6c021c3fd912c79bdaf55.tar.bz2
* linker.c (_bfd_generic_link_add_one_symbol): Add constructor and
bitsize arguments. Changed all callers (aoutx.h). (default_indirect_link_order): Renamed from _bfd_generic_indirect_link_order and made static. (_bfd_generic_final_link): Don't switch on link_order type, just call _bfd_default_link_order. (_bfd_default_link_order): Handle bfd_indirect_link_order type. * genlink.h: Removed declaration of _bfd_generic_indirect_link_order. * elf32-mips.c (mips_elf_final_link): Don't switch on link_order type, just call _bfd_default_link_order.
Diffstat (limited to 'bfd')
-rw-r--r--bfd/elf32-mips.c778
-rw-r--r--bfd/linker.c196
2 files changed, 831 insertions, 143 deletions
diff --git a/bfd/elf32-mips.c b/bfd/elf32-mips.c
index c56df38..585187a 100644
--- a/bfd/elf32-mips.c
+++ b/bfd/elf32-mips.c
@@ -23,28 +23,48 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "bfd.h"
#include "sysdep.h"
#include "libbfd.h"
-#include "seclet.h"
+#include "bfdlink.h"
+#include "genlink.h"
#include "libelf.h"
#include "elf/mips.h"
+/* Get the ECOFF swapping routines. */
+#include "coff/sym.h"
+#include "coff/symconst.h"
+#include "coff/internal.h"
+#include "coff/ecoff.h"
+#include "coff/mips.h"
+#define ECOFF_32
+#include "ecoffswap.h"
+
static bfd_reloc_status_type mips_elf_hi16_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
- bfd *output_bfd));
+ bfd *output_bfd,
+ char **error));
+static bfd_reloc_status_type mips_elf_got16_reloc PARAMS ((bfd *abfd,
+ arelent *reloc,
+ asymbol *symbol,
+ PTR data,
+ asection *section,
+ bfd *output_bfd,
+ char **error));
static bfd_reloc_status_type mips_elf_lo16_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
- bfd *output_bfd));
+ bfd *output_bfd,
+ char **error));
static bfd_reloc_status_type mips_elf_gprel16_reloc PARAMS ((bfd *abfd,
arelent *reloc,
asymbol *symbol,
PTR data,
asection *section,
- bfd *output_bfd));
+ bfd *output_bfd,
+ char **error));
#define USE_REL 1 /* MIPS uses REL relocations instead of RELA */
@@ -129,7 +149,10 @@ static reloc_howto_type elf_mips_howto_table[] =
26, /* bitsize */
false, /* pc_relative */
0, /* bitpos */
- complain_overflow_bitfield, /* complain_on_overflow */
+ complain_overflow_dont, /* complain_on_overflow */
+ /* This needs complex overflow
+ detection, because the upper four
+ bits must match the PC. */
bfd_elf_generic_reloc, /* special_function */
"R_MIPS_26", /* name */
true, /* partial_inplace */
@@ -206,7 +229,7 @@ static reloc_howto_type elf_mips_howto_table[] =
false, /* pc_relative */
0, /* bitpos */
complain_overflow_signed, /* complain_on_overflow */
- bfd_elf_generic_reloc, /* special_function */
+ mips_elf_got16_reloc, /* special_function */
"R_MIPS_GOT16", /* name */
false, /* partial_inplace */
0, /* src_mask */
@@ -276,22 +299,19 @@ mips_elf_hi16_reloc (abfd,
symbol,
data,
input_section,
- output_bfd)
+ output_bfd,
+ error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
PTR data;
asection *input_section;
bfd *output_bfd;
+ char **error_message;
{
bfd_reloc_status_type ret;
bfd_vma relocation;
- /* FIXME: The symbol _gp_disp requires special handling, which we do
- not do. */
- if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0)
- abort ();
-
/* If we're relocating, and this an external symbol, we don't want
to change anything. */
if (output_bfd != (bfd *) NULL
@@ -302,6 +322,11 @@ mips_elf_hi16_reloc (abfd,
return bfd_reloc_ok;
}
+ /* FIXME: The symbol _gp_disp requires special handling, which we do
+ not do. */
+ if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0)
+ abort ();
+
ret = bfd_reloc_ok;
if (symbol->section == &bfd_und_section
&& output_bfd == (bfd *) NULL)
@@ -339,17 +364,20 @@ mips_elf_lo16_reloc (abfd,
symbol,
data,
input_section,
- output_bfd)
+ output_bfd,
+ error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
PTR data;
asection *input_section;
bfd *output_bfd;
+ char **error_message;
{
/* FIXME: The symbol _gp_disp requires special handling, which we do
not do. */
- if (strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0)
+ if (output_bfd == (bfd *) NULL
+ && strcmp (bfd_asymbol_name (symbol), "_gp_disp") == 0)
abort ();
if (mips_hi16_addr != (bfd_byte *) NULL)
@@ -386,7 +414,57 @@ mips_elf_lo16_reloc (abfd,
/* Now do the LO16 reloc in the usual way. */
return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
- input_section, output_bfd);
+ input_section, output_bfd, error_message);
+}
+
+/* Do a R_MIPS_GOT16 reloc. This is a reloc against the global offset
+ table used for PIC code. If the symbol is an external symbol, the
+ instruction is modified to contain the offset of the appropriate
+ entry in the global offset table. If the symbol is a section
+ symbol, the next reloc is a R_MIPS_LO16 reloc. The two 16 bit
+ addends are combined to form the real addend against the section
+ symbol; the GOT16 is modified to contain the offset of an entry in
+ the global offset table, and the LO16 is modified to offset it
+ appropriately. Thus an offset larger than 16 bits requires a
+ modified value in the global offset table.
+
+ This implementation suffices for the assembler, but the linker does
+ not yet know how to create global offset tables. */
+
+static bfd_reloc_status_type
+mips_elf_got16_reloc (abfd,
+ reloc_entry,
+ symbol,
+ data,
+ input_section,
+ output_bfd,
+ error_message)
+ bfd *abfd;
+ arelent *reloc_entry;
+ asymbol *symbol;
+ PTR data;
+ asection *input_section;
+ bfd *output_bfd;
+ char **error_message;
+{
+ /* If we're relocating, and this an external symbol, we don't want
+ to change anything. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) == 0
+ && reloc_entry->addend == 0)
+ {
+ reloc_entry->address += input_section->output_offset;
+ return bfd_reloc_ok;
+ }
+
+ /* If we're relocating, and this is a local symbol, we can handle it
+ just like HI16. */
+ if (output_bfd != (bfd *) NULL
+ && (symbol->flags & BSF_SECTION_SYM) != 0)
+ return mips_elf_hi16_reloc (abfd, reloc_entry, symbol, data,
+ input_section, output_bfd, error_message);
+
+ abort ();
}
/* Do a R_MIPS_GPREL16 relocation. This is a 16 bit value which must
@@ -401,13 +479,15 @@ mips_elf_gprel16_reloc (abfd,
symbol,
data,
input_section,
- output_bfd)
+ output_bfd,
+ error_message)
bfd *abfd;
arelent *reloc_entry;
asymbol *symbol;
PTR data;
asection *input_section;
bfd *output_bfd;
+ char **error_message;
{
boolean relocateable;
bfd_vma relocation;
@@ -483,9 +563,8 @@ mips_elf_gprel16_reloc (abfd,
{
/* Only get the error once. */
elf_gp (output_bfd) = 4;
- /* FIXME: How can we get the program name here? */
- fprintf (stderr,
- "GP relative relocation when _gp not defined\n");
+ *error_message =
+ (char *) "GP relative relocation when _gp not defined";
return bfd_reloc_dangerous;
}
}
@@ -524,7 +603,7 @@ mips_elf_gprel16_reloc (abfd,
/* Make sure it fit in 16 bits. */
if (val >= 0x8000 && val < 0xffff8000)
- return bfd_reloc_outofrange;
+ return bfd_reloc_overflow;
return bfd_reloc_ok;
}
@@ -633,6 +712,78 @@ bfd_mips_elf32_swap_reginfo_out (abfd, in, ex)
(bfd_byte *) ex->ri_gp_value);
}
+/* Determine whether a symbol is global for the purposes of splitting
+ the symbol table into global symbols and local symbols. At least
+ on Irix 5, this split must be between section symbols and all other
+ symbols. On most ELF targets the split is between static symbols
+ and externally visible symbols. */
+
+/*ARGSUSED*/
+static boolean
+mips_elf_sym_is_global (abfd, sym)
+ bfd *abfd;
+ asymbol *sym;
+{
+ return (sym->flags & BSF_SECTION_SYM) == 0 ? true : false;
+}
+
+/* Set the right machine number for a MIPS ELF file. */
+
+static boolean
+mips_elf_object_p (abfd)
+ bfd *abfd;
+{
+ switch (elf_elfheader (abfd)->e_flags & EF_MIPS_ARCH)
+ {
+ default:
+ case E_MIPS_ARCH_1:
+ /* Just use the default, which was set in elfcode.h. */
+ break;
+
+ case E_MIPS_ARCH_2:
+ (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 6000);
+ break;
+
+ case E_MIPS_ARCH_3:
+ (void) bfd_default_set_arch_mach (abfd, bfd_arch_mips, 4000);
+ break;
+ }
+
+ return true;
+}
+
+/* The final processing done just before writing out a MIPS ELF object
+ file. This gets the MIPS architecture right based on the machine
+ number. */
+
+static void
+mips_elf_final_write_processing (abfd)
+ bfd *abfd;
+{
+ unsigned long val;
+
+ switch (bfd_get_mach (abfd))
+ {
+ case 3000:
+ val = E_MIPS_ARCH_1;
+ break;
+
+ case 6000:
+ val = E_MIPS_ARCH_2;
+ break;
+
+ case 4000:
+ val = E_MIPS_ARCH_3;
+ break;
+
+ default:
+ return;
+ }
+
+ elf_elfheader (abfd)->e_flags &=~ EF_MIPS_ARCH;
+ elf_elfheader (abfd)->e_flags |= val;
+}
+
/* Handle a MIPS specific section when reading an object file. This
is called when elfcode.h finds a section with an unknown type.
FIXME: We need to handle the SHF_MIPS_GPREL flag, but I'm not sure
@@ -676,6 +827,10 @@ mips_elf_section_from_shdr (abfd, hdr, name)
|| hdr->sh_size != sizeof (Elf32_External_RegInfo))
return false;
break;
+ case SHT_MIPS_OPTIONS:
+ if (strcmp (name, ".options") != 0)
+ return false;
+ break;
default:
return false;
}
@@ -768,16 +923,25 @@ mips_elf_fake_sections (abfd, hdr, sec)
else if (strcmp (name, ".ucode") == 0)
hdr->sh_type = SHT_MIPS_UCODE;
else if (strcmp (name, ".mdebug") == 0)
- hdr->sh_type = SHT_MIPS_DEBUG;
+ {
+ hdr->sh_type = SHT_MIPS_DEBUG;
+ hdr->sh_entsize = 1;
+ }
else if (strcmp (name, ".reginfo") == 0)
{
hdr->sh_type = SHT_MIPS_REGINFO;
+ hdr->sh_entsize = 1;
/* Force the section size to the correct value, even if the
linker thinks it is larger. The link routine below will only
write out this much data for .reginfo. */
hdr->sh_size = sec->_raw_size = sizeof (Elf32_External_RegInfo);
}
+ else if (strcmp (name, ".options") == 0)
+ {
+ hdr->sh_type = SHT_MIPS_OPTIONS;
+ hdr->sh_entsize = 1;
+ }
return true;
}
@@ -853,89 +1017,469 @@ mips_elf_section_processing (abfd, hdr)
return true;
}
-/* We need to use a special link routine to handle the .reginfo
- section. We need to merge all the .reginfo sections together, not
- write them all out sequentially. */
+/* Read ECOFF debugging information from a .mdebug section into a
+ ecoff_debug_info structure. */
static boolean
-mips_elf_seclet_link (abfd, data, relocateable)
+mips_elf_read_ecoff_info (abfd, section, debug)
bfd *abfd;
- PTR data;
- boolean relocateable;
+ asection *section;
+ struct ecoff_debug_info *debug;
{
- asection *sec;
+ HDRR *symhdr;
+ const struct ecoff_debug_swap *swap;
+ char *ext_hdr;
+
+ swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
+
+ ext_hdr = (char *) alloca (swap->external_hdr_size);
+
+ if (bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0,
+ swap->external_hdr_size)
+ == false)
+ return false;
+
+ symhdr = &debug->symbolic_header;
+ (*swap->swap_hdr_in) (abfd, ext_hdr, symhdr);
+
+ /* The symbolic header contains absolute file offsets and sizes to
+ read. */
+#define READ(ptr, offset, count, size, type) \
+ if (symhdr->count == 0) \
+ debug->ptr = NULL; \
+ else \
+ { \
+ debug->ptr = (type) malloc (size * symhdr->count); \
+ if (debug->ptr == NULL) \
+ { \
+ bfd_error = no_memory; \
+ return false; \
+ } \
+ if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0 \
+ || (bfd_read (debug->ptr, size, symhdr->count, \
+ abfd) != size * symhdr->count)) \
+ return false; \
+ }
+
+ 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 (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *);
+ READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
+ READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
+ READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR);
+
+ return true;
+}
+
+/* Get EXTR information for a symbol. */
+
+static boolean
+mips_elf_get_extr (sym, esym)
+ asymbol *sym;
+ EXTR *esym;
+{
+ if (sym->flags & BSF_SECTION_SYM)
+ return false;
+
+ if (bfd_asymbol_flavour (sym) != bfd_target_elf_flavour
+ || ((elf_symbol_type *) sym)->tc_data.mips_extr == NULL)
+ {
+ esym->jmptbl = 0;
+ esym->cobol_main = 0;
+ esym->weakext = 0;
+ esym->reserved = 0;
+ esym->ifd = ifdNil;
+ /* FIXME: we can do better than this for st and sc. */
+ esym->asym.st = stGlobal;
+ esym->asym.sc = scAbs;
+ esym->asym.reserved = 0;
+ esym->asym.index = indexNil;
+ return true;
+ }
+
+ *esym = *((elf_symbol_type *) sym)->tc_data.mips_extr;
+
+ return true;
+}
+
+/* Set the symbol index for an external symbol. This is actually not
+ needed for ELF. */
+
+/*ARGSUSED*/
+static void
+mips_elf_set_index (sym, indx)
+ asymbol *sym;
+ bfd_size_type indx;
+{
+}
+
+/* We need to use a special link routine to handle the .reginfo and
+ the .mdebug sections. We need to merge all instances of these
+ sections together, not write them all out sequentially. */
+
+static boolean
+mips_elf_final_link (abfd, info)
+ bfd *abfd;
+ struct bfd_link_info *info;
+{
+ bfd *sub;
+ size_t outsymalloc;
+ struct generic_write_global_symbol_info wginfo;
+ asection **secpp;
+ asection *o;
+ struct bfd_link_order *p;
+ asection *reginfo_sec, *mdebug_sec;
Elf32_RegInfo reginfo;
+ struct ecoff_debug_info debug;
+ const struct ecoff_debug_swap *swap
+ = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
+ HDRR *symhdr = &debug.symbolic_header;
+
+ abfd->outsymbols = (asymbol **) NULL;
+ abfd->symcount = 0;
+ outsymalloc = 0;
+
+ /* Build the output symbol table. This also reads in the symbols
+ for all the input BFDs, keeping them in the outsymbols field. */
+ for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
+ if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
+ return false;
- memset (&reginfo, 0, sizeof reginfo);
+ /* Accumulate the global symbols. */
+ wginfo.output_bfd = abfd;
+ wginfo.psymalloc = &outsymalloc;
+ _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
+ _bfd_generic_link_write_global_symbol,
+ (PTR) &wginfo);
+
+ /* Remove empty sections. Also drop the .options section, since it
+ has special semantics which I haven't bothered to figure out.
+ Also drop the .gptab sections, which also require special
+ handling which is not currently done. Removing the .gptab
+ sections is required for Irix 5 compatibility; I don't know about
+ the other sections. */
+ secpp = &abfd->sections;
+ while (*secpp != NULL)
+ {
+ if ((*secpp)->_raw_size == 0
+ || strcmp ((*secpp)->name, ".options") == 0
+ || strncmp ((*secpp)->name, ".gptab", 6) == 0)
+ {
+ *secpp = (*secpp)->next;
+ --abfd->section_count;
+ }
+ else
+ secpp = &(*secpp)->next;
+ }
- for (sec = abfd->sections; sec != (asection *) NULL; sec = sec->next)
+ /* Go through the sections and collect the .reginfo and .mdebug
+ information. We don't write out the information until we have
+ set the section sizes, because the ELF backend only assigns space
+ in the file once. */
+ for (o = abfd->sections; o != (asection *) NULL; o = o->next)
{
- if (strcmp (sec->name, ".reginfo") == 0)
+ if (strcmp (o->name, ".reginfo") == 0)
{
- bfd_seclet_type *p;
- Elf32_External_RegInfo ext;
+ memset (&reginfo, 0, sizeof reginfo);
/* We have found the .reginfo section in the output file.
- Look through all the seclets comprising it and merge the
- information together. */
- for (p = sec->seclets_head;
- p != (bfd_seclet_type *) NULL;
+ Look through all the link_orders comprising it and merge
+ the information together. */
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
p = p->next)
{
- switch (p->type)
+ asection *input_section;
+ bfd *input_bfd;
+ Elf32_External_RegInfo ext;
+ Elf32_RegInfo sub;
+
+ if (p->type != bfd_indirect_link_order)
+ continue;
+
+ input_section = p->u.indirect.section;
+ input_bfd = input_section->owner;
+ BFD_ASSERT (input_section->_raw_size
+ == sizeof (Elf32_External_RegInfo));
+ if (! bfd_get_section_contents (input_bfd, input_section,
+ (PTR) &ext,
+ (file_ptr) 0,
+ sizeof ext))
+ return false;
+
+ bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub);
+
+ reginfo.ri_gprmask |= sub.ri_gprmask;
+ reginfo.ri_cprmask[0] |= sub.ri_cprmask[0];
+ reginfo.ri_cprmask[1] |= sub.ri_cprmask[1];
+ reginfo.ri_cprmask[2] |= sub.ri_cprmask[2];
+ reginfo.ri_cprmask[3] |= sub.ri_cprmask[3];
+
+ /* ri_gp_value is set by the function
+ mips_elf_section_processing when the section is
+ finally written out. */
+ }
+
+ /* Force the section size to the value we want. */
+ o->_raw_size = sizeof (Elf32_External_RegInfo);
+
+ /* Skip this section later on. */
+ o->link_order_head = (struct bfd_link_order *) NULL;
+
+ reginfo_sec = o;
+ }
+
+ if (strcmp (o->name, ".mdebug") == 0)
+ {
+ /* We have found the .mdebug section in the output file.
+ Look through all the link_orders comprising it and merge
+ the information together. */
+ symhdr->magic = swap->sym_magic;
+ /* FIXME: What should the version stamp be? */
+ symhdr->vstamp = 0;
+ symhdr->ilineMax = 0;
+ symhdr->cbLine = 0;
+ symhdr->idnMax = 0;
+ symhdr->ipdMax = 0;
+ symhdr->isymMax = 0;
+ symhdr->ioptMax = 0;
+ symhdr->iauxMax = 0;
+ symhdr->issMax = 0;
+ symhdr->issExtMax = 0;
+ symhdr->ifdMax = 0;
+ symhdr->crfd = 0;
+ symhdr->iextMax = 0;
+
+ /* We accumulate the debugging information itself in the
+ debug_info structure. */
+ debug.line = debug.line_end = NULL;
+ debug.external_dnr = debug.external_dnr_end = NULL;
+ debug.external_pdr = debug.external_pdr_end = NULL;
+ debug.external_sym = debug.external_sym_end = NULL;
+ debug.external_opt = debug.external_opt_end = NULL;
+ debug.external_aux = debug.external_aux_end = NULL;
+ debug.ss = debug.ss_end = NULL;
+ debug.ssext = debug.ssext_end = NULL;
+ debug.external_fdr = debug.external_fdr_end = NULL;
+ debug.external_rfd = debug.external_rfd_end = NULL;
+ debug.external_ext = debug.external_ext_end = NULL;
+
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ asection *input_section;
+ bfd *input_bfd;
+ const struct ecoff_debug_swap *input_swap;
+ struct ecoff_debug_info input_debug;
+
+ if (p->type != bfd_indirect_link_order)
+ continue;
+
+ input_section = p->u.indirect.section;
+ input_bfd = input_section->owner;
+
+ if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour
+ || (get_elf_backend_data (input_bfd)
+ ->elf_backend_ecoff_debug_swap) == NULL)
{
- case bfd_indirect_seclet:
- {
- asection *input_section;
- bfd *input_bfd;
- Elf32_RegInfo sub;
-
- input_section = p->u.indirect.section;
- input_bfd = input_section->owner;
- BFD_ASSERT (input_section->_raw_size
- == sizeof (Elf32_External_RegInfo));
- if (! bfd_get_section_contents (input_bfd, input_section,
- (PTR) &ext,
- (file_ptr) 0,
- sizeof ext))
- return false;
-
- bfd_mips_elf32_swap_reginfo_in (input_bfd, &ext, &sub);
-
- reginfo.ri_gprmask |= sub.ri_gprmask;
- reginfo.ri_cprmask[0] |= sub.ri_cprmask[0];
- reginfo.ri_cprmask[1] |= sub.ri_cprmask[1];
- reginfo.ri_cprmask[2] |= sub.ri_cprmask[2];
- reginfo.ri_cprmask[3] |= sub.ri_cprmask[3];
-
- /* ri_gp_value is set by the function
- mips_elf_section_processing when the section is
- finally written out. */
- }
- break;
-
- default:
- break;
+ /* I don't know what a non MIPS ELF bfd would be
+ doing with a .mdebug section, but I don't really
+ want to deal with it. */
+ continue;
}
+
+ input_swap = (get_elf_backend_data (input_bfd)
+ ->elf_backend_ecoff_debug_swap);
+
+ BFD_ASSERT (p->size == input_section->_raw_size);
+
+ /* The ECOFF linking code expects that we have already
+ read in the debugging information and set up an
+ ecoff_debug_info structure, so we do that now. */
+ if (! mips_elf_read_ecoff_info (input_bfd, input_section,
+ &input_debug))
+ return false;
+
+ if (! (bfd_ecoff_debug_accumulate
+ (abfd, &debug, swap,
+ input_bfd, &input_debug, input_swap,
+ info->relocateable)))
+ return false;
+
+ /* Loop through the external symbols. For each one with
+ interesting information, try to find the symbol on
+ the symbol table of abfd and save the information in
+ order to put it into the final external symbols. */
+ if (info->hash->creator == input_bfd->xvec)
+ {
+ char *eraw_src;
+ char *eraw_end;
+
+ eraw_src = input_debug.external_ext;
+ eraw_end = (eraw_src
+ + (input_debug.symbolic_header.iextMax
+ * input_swap->external_ext_size));
+ for (;
+ eraw_src < eraw_end;
+ eraw_src += input_swap->external_ext_size)
+ {
+ EXTR ext;
+ const char *name;
+ struct generic_link_hash_entry *h;
+ elf_symbol_type *elf_sym;
+
+ (*input_swap->swap_ext_in) (input_bfd, (PTR) eraw_src,
+ &ext);
+ if (ext.asym.sc == scNil
+ || ext.asym.sc == scUndefined
+ || ext.asym.sc == scSUndefined)
+ continue;
+
+ name = input_debug.ssext + ext.asym.iss;
+ h = ((struct generic_link_hash_entry *)
+ bfd_link_hash_lookup (info->hash, name, false,
+ false, true));
+ if (h == (struct generic_link_hash_entry *) NULL
+ || h->sym == (asymbol *) NULL)
+ continue;
+
+ elf_sym = (elf_symbol_type *) (h->sym);
+
+ if (elf_sym->tc_data.mips_extr != NULL)
+ continue;
+
+ elf_sym->tc_data.mips_extr =
+ (EXTR *) bfd_alloc (abfd, sizeof (EXTR));
+
+ ext.ifd += input_debug.ifdbase;
+ *elf_sym->tc_data.mips_extr = ext;
+ }
+ }
+
+ /* Free up the information we just read. */
+ free (input_debug.line);
+ free (input_debug.external_dnr);
+ free (input_debug.external_pdr);
+ free (input_debug.external_sym);
+ free (input_debug.external_opt);
+ free (input_debug.external_aux);
+ free (input_debug.ss);
+ free (input_debug.ssext);
+ free (input_debug.external_fdr);
+ free (input_debug.external_rfd);
+ free (input_debug.external_ext);
}
- /* Write out the information we have accumulated. */
- bfd_mips_elf32_swap_reginfo_out (abfd, &reginfo, &ext);
- if (! bfd_set_section_contents (abfd, sec, (PTR) &ext,
- (file_ptr) 0, sizeof ext))
+ /* Build the external symbol information. */
+ if (! bfd_ecoff_debug_externals (abfd, &debug, swap,
+ info->relocateable,
+ mips_elf_get_extr,
+ mips_elf_set_index))
return false;
- /* Force the section size to the value we want. */
- sec->_raw_size = sizeof (Elf32_External_RegInfo);
+ /* Set the size of the section. */
+ o->_raw_size = bfd_ecoff_debug_size (abfd, &debug, swap);
+
+ /* Skip this section later on. */
+ o->link_order_head = (struct bfd_link_order *) NULL;
+
+ mdebug_sec = o;
+ }
+ }
+
+ if (info->relocateable)
+ {
+ /* Allocate space for the output relocs for each section. */
+ for (o = abfd->sections;
+ o != (asection *) NULL;
+ o = o->next)
+ {
+ o->reloc_count = 0;
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ if (p->type == bfd_indirect_link_order)
+ {
+ asection *input_section;
+ bfd *input_bfd;
+ bfd_size_type relsize;
+ arelent **relocs;
+ bfd_size_type reloc_count;
+
+ input_section = p->u.indirect.section;
+ input_bfd = input_section->owner;
+ relsize = bfd_get_reloc_upper_bound (input_bfd,
+ input_section);
+ relocs = (arelent **) bfd_xmalloc (relsize);
+ reloc_count =
+ bfd_canonicalize_reloc (input_bfd, input_section,
+ relocs,
+ bfd_get_outsymbols (input_bfd));
+ BFD_ASSERT (reloc_count == input_section->reloc_count);
+ o->reloc_count += reloc_count;
+ free (relocs);
+ }
+ }
+ if (o->reloc_count > 0)
+ {
+ o->orelocation = ((arelent **)
+ bfd_alloc (abfd,
+ (o->reloc_count
+ * sizeof (arelent *))));
+ /* Reset the count so that it can be used as an index
+ when putting in the output relocs. */
+ o->reloc_count = 0;
+ }
+ }
+ }
- /* Force bfd_generic_seclet_link to ignore this section. */
- sec->seclets_head = (bfd_seclet_type *) NULL;
+ /* Write out the information we have accumulated. */
+ if (reginfo_sec != (asection *) NULL)
+ {
+ Elf32_External_RegInfo ext;
+
+ bfd_mips_elf32_swap_reginfo_out (abfd, &reginfo, &ext);
+ if (! bfd_set_section_contents (abfd, reginfo_sec, (PTR) &ext,
+ (file_ptr) 0, sizeof ext))
+ return false;
+ }
- break;
+ if (mdebug_sec != (asection *) NULL)
+ {
+ if (! abfd->output_has_begun)
+ {
+ /* Force the section to be given a file position. */
+ bfd_set_section_contents (abfd, mdebug_sec, (PTR) NULL,
+ (file_ptr) 0, (bfd_size_type) 0);
+ BFD_ASSERT (abfd->output_has_begun);
}
+ if (! bfd_ecoff_write_debug (abfd, &debug, swap, mdebug_sec->filepos))
+ return false;
}
- return bfd_generic_seclet_link (abfd, data, relocateable);
+ /* Handle all the link order information for the sections. */
+ for (o = abfd->sections;
+ o != (asection *) NULL;
+ o = o->next)
+ {
+ for (p = o->link_order_head;
+ p != (struct bfd_link_order *) NULL;
+ p = p->next)
+ {
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ return false;
+ }
+ }
+
+ return true;
}
/* MIPS ELF uses two common sections. One is the usual one, and the
@@ -947,6 +1491,13 @@ static asection mips_elf_scom_section;
static asymbol mips_elf_scom_symbol;
static asymbol *mips_elf_scom_symbol_ptr;
+/* MIPS ELF also uses an acommon section, which represents an
+ allocated common symbol which may be overridden by a
+ definition in a shared library. */
+static asection mips_elf_acom_section;
+static asymbol mips_elf_acom_symbol;
+static asymbol *mips_elf_acom_symbol_ptr;
+
/* Handle the special MIPS section numbers that a symbol may use. */
static void
@@ -960,9 +1511,25 @@ mips_elf_symbol_processing (abfd, asym)
switch (elfsym->internal_elf_sym.st_shndx)
{
case SHN_MIPS_ACOMMON:
- /* FIXME: I don't really understand just what this section
- means or when it would be used. */
- abort ();
+ /* This section is used in a dynamically linked executable file.
+ It is an allocated common section. The dynamic linker can
+ either resolve these symbols to something in a shared
+ library, or it can just leave them here. For our purposes,
+ we can consider these symbols to be in a new section. */
+ if (mips_elf_acom_section.name == NULL)
+ {
+ /* Initialize the acommon section. */
+ mips_elf_acom_section.name = ".acommon";
+ mips_elf_acom_section.flags = SEC_NO_FLAGS;
+ mips_elf_acom_section.output_section = &mips_elf_acom_section;
+ mips_elf_acom_section.symbol = &mips_elf_acom_symbol;
+ mips_elf_acom_section.symbol_ptr_ptr = &mips_elf_acom_symbol_ptr;
+ mips_elf_acom_symbol.name = ".acommon";
+ mips_elf_acom_symbol.flags = BSF_SECTION_SYM;
+ mips_elf_acom_symbol.section = &mips_elf_acom_section;
+ mips_elf_acom_symbol_ptr = &mips_elf_acom_symbol;
+ }
+ asym->section = &mips_elf_acom_section;
break;
case SHN_COMMON:
@@ -995,21 +1562,64 @@ mips_elf_symbol_processing (abfd, asym)
}
}
+/* ECOFF swapping routines. These are used when dealing with the
+ .mdebug section, which is in the ECOFF debugging format. */
+static const struct ecoff_debug_swap mips_elf_ecoff_debug_swap =
+{
+ /* Symbol table magic number. */
+ magicSym,
+ /* Alignment of debugging information. E.g., 4. */
+ 4,
+ /* Sizes of external symbolic information. */
+ sizeof (struct hdr_ext),
+ sizeof (struct dnr_ext),
+ sizeof (struct pdr_ext),
+ sizeof (struct sym_ext),
+ sizeof (struct opt_ext),
+ sizeof (struct fdr_ext),
+ sizeof (struct rfd_ext),
+ sizeof (struct ext_ext),
+ /* Functions to swap in external symbolic data. */
+ ecoff_swap_hdr_in,
+ ecoff_swap_dnr_in,
+ ecoff_swap_pdr_in,
+ ecoff_swap_sym_in,
+ ecoff_swap_opt_in,
+ ecoff_swap_fdr_in,
+ ecoff_swap_rfd_in,
+ ecoff_swap_ext_in,
+ /* Functions to swap out external symbolic data. */
+ ecoff_swap_hdr_out,
+ ecoff_swap_dnr_out,
+ ecoff_swap_pdr_out,
+ ecoff_swap_sym_out,
+ ecoff_swap_opt_out,
+ ecoff_swap_fdr_out,
+ ecoff_swap_rfd_out,
+ ecoff_swap_ext_out
+};
+
#define TARGET_LITTLE_SYM bfd_elf32_littlemips_vec
#define TARGET_LITTLE_NAME "elf32-littlemips"
#define TARGET_BIG_SYM bfd_elf32_bigmips_vec
#define TARGET_BIG_NAME "elf32-bigmips"
#define ELF_ARCH bfd_arch_mips
+#define ELF_MACHINE_CODE EM_MIPS
#define ELF_MAXPAGESIZE 0x10000
#define elf_info_to_howto 0
#define elf_info_to_howto_rel mips_info_to_howto_rel
+#define elf_backend_sym_is_global mips_elf_sym_is_global
+#define elf_backend_object_p mips_elf_object_p
#define elf_backend_section_from_shdr mips_elf_section_from_shdr
#define elf_backend_fake_sections mips_elf_fake_sections
#define elf_backend_section_from_bfd_section \
mips_elf_section_from_bfd_section
#define elf_backend_section_processing mips_elf_section_processing
#define elf_backend_symbol_processing mips_elf_symbol_processing
+#define elf_backend_final_write_processing \
+ mips_elf_final_write_processing
+#define elf_backend_ecoff_debug_swap &mips_elf_ecoff_debug_swap
-#define bfd_elf32_bfd_seclet_link mips_elf_seclet_link
+#define bfd_elf32_bfd_final_link mips_elf_final_link
#include "elf32-target.h"
diff --git a/bfd/linker.c b/bfd/linker.c
index 0e8c9f4..eb8b4e8 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -38,6 +38,9 @@ static boolean generic_add_output_symbol
static boolean default_fill_link_order
PARAMS ((bfd *, struct bfd_link_info *, asection *,
struct bfd_link_order *));
+static boolean default_indirect_link_order
+ PARAMS ((bfd *, struct bfd_link_info *, asection *,
+ struct bfd_link_order *));
/* The link hash table structure is defined in bfdlink.h. It provides
a base hash table which the backend specific hash tables are built
@@ -580,11 +583,16 @@ generic_link_check_archive_element (abfd, info, pneeded)
the object file. This is how a.out works. Object
formats that require different semantics must implement
this function differently. This symbol is already on the
- undefs list. */
+ undefs list. We add the section to a common section
+ attached to symbfd to ensure that it is in a BFD which
+ will be linked in. */
h->type = bfd_link_hash_common;
h->u.c.size = bfd_asymbol_value (p);
- h->u.c.section = bfd_make_section_old_way (symbfd,
- "COMMON");
+ if (p->section == &bfd_com_section)
+ h->u.c.section = bfd_make_section_old_way (symbfd, "COMMON");
+ else
+ h->u.c.section = bfd_make_section_old_way (symbfd,
+ p->section->name);
}
else
{
@@ -647,9 +655,17 @@ generic_link_add_symbol_list (abfd, info, symbol_count, symbols)
}
else
string = NULL;
+
+ /* We pass the constructor argument as false, for
+ compatibility. As backends are converted they can
+ arrange to pass the right value (the right value is the
+ size of a function pointer if gcc uses collect2 for the
+ object file format, zero if it does not).
+ FIXME: We pass the bitsize as 32, which is just plain
+ wrong, but actually doesn't matter very much. */
if (! (_bfd_generic_link_add_one_symbol
(info, abfd, name, p->flags, bfd_get_section (p),
- p->value, string, false,
+ p->value, string, false, 0, 32,
(struct bfd_link_hash_entry **) &h)))
return false;
@@ -745,12 +761,15 @@ static const enum link_action link_action[8][7] =
which case it is the warning string.
COPY is true if NAME or STRING must be copied into locally
allocated memory if they need to be saved.
+ CONSTRUCTOR is true if we should automatically collect gcc
+ constructor or destructor names.
+ BITSIZE is the number of bits in constructor or set entries.
HASHP, if not NULL, is a place to store the created hash table
entry. */
boolean
_bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
- string, copy, hashp)
+ string, copy, constructor, bitsize, hashp)
struct bfd_link_info *info;
bfd *abfd;
const char *name;
@@ -759,6 +778,8 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
bfd_vma value;
const char *string;
boolean copy;
+ boolean constructor;
+ unsigned int bitsize;
struct bfd_link_hash_entry **hashp;
{
enum link_row row;
@@ -836,6 +857,47 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
h->type = bfd_link_hash_defined;
h->u.def.section = section;
h->u.def.value = value;
+
+ /* If we have been asked to, we act like collect2 and
+ identify all functions that might be global constructors
+ and destructors and pass them up in a callback. We only
+ do this for certain object file types, since many object
+ file types can handle this automatically. */
+ if (constructor && name[0] == '_')
+ {
+ const char *s;
+
+ /* A constructor or destructor name starts like this:
+ _+GLOBAL_[_.$][ID][_.$]
+ where the first [_.$] and the second are the same
+ character (we accept any character there, in case a
+ new object file format comes along with even worse
+ naming restrictions). */
+
+#define CONS_PREFIX "GLOBAL_"
+#define CONS_PREFIX_LEN (sizeof CONS_PREFIX - 1)
+
+ s = name + 1;
+ while (*s == '_')
+ ++s;
+ if (s[0] == 'G'
+ && strncmp (s, CONS_PREFIX, CONS_PREFIX_LEN - 1) == 0)
+ {
+ char c;
+
+ c = s[CONS_PREFIX_LEN + 1];
+ if ((c == 'I' || c == 'D')
+ && s[CONS_PREFIX_LEN] == s[CONS_PREFIX_LEN + 2])
+ {
+ if (! ((*info->callbacks->constructor)
+ (info,
+ c == 'I' ? true : false, bitsize,
+ name, abfd, section, value)))
+ return false;
+ }
+ }
+ }
+
break;
case COM:
if (h->type == bfd_link_hash_new)
@@ -860,8 +922,6 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
return false;
if (value > h->u.c.size)
h->u.c.size = value;
- if (h->u.c.section == (asection *) NULL)
- h->u.c.section = bfd_make_section_old_way (abfd, "COMMON");
break;
case CREF:
BFD_ASSERT (h->type == bfd_link_hash_defined);
@@ -921,7 +981,8 @@ _bfd_generic_link_add_one_symbol (info, abfd, name, flags, section, value,
}
break;
case SET:
- if (! (*info->callbacks->add_to_set) (info, h, abfd, section, value))
+ if (! (*info->callbacks->add_to_set) (info, h, bitsize, abfd,
+ section, value))
return false;
break;
case WARN:
@@ -1057,17 +1118,8 @@ _bfd_generic_final_link (abfd, info)
p != (struct bfd_link_order *) NULL;
p = p->next)
{
- switch (p->type)
- {
- case bfd_indirect_link_order:
- if (! _bfd_generic_indirect_link_order (abfd, info, o, p))
- return false;
- break;
- default:
- if (! _bfd_default_link_order (abfd, info, o, p))
- return false;
- break;
- }
+ if (! _bfd_default_link_order (abfd, info, o, p))
+ return false;
}
}
@@ -1368,45 +1420,6 @@ _bfd_generic_link_write_global_symbol (h, data)
return true;
}
-
-/* Handle an indirect section when doing a generic link. */
-
-boolean
-_bfd_generic_indirect_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;
-{
- asection *input_section;
- bfd *input_bfd;
- bfd_byte *contents;
-
- BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
-
- if (link_order->size == 0)
- return true;
-
- input_section = link_order->u.indirect.section;
- input_bfd = input_section->owner;
-
- 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 and relocate the section contents. */
- contents = (bfd_byte *) alloca (bfd_section_size (input_bfd, input_section));
- contents = (bfd_get_relocated_section_contents
- (output_bfd, info, link_order, contents, info->relocateable,
- bfd_get_outsymbols (input_bfd)));
-
- /* Output the section contents. */
- if (! bfd_set_section_contents (output_bfd, output_section, contents,
- link_order->offset, link_order->size))
- return false;
-
- return true;
-}
/* Allocate a new link_order for a section. */
@@ -1449,7 +1462,7 @@ _bfd_default_link_order (abfd, info, sec, link_order)
default:
abort ();
case bfd_indirect_link_order:
- abort ();
+ return default_indirect_link_order (abfd, info, sec, link_order);
case bfd_fill_link_order:
return default_fill_link_order (abfd, info, sec, link_order);
}
@@ -1457,6 +1470,7 @@ _bfd_default_link_order (abfd, info, sec, link_order)
/* Default routine to handle a bfd_fill_link_order. */
+/*ARGSUSED*/
static boolean
default_fill_link_order (abfd, info, sec, link_order)
bfd *abfd;
@@ -1482,3 +1496,67 @@ default_fill_link_order (abfd, info, sec, link_order)
(file_ptr) link_order->offset,
link_order->size);
}
+
+/* Default routine to handle a bfd_indirect_link_order. */
+
+static boolean
+default_indirect_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;
+{
+ asection *input_section;
+ bfd *input_bfd;
+ bfd_byte *contents;
+
+ BFD_ASSERT ((output_section->flags & SEC_HAS_CONTENTS) != 0);
+
+ if (link_order->size == 0)
+ return true;
+
+ input_section = link_order->u.indirect.section;
+ input_bfd = input_section->owner;
+
+ 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);
+
+ if (info->relocateable
+ && output_section->orelocation == (arelent **) NULL)
+ {
+ /* Space has not been allocated for the output relocations.
+ This can happen when we are called by a specific backend
+ because somebody is attempting to link together different
+ types of object files. Handling this case correctly is
+ difficult, and sometimes impossible. */
+ abort ();
+ }
+
+ /* Get the canonical symbols. The generic linker will always have
+ retrieved them by this point, but we may be being called by a
+ specific linker when linking different types of object files
+ together. */
+ if (bfd_get_outsymbols (input_bfd) == (asymbol **) NULL)
+ {
+ size_t symsize;
+
+ symsize = get_symtab_upper_bound (input_bfd);
+ input_bfd->outsymbols = (asymbol **) bfd_alloc (input_bfd, symsize);
+ input_bfd->symcount = bfd_canonicalize_symtab (input_bfd,
+ input_bfd->outsymbols);
+ }
+
+ /* Get and relocate the section contents. */
+ contents = (bfd_byte *) alloca (bfd_section_size (input_bfd, input_section));
+ contents = (bfd_get_relocated_section_contents
+ (output_bfd, info, link_order, contents, info->relocateable,
+ bfd_get_outsymbols (input_bfd)));
+
+ /* Output the section contents. */
+ if (! bfd_set_section_contents (output_bfd, output_section, (PTR) contents,
+ link_order->offset, link_order->size))
+ return false;
+
+ return true;
+}