aboutsummaryrefslogtreecommitdiff
path: root/bfd/elflink.h
diff options
context:
space:
mode:
authornobody <>1999-07-20 22:27:32 +0000
committernobody <>1999-07-20 22:27:32 +0000
commitf59527fdfff0315fe386cf150797856c098eaa45 (patch)
tree5c81995e4b0c159d50d64bc5e9d83f5af26f61f6 /bfd/elflink.h
parent252b5132c753830d5fd56823373aed85f2a0db63 (diff)
downloadgdb-binu_ss_19990721.zip
gdb-binu_ss_19990721.tar.gz
gdb-binu_ss_19990721.tar.bz2
This commit was manufactured by cvs2svn to create tag 'binu_ss_19990721'.binu_ss_19990721
Sprout from cygnus 1999-05-03 07:29:11 UTC Richard Henderson <rth@redhat.com> '19990502 sourceware import' Cherrypick from master 1999-07-20 22:27:31 UTC Doug Evans <dje@google.com> ' * ldlang.c (lang_gc_sections): Only handle the start symbol': ChangeLog Makefile.in bfd/ChangeLog bfd/Makefile.am bfd/Makefile.in bfd/aclocal.m4 bfd/aix386-core.c bfd/aout-adobe.c bfd/aout-arm.c bfd/aout-ns32k.c bfd/aout-target.h bfd/aout-tic30.c bfd/aoutx.h bfd/archive.c bfd/archures.c bfd/bfd-in.h bfd/bfd-in2.h bfd/bfd.c bfd/binary.c bfd/bout.c bfd/cisco-core.c bfd/coff-a29k.c bfd/coff-alpha.c bfd/coff-apollo.c bfd/coff-arm.c bfd/coff-h8300.c bfd/coff-h8500.c bfd/coff-i386.c bfd/coff-i860.c bfd/coff-i960.c bfd/coff-m68k.c bfd/coff-m88k.c bfd/coff-mcore.c bfd/coff-mips.c bfd/coff-ppc.c bfd/coff-rs6000.c bfd/coff-sh.c bfd/coff-sparc.c bfd/coff-stgo32.c bfd/coff-tic30.c bfd/coff-tic80.c bfd/coff-w65.c bfd/coff-we32k.c bfd/coff-z8k.c bfd/coffcode.h bfd/coffgen.c bfd/cofflink.c bfd/coffswap.h bfd/config.bfd bfd/config.in bfd/configure bfd/configure.host bfd/configure.in bfd/cpu-arm.c bfd/cpu-h8500.c bfd/cpu-ns32k.c bfd/cpu-w65.c bfd/dwarf1.c bfd/dwarf2.c bfd/ecoff.c bfd/ecofflink.c bfd/elf-bfd.h bfd/elf-hppa.h bfd/elf-m10200.c bfd/elf-m10300.c bfd/elf.c bfd/elf32-arc.c bfd/elf32-arm.h bfd/elf32-d10v.c bfd/elf32-d30v.c bfd/elf32-fr30.c bfd/elf32-gen.c bfd/elf32-hppa.c bfd/elf32-hppa.h bfd/elf32-i386.c bfd/elf32-i860.c bfd/elf32-i960.c bfd/elf32-m32r.c bfd/elf32-m68k.c bfd/elf32-m88k.c bfd/elf32-mcore.c bfd/elf32-mips.c bfd/elf32-ppc.c bfd/elf32-sh.c bfd/elf32-sparc.c bfd/elf32-v850.c bfd/elf64-alpha.c bfd/elf64-gen.c bfd/elf64-mips.c bfd/elf64-sparc.c bfd/elfarm-nabi.c bfd/elfarm-oabi.c bfd/elfcode.h bfd/elflink.c bfd/elflink.h bfd/elfxx-target.h bfd/epoc-pe-arm.c bfd/epoc-pei-arm.c bfd/hash.c bfd/hosts/alphalinux.h bfd/hp300hpux.c bfd/hppabsd-core.c bfd/hpux-core.c bfd/i386linux.c bfd/i386lynx.c bfd/i386msdos.c bfd/i386os9k.c bfd/ieee.c bfd/ihex.c bfd/irix-core.c bfd/libbfd-in.h bfd/libbfd.c bfd/libbfd.h bfd/libhppa.h bfd/linker.c bfd/m68klinux.c bfd/mipsbsd.c bfd/netbsd-core.c bfd/nlm-target.h bfd/nlm32-ppc.c bfd/nlm32-sparc.c bfd/nlmcode.h bfd/oasys.c bfd/osf-core.c bfd/pe-arm.c bfd/pei-arm.c bfd/peicode.h bfd/po/POTFILES.in bfd/po/bfd.pot bfd/ppcboot.c bfd/ptrace-core.c bfd/reloc.c bfd/riscix.c bfd/sco5-core.c bfd/section.c bfd/som.c bfd/sparclinux.c bfd/srec.c bfd/stabs.c bfd/sunos.c bfd/syms.c bfd/targets.c bfd/tekhex.c bfd/trad-core.c bfd/versados.c bfd/vms-gsd.c bfd/vms-hdr.c bfd/vms-misc.c bfd/vms-tir.c bfd/vms.c bfd/vms.h bfd/xcofflink.c binutils/ChangeLog binutils/Makefile.am binutils/Makefile.in binutils/NEWS binutils/addr2line.c binutils/ar.c binutils/arparse.y binutils/arsup.c binutils/binutils.texi binutils/config.in binutils/configure binutils/configure.in binutils/debug.c binutils/deflex.l binutils/defparse.y binutils/dlltool.c binutils/dllwrap.c binutils/filemode.c binutils/ieee.c binutils/nm.c binutils/objcopy.1 binutils/objcopy.c binutils/objdump.c binutils/po/POTFILES.in binutils/po/binutils.pot binutils/prdbg.c binutils/rclex.l binutils/rcparse.y binutils/rdcoff.c binutils/readelf.c binutils/rename.c binutils/rescoff.c binutils/resrc.c binutils/size.c binutils/stabs.c binutils/testsuite/ChangeLog binutils/testsuite/binutils-all/objdump.exp binutils/testsuite/binutils-all/readelf.h binutils/testsuite/binutils-all/readelf.r binutils/testsuite/binutils-all/readelf.wi binutils/windres.c binutils/windres.h binutils/wrstabs.c config.guess config.sub configure configure.in gas/ChangeLog gas/Makefile.am gas/Makefile.in gas/NEWS gas/aclocal.m4 gas/app.c gas/as.c gas/as.h gas/atof-generic.c gas/cgen.c gas/cond.c gas/config/atof-ieee.c gas/config/m68k-parse.h gas/config/obj-aout.c gas/config/obj-aout.h gas/config/obj-bout.c gas/config/obj-coff.c gas/config/obj-coff.h gas/config/obj-ecoff.c gas/config/obj-ecoff.h gas/config/obj-elf.c gas/config/obj-elf.h gas/config/obj-multi.h gas/config/obj-vms.h gas/config/tc-alpha.c gas/config/tc-alpha.h gas/config/tc-arc.c gas/config/tc-arc.h gas/config/tc-arm.c gas/config/tc-arm.h gas/config/tc-d10v.c gas/config/tc-d30v.c gas/config/tc-d30v.h gas/config/tc-fr30.c gas/config/tc-hppa.c gas/config/tc-hppa.h gas/config/tc-i386.c gas/config/tc-i386.h gas/config/tc-i860.c gas/config/tc-i960.c gas/config/tc-i960.h gas/config/tc-m32r.c gas/config/tc-m68k.c gas/config/tc-m68k.h gas/config/tc-m88k.c gas/config/tc-mcore.c gas/config/tc-mcore.h gas/config/tc-mips.c gas/config/tc-mips.h gas/config/tc-mn10200.c gas/config/tc-mn10300.c gas/config/tc-ns32k.c gas/config/tc-ns32k.h gas/config/tc-ppc.c gas/config/tc-ppc.h gas/config/tc-sh.c gas/config/tc-sh.h gas/config/tc-sparc.c gas/config/tc-sparc.h gas/config/tc-tahoe.c gas/config/tc-tic30.c gas/config/tc-v850.c gas/config/tc-vax.c gas/config/tc-w65.c gas/config/tc-z8k.c gas/configure gas/configure.in gas/dep-in.sed gas/doc/Makefile.in gas/doc/c-arm.texi gas/doc/c-sparc.texi gas/doc/internals.texi gas/dwarf2dbg.c gas/dwarf2dbg.h gas/ecoff.c gas/ecoff.h gas/expr.c gas/expr.h gas/frags.h gas/gasp.c gas/hash.c gas/hash.h gas/input-file.c gas/itbl-ops.c gas/itbl-ops.h gas/listing.c gas/macro.c gas/po/POTFILES.in gas/po/gas.pot gas/read.c gas/read.h gas/stabs.c gas/struc-symbol.h gas/subsegs.c gas/symbols.c gas/symbols.h gas/testsuite/ChangeLog gas/testsuite/gas/all/itbl-test.c gas/testsuite/gas/arm/arm7t.d gas/testsuite/gas/arm/inst.d gas/testsuite/gas/elf/elf.exp gas/testsuite/gas/elf/section0.d gas/testsuite/gas/elf/section0.s gas/testsuite/gas/elf/section1.d gas/testsuite/gas/elf/section1.s gas/testsuite/gas/i386/amd.d gas/testsuite/gas/i386/amd.s gas/testsuite/gas/i386/i386.exp gas/testsuite/gas/i386/katmai.d gas/testsuite/gas/i386/katmai.s gas/testsuite/gas/i386/opcode.d gas/testsuite/gas/i386/prefix.d gas/testsuite/gas/i386/prefix.s gas/testsuite/gas/i386/reloc.d gas/testsuite/gas/i386/reloc.s gas/testsuite/gas/macros/irp.d gas/testsuite/gas/macros/irp.s gas/testsuite/gas/macros/rept.d gas/testsuite/gas/macros/rept.s gas/testsuite/gas/macros/test2.d gas/testsuite/gas/macros/test2.s gas/testsuite/gas/macros/test3.d gas/testsuite/gas/macros/test3.s gas/testsuite/gas/mcore/allinsn.d gas/testsuite/gas/mips/elf_e_flags.c gas/testsuite/gas/mips/elf_e_flags.s gas/testsuite/gas/mips/elf_e_flags1.d gas/testsuite/gas/mips/elf_e_flags2.d gas/testsuite/gas/mips/elf_e_flags3.d gas/testsuite/gas/mips/elf_e_flags4.d gas/testsuite/gas/mips/sync.d gas/testsuite/gas/sparc/prefetch.d gas/testsuite/gas/sparc/rdpr.d gas/testsuite/gas/sparc/reloc64.d gas/testsuite/gas/sparc/set64.d gas/testsuite/gas/sparc/set64.s gas/testsuite/gas/sparc/sparc.exp gas/testsuite/gas/sparc/synth64.d gas/testsuite/gas/sparc/synth64.s gas/testsuite/gas/sparc/wrpr.d gas/testsuite/gas/vtable/vtable.exp gas/write.c gprof/ChangeLog gprof/Makefile.am gprof/Makefile.in gprof/alpha.c gprof/basic_blocks.c gprof/call_graph.c gprof/cg_dfn.c gprof/configure gprof/configure.in gprof/corefile.c gprof/gmon_io.c gprof/gprof.texi gprof/hist.c gprof/i386.c gprof/po/POTFILES.in gprof/po/gprof.pot gprof/sparc.c gprof/sym_ids.c gprof/symtab.c gprof/tahoe.c gprof/vax.c include/ChangeLog include/ansidecl.h include/aout/ChangeLog include/aout/aout64.h include/bfdlink.h include/coff/ChangeLog include/coff/arm.h include/coff/internal.h include/coff/mcore.h include/dis-asm.h include/elf/ChangeLog include/elf/arm.h include/elf/common.h include/elf/dwarf.h include/elf/dwarf2.h include/elf/hppa.h include/elf/i960.h include/elf/m68k.h include/elf/mcore.h include/elf/mips.h include/elf/reloc-macros.h include/elf/sparc.h include/opcode/ChangeLog include/opcode/hppa.h include/opcode/i386.h include/opcode/m68k.h include/opcode/ppc.h ld/ChangeLog ld/Makefile.am ld/Makefile.in ld/NEWS ld/configure ld/configure.host ld/configure.in ld/configure.tgt ld/emulparams/armelf.sh ld/emulparams/armelf_linux.sh ld/emulparams/armelf_oabi.sh ld/emulparams/elf32_i960.sh ld/emulparams/elf32bmipn32.sh ld/emulparams/elf32mcore.sh ld/emulparams/elf32ppclinux.sh ld/emulparams/elf64_sparc.sh ld/emulparams/elf64bmip.sh ld/emulparams/mcorepe.sh ld/emultempl/armcoff.em ld/emultempl/armelf.em ld/emultempl/armelf_oabi.em ld/emultempl/elf32.em ld/emultempl/linux.em ld/emultempl/pe.em ld/emultempl/sunos.em ld/genscripts.sh ld/ld.texinfo ld/ldcref.c ld/ldemul.c ld/ldexp.c ld/ldfile.c ld/ldgram.y ld/ldlang.c ld/ldlang.h ld/ldmain.c ld/lexsup.c ld/pe-dll.c ld/po/POTFILES.in ld/po/ld.pot ld/scripttempl/armcoff.sc ld/scripttempl/elf.sc ld/scripttempl/mcorepe.sc ld/scripttempl/pe.sc ld/scripttempl/v850.sc ld/testsuite/ChangeLog ld/testsuite/ld-cdtest/cdtest-main.cc ld/testsuite/ld-checks/asm.s ld/testsuite/ld-checks/checks.exp ld/testsuite/ld-elfvers/vers.exp ld/testsuite/ld-elfvers/vers17.c ld/testsuite/ld-elfvers/vers17.dsym ld/testsuite/ld-elfvers/vers17.map ld/testsuite/ld-elfvers/vers17.ver ld/testsuite/ld-elfvers/vers18.c ld/testsuite/ld-elfvers/vers18.dsym ld/testsuite/ld-elfvers/vers18.map ld/testsuite/ld-elfvers/vers18.sym ld/testsuite/ld-elfvers/vers18.ver ld/testsuite/ld-elfvers/vers19.c ld/testsuite/ld-elfvers/vers19.dsym ld/testsuite/ld-elfvers/vers19.ver ld/testsuite/ld-scripts/phdrs.exp ld/testsuite/ld-scripts/weak.exp ld/testsuite/ld-shared/sh1.c ld/testsuite/ld-shared/shared.exp ld/testsuite/ld-srec/srec.exp ld/testsuite/ld-undefined/undefined.exp ld/testsuite/lib/ld-lib.exp libiberty/ChangeLog libiberty/argv.c libiberty/choose-temp.c libiberty/configure libiberty/configure.in libiberty/cplus-dem.c libiberty/getruntime.c libiberty/splay-tree.c opcodes/ChangeLog opcodes/Makefile.am opcodes/Makefile.in opcodes/alpha-dis.c opcodes/arm-dis.c opcodes/dis-buf.c opcodes/disassemble.c opcodes/i386-dis.c opcodes/m68k-dis.c opcodes/m68k-opc.c opcodes/mcore-dis.c opcodes/mcore-opc.h opcodes/po/POTFILES.in opcodes/po/opcodes.pot opcodes/sparc-dis.c opcodes/sparc-opc.c opcodes/tic30-dis.c texinfo/texinfo.tex Delete: intl/ChangeLog.Cygnus
Diffstat (limited to 'bfd/elflink.h')
-rw-r--r--bfd/elflink.h855
1 files changed, 579 insertions, 276 deletions
diff --git a/bfd/elflink.h b/bfd/elflink.h
index 32bfab0..6fb9bba 100644
--- a/bfd/elflink.h
+++ b/bfd/elflink.h
@@ -48,10 +48,17 @@ static boolean elf_link_find_version_dependencies
PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_link_assign_sym_version
PARAMS ((struct elf_link_hash_entry *, PTR));
-static boolean elf_link_renumber_dynsyms
- PARAMS ((struct elf_link_hash_entry *, PTR));
static boolean elf_collect_hash_codes
PARAMS ((struct elf_link_hash_entry *, PTR));
+static boolean elf_link_read_relocs_from_section
+ PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *));
+static void elf_link_output_relocs
+ PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *));
+static boolean elf_link_size_reloc_section
+ PARAMS ((bfd *, Elf_Internal_Shdr *, asection *));
+static void elf_link_adjust_relocs
+ PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int,
+ struct elf_link_hash_entry **));
/* Given an ELF BFD, add symbols to the global hash table as
appropriate. */
@@ -358,6 +365,17 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
break;
}
+ /* In cases involving weak versioned symbols, we may wind up trying
+ to merge a symbol with itself. Catch that here, to avoid the
+ confusion that results if we try to override a symbol with
+ itself. The additional tests catch cases like
+ _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a
+ dynamic object, which we do want to handle here. */
+ if (abfd == oldbfd
+ && ((abfd->flags & DYNAMIC) == 0
+ || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0))
+ return true;
+
/* NEWDYN and OLDDYN indicate whether the new or old symbol,
respectively, is from a dynamic object. */
@@ -484,14 +502,19 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
represent variables; this can cause confusion in principle, but
any such confusion would seem to indicate an erroneous program or
shared library. We also permit a common symbol in a regular
- object to override a weak symbol in a shared object. */
+ object to override a weak symbol in a shared object.
+
+ We prefer a non-weak definition in a shared library to a weak
+ definition in the executable. */
if (newdyn
&& newdef
&& (olddef
|| (h->root.type == bfd_link_hash_common
&& (bind == STB_WEAK
- || ELF_ST_TYPE (sym->st_info) == STT_FUNC))))
+ || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))
+ && (h->root.type != bfd_link_hash_defweak
+ || bind == STB_WEAK))
{
*override = true;
newdef = false;
@@ -535,7 +558,10 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
As above, we again permit a common symbol in a regular object to
override a definition in a shared object if the shared object
- symbol is a function or is weak. */
+ symbol is a function or is weak.
+
+ As above, we permit a non-weak definition in a shared object to
+ override a weak definition in a regular object. */
if (! newdyn
&& (newdef
@@ -544,7 +570,9 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
|| h->type == STT_FUNC)))
&& olddyn
&& olddef
- && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)
+ && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0
+ && (bind != STB_WEAK
+ || h->root.type == bfd_link_hash_defweak))
{
/* Change the hash table entry to undefined, and let
_bfd_generic_link_add_one_symbol do the right thing with the
@@ -618,6 +646,41 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash,
h->verinfo.vertree = NULL;
}
+ /* Handle the special case of a weak definition in a regular object
+ followed by a non-weak definition in a shared object. In this
+ case, we prefer the definition in the shared object. */
+ if (olddef
+ && h->root.type == bfd_link_hash_defweak
+ && newdef
+ && newdyn
+ && bind != STB_WEAK)
+ {
+ /* To make this work we have to frob the flags so that the rest
+ of the code does not think we are using the regular
+ definition. */
+ h->elf_link_hash_flags &= ~ ELF_LINK_HASH_DEF_REGULAR;
+ h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR;
+
+ /* If H is the target of an indirection, we want the caller to
+ use H rather than the indirect symbol. Otherwise if we are
+ defining a new indirect symbol we will wind up attaching it
+ to the entry we are overriding. */
+ *sym_hash = h;
+ }
+
+ /* Handle the special case of a non-weak definition in a shared
+ object followed by a weak definition in a regular object. In
+ this case we prefer to definition in the shared object. To make
+ this work we have to tell the caller to not treat the new symbol
+ as a definition. */
+ if (olddef
+ && olddyn
+ && h->root.type != bfd_link_hash_defweak
+ && newdef
+ && ! newdyn
+ && bind == STB_WEAK)
+ *override = true;
+
return true;
}
@@ -1937,16 +2000,18 @@ elf_link_create_dynamic_sections (abfd, info)
&& ! _bfd_elf_link_record_dynamic_symbol (info, h))
return false;
+ bed = get_elf_backend_data (abfd);
+
s = bfd_make_section (abfd, ".hash");
if (s == NULL
|| ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY)
|| ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN))
return false;
+ elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry;
/* Let the backend create the rest of the sections. This lets the
backend set the right flags. The backend will normally create
the .got and .plt sections. */
- bed = get_elf_backend_data (abfd);
if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info))
return false;
@@ -1989,14 +2054,170 @@ elf_add_dynamic_entry (info, tag, val)
return true;
}
+
+/* Record a new local dynamic symbol. */
+
+boolean
+elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx)
+ struct bfd_link_info *info;
+ bfd *input_bfd;
+ long input_indx;
+{
+ struct elf_link_local_dynamic_entry *entry;
+ struct elf_link_hash_table *eht;
+ struct bfd_strtab_hash *dynstr;
+ Elf_External_Sym esym;
+ unsigned long dynstr_index;
+ char *name;
+
+ /* See if the entry exists already. */
+ for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next)
+ if (entry->input_bfd == input_bfd && entry->input_indx == input_indx)
+ return true;
+
+ entry = (struct elf_link_local_dynamic_entry *)
+ bfd_alloc (input_bfd, sizeof (*entry));
+ if (entry == NULL)
+ return false;
+
+ /* Go find the symbol, so that we can find it's name. */
+ if (bfd_seek (input_bfd,
+ (elf_tdata (input_bfd)->symtab_hdr.sh_offset
+ + input_indx * sizeof (Elf_External_Sym)),
+ SEEK_SET) != 0
+ || (bfd_read (&esym, sizeof (Elf_External_Sym), 1, input_bfd)
+ != sizeof (Elf_External_Sym)))
+ return false;
+ elf_swap_symbol_in (input_bfd, &esym, &entry->isym);
+
+ name = (bfd_elf_string_from_elf_section
+ (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link,
+ entry->isym.st_name));
+
+ dynstr = elf_hash_table (info)->dynstr;
+ if (dynstr == NULL)
+ {
+ /* Create a strtab to hold the dynamic symbol names. */
+ elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init ();
+ if (dynstr == NULL)
+ return false;
+ }
+
+ dynstr_index = _bfd_stringtab_add (dynstr, name, true, false);
+ if (dynstr_index == (unsigned long) -1)
+ return false;
+ entry->isym.st_name = dynstr_index;
+
+ eht = elf_hash_table (info);
+
+ entry->next = eht->dynlocal;
+ eht->dynlocal = entry;
+ entry->input_bfd = input_bfd;
+ entry->input_indx = input_indx;
+ eht->dynsymcount++;
+
+ /* The dynindx will be set at the end of size_dynamic_sections. */
+
+ return true;
+}
-/* Read and swap the relocs for a section. They may have been cached.
- If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are not NULL,
- they are used as buffers to read into. They are known to be large
- enough. If the INTERNAL_RELOCS relocs argument is NULL, the return
- value is allocated using either malloc or bfd_alloc, according to
- the KEEP_MEMORY argument. */
+/* Read and swap the relocs from the section indicated by SHDR. This
+ may be either a REL or a RELA section. The relocations are
+ translated into RELA relocations and stored in INTERNAL_RELOCS,
+ which should have already been allocated to contain enough space.
+ The EXTERNAL_RELOCS are a buffer where the external form of the
+ relocations should be stored.
+
+ Returns false if something goes wrong. */
+
+static boolean
+elf_link_read_relocs_from_section (abfd, shdr, external_relocs,
+ internal_relocs)
+ bfd *abfd;
+ Elf_Internal_Shdr *shdr;
+ PTR external_relocs;
+ Elf_Internal_Rela *internal_relocs;
+{
+ struct elf_backend_data *bed;
+
+ /* If there aren't any relocations, that's OK. */
+ if (!shdr)
+ return true;
+
+ /* Position ourselves at the start of the section. */
+ if (bfd_seek (abfd, shdr->sh_offset, SEEK_SET) != 0)
+ return false;
+
+ /* Read the relocations. */
+ if (bfd_read (external_relocs, 1, shdr->sh_size, abfd)
+ != shdr->sh_size)
+ return false;
+
+ bed = get_elf_backend_data (abfd);
+
+ /* Convert the external relocations to the internal format. */
+ if (shdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+ Elf_External_Rel *erelend;
+ Elf_Internal_Rela *irela;
+ Elf_Internal_Rel *irel;
+
+ erel = (Elf_External_Rel *) external_relocs;
+ erelend = erel + shdr->sh_size / shdr->sh_entsize;
+ irela = internal_relocs;
+ irel = bfd_alloc (abfd, (bed->s->int_rels_per_ext_rel
+ * sizeof (Elf_Internal_Rel)));
+ for (; erel < erelend; erel++, irela += bed->s->int_rels_per_ext_rel)
+ {
+ unsigned char i;
+
+ if (bed->s->swap_reloc_in)
+ (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel);
+ else
+ elf_swap_reloc_in (abfd, erel, irel);
+
+ for (i = 0; i < bed->s->int_rels_per_ext_rel; ++i)
+ {
+ irela[i].r_offset = irel[i].r_offset;
+ irela[i].r_info = irel[i].r_info;
+ irela[i].r_addend = 0;
+ }
+ }
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+ Elf_External_Rela *erelaend;
+ Elf_Internal_Rela *irela;
+
+ BFD_ASSERT (shdr->sh_entsize == sizeof (Elf_External_Rela));
+
+ erela = (Elf_External_Rela *) external_relocs;
+ erelaend = erela + shdr->sh_size / shdr->sh_entsize;
+ irela = internal_relocs;
+ for (; erela < erelaend; erela++, irela += bed->s->int_rels_per_ext_rel)
+ {
+ if (bed->s->swap_reloca_in)
+ (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela);
+ else
+ elf_swap_reloca_in (abfd, erela, irela);
+ }
+ }
+
+ return true;
+}
+
+/* Read and swap the relocs for a section O. They may have been
+ cached. If the EXTERNAL_RELOCS and INTERNAL_RELOCS arguments are
+ not NULL, they are used as buffers to read into. They are known to
+ be large enough. If the INTERNAL_RELOCS relocs argument is NULL,
+ the return value is allocated using either malloc or bfd_alloc,
+ according to the KEEP_MEMORY argument. If O has two relocation
+ sections (both REL and RELA relocations), then the REL_HDR
+ relocations will appear first in INTERNAL_RELOCS, followed by the
+ REL_HDR2 relocations. */
Elf_Internal_Rela *
NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
@@ -2010,6 +2231,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
Elf_Internal_Shdr *rel_hdr;
PTR alloc1 = NULL;
Elf_Internal_Rela *alloc2 = NULL;
+ struct elf_backend_data *bed = get_elf_backend_data (abfd);
if (elf_section_data (o)->relocs != NULL)
return elf_section_data (o)->relocs;
@@ -2023,7 +2245,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
{
size_t size;
- size = o->reloc_count * sizeof (Elf_Internal_Rela);
+ size = (o->reloc_count * bed->s->int_rels_per_ext_rel
+ * sizeof (Elf_Internal_Rela));
if (keep_memory)
internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size);
else
@@ -2034,53 +2257,27 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
if (external_relocs == NULL)
{
- alloc1 = (PTR) bfd_malloc ((size_t) rel_hdr->sh_size);
+ size_t size = (size_t) rel_hdr->sh_size;
+
+ if (elf_section_data (o)->rel_hdr2)
+ size += (size_t) elf_section_data (o)->rel_hdr2->sh_size;
+ alloc1 = (PTR) bfd_malloc (size);
if (alloc1 == NULL)
goto error_return;
external_relocs = alloc1;
}
- if ((bfd_seek (abfd, rel_hdr->sh_offset, SEEK_SET) != 0)
- || (bfd_read (external_relocs, 1, rel_hdr->sh_size, abfd)
- != rel_hdr->sh_size))
+ if (!elf_link_read_relocs_from_section (abfd, rel_hdr,
+ external_relocs,
+ internal_relocs))
+ goto error_return;
+ if (!elf_link_read_relocs_from_section
+ (abfd,
+ elf_section_data (o)->rel_hdr2,
+ ((bfd_byte *) external_relocs) + rel_hdr->sh_size,
+ internal_relocs + (rel_hdr->sh_size / rel_hdr->sh_entsize
+ * bed->s->int_rels_per_ext_rel)))
goto error_return;
-
- /* Swap in the relocs. For convenience, we always produce an
- Elf_Internal_Rela array; if the relocs are Rel, we set the addend
- to 0. */
- if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
- {
- Elf_External_Rel *erel;
- Elf_External_Rel *erelend;
- Elf_Internal_Rela *irela;
-
- erel = (Elf_External_Rel *) external_relocs;
- erelend = erel + o->reloc_count;
- irela = internal_relocs;
- for (; erel < erelend; erel++, irela++)
- {
- Elf_Internal_Rel irel;
-
- elf_swap_reloc_in (abfd, erel, &irel);
- irela->r_offset = irel.r_offset;
- irela->r_info = irel.r_info;
- irela->r_addend = 0;
- }
- }
- else
- {
- Elf_External_Rela *erela;
- Elf_External_Rela *erelaend;
- Elf_Internal_Rela *irela;
-
- BFD_ASSERT (rel_hdr->sh_entsize == sizeof (Elf_External_Rela));
-
- erela = (Elf_External_Rela *) external_relocs;
- erelaend = erela + o->reloc_count;
- irela = internal_relocs;
- for (; erela < erelaend; erela++, irela++)
- elf_swap_reloca_in (abfd, erela, irela);
- }
/* Cache the results for next time, if we can. */
if (keep_memory)
@@ -2109,7 +2306,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs,
/*ARGSUSED*/
boolean
NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide)
- bfd *output_bfd;
+ bfd *output_bfd ATTRIBUTE_UNUSED;
struct bfd_link_info *info;
const char *name;
boolean provide;
@@ -2182,8 +2379,6 @@ struct elf_assign_sym_version_info
struct bfd_elf_version_tree *verdefs;
/* Whether we are exporting all dynamic symbols. */
boolean export_dynamic;
- /* Whether we removed any symbols from the dynamic symbol table. */
- boolean removed_dynamic;
/* Whether we had a failure. */
boolean failed;
};
@@ -2228,7 +2423,7 @@ compute_bucket_count (info)
struct bfd_link_info *info;
{
size_t dynsymcount = elf_hash_table (info)->dynsymcount;
- size_t best_size;
+ size_t best_size = 0;
unsigned long int *hashcodes;
unsigned long int *hashcodesp;
unsigned long int i;
@@ -2381,7 +2576,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
bfd_size_type soname_indx;
bfd *dynobj;
struct elf_backend_data *bed;
- bfd_size_type old_dynsymcount;
struct elf_assign_sym_version_info asvinfo;
*sinterpptr = NULL;
@@ -2486,7 +2680,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
asvinfo.info = info;
asvinfo.verdefs = verdefs;
asvinfo.export_dynamic = export_dynamic;
- asvinfo.removed_dynamic = false;
asvinfo.failed = false;
elf_link_hash_traverse (elf_hash_table (info),
@@ -2508,8 +2701,14 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
/* Add some entries to the .dynamic section. We fill in some of the
values later, in elf_bfd_final_link, but we must add the entries
now so that we know the final size of the .dynamic section. */
- h = elf_link_hash_lookup (elf_hash_table (info), "_init", false,
- false, false);
+
+ /* If there are initialization and/or finalization functions to
+ call then add the corresponding DT_INIT/DT_FINI entries. */
+ h = (info->init_function
+ ? elf_link_hash_lookup (elf_hash_table (info),
+ info->init_function, false,
+ false, false)
+ : NULL);
if (h != NULL
&& (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
| ELF_LINK_HASH_DEF_REGULAR)) != 0)
@@ -2517,8 +2716,11 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
if (! elf_add_dynamic_entry (info, DT_INIT, 0))
return false;
}
- h = elf_link_hash_lookup (elf_hash_table (info), "_fini", false,
- false, false);
+ h = (info->fini_function
+ ? elf_link_hash_lookup (elf_hash_table (info),
+ info->fini_function, false,
+ false, false)
+ : NULL);
if (h != NULL
&& (h->elf_link_hash_flags & (ELF_LINK_HASH_REF_REGULAR
| ELF_LINK_HASH_DEF_REGULAR)) != 0)
@@ -2526,6 +2728,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
if (! elf_add_dynamic_entry (info, DT_FINI, 0))
return false;
}
+
strsize = _bfd_stringtab_size (elf_hash_table (info)->dynstr);
if (! elf_add_dynamic_entry (info, DT_HASH, 0)
|| ! elf_add_dynamic_entry (info, DT_STRTAB, 0)
@@ -2538,7 +2741,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
/* The backend must work out the sizes of all the other dynamic
sections. */
- old_dynsymcount = elf_hash_table (info)->dynsymcount;
if (bed->elf_backend_size_dynamic_sections
&& ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info))
return false;
@@ -2549,6 +2751,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
asection *s;
size_t bucketcount = 0;
Elf_Internal_Sym isym;
+ size_t hash_entry_size;
/* Set up the version definition section. */
s = bfd_get_section_by_name (dynobj, ".gnu.version_d");
@@ -2559,17 +2762,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
verdefs = asvinfo.verdefs;
if (verdefs == NULL)
- {
- asection **spp;
-
- /* Don't include this section in the output file. */
- for (spp = &output_bfd->sections;
- *spp != s->output_section;
- spp = &(*spp)->next)
- ;
- *spp = s->output_section->next;
- --output_bfd->section_count;
- }
+ _bfd_strip_section_from_output (s);
else
{
unsigned int cdefs;
@@ -2579,23 +2772,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
Elf_Internal_Verdef def;
Elf_Internal_Verdaux defaux;
- if (asvinfo.removed_dynamic)
- {
- /* Some dynamic symbols were changed to be local
- symbols. In this case, we renumber all of the
- dynamic symbols, so that we don't have a hole. If
- the backend changed dynsymcount, then assume that the
- new symbols are at the start. This is the case on
- the MIPS. FIXME: The names of the removed symbols
- will still be in the dynamic string table, wasting
- space. */
- elf_hash_table (info)->dynsymcount =
- 1 + (elf_hash_table (info)->dynsymcount - old_dynsymcount);
- elf_link_hash_traverse (elf_hash_table (info),
- elf_link_renumber_dynsyms,
- (PTR) info);
- }
-
cdefs = 0;
size = 0;
@@ -2635,7 +2811,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
if (soname_indx != (bfd_size_type) -1)
{
- def.vd_hash = bfd_elf_hash ((const unsigned char *) soname);
+ def.vd_hash = bfd_elf_hash (soname);
defaux.vda_name = soname_indx;
}
else
@@ -2644,7 +2820,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
bfd_size_type indx;
name = output_bfd->filename;
- def.vd_hash = bfd_elf_hash ((const unsigned char *) name);
+ def.vd_hash = bfd_elf_hash (name);
indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
name, true, false);
if (indx == (bfd_size_type) -1)
@@ -2692,7 +2868,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
def.vd_flags |= VER_FLG_WEAK;
def.vd_ndx = t->vernum + 1;
def.vd_cnt = cdeps + 1;
- def.vd_hash = bfd_elf_hash ((const unsigned char *) t->name);
+ def.vd_hash = bfd_elf_hash (t->name);
def.vd_aux = sizeof (Elf_External_Verdef);
if (t->next != NULL)
def.vd_next = (sizeof (Elf_External_Verdef)
@@ -2762,19 +2938,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
(PTR) &sinfo);
if (elf_tdata (output_bfd)->verref == NULL)
- {
- asection **spp;
-
- /* We don't have any version definitions, so we can just
- remove the section. */
-
- for (spp = &output_bfd->sections;
- *spp != s->output_section;
- spp = &(*spp)->next)
- ;
- *spp = s->output_section->next;
- --output_bfd->section_count;
- }
+ _bfd_strip_section_from_output (s);
else
{
Elf_Internal_Verneed *t;
@@ -2840,8 +3004,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr)
{
- a->vna_hash = bfd_elf_hash ((const unsigned char *)
- a->vna_nodename);
+ a->vna_hash = bfd_elf_hash (a->vna_nodename);
indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr,
a->vna_nodename, true, false);
if (indx == (bfd_size_type) -1)
@@ -2866,7 +3029,12 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
}
}
- dynsymcount = elf_hash_table (info)->dynsymcount;
+ /* Assign dynsym indicies. In a shared library we generate a
+ section symbol for each output section, which come first.
+ Next come all of the back-end allocated local dynamic syms,
+ followed by the rest of the global symbols. */
+
+ dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
/* Work out the size of the symbol version section. */
s = bfd_get_section_by_name (dynobj, ".gnu.version");
@@ -2874,16 +3042,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
if (dynsymcount == 0
|| (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL))
{
- asection **spp;
-
- /* We don't need any symbol versions; just discard the
- section. */
- for (spp = &output_bfd->sections;
- *spp != s->output_section;
- spp = &(*spp)->next)
- ;
- *spp = s->output_section->next;
- --output_bfd->section_count;
+ _bfd_strip_section_from_output (s);
+ /* The DYNSYMCOUNT might have changed if we were going to
+ output a dynamic symbol table entry for S. */
+ dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info);
}
else
{
@@ -2925,14 +3087,16 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath,
s = bfd_get_section_by_name (dynobj, ".hash");
BFD_ASSERT (s != NULL);
- s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8);
+ hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize;
+ s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size);
s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size);
if (s->contents == NULL)
return false;
memset (s->contents, 0, (size_t) s->_raw_size);
- put_word (output_bfd, bucketcount, s->contents);
- put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8));
+ bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents);
+ bfd_put (8 * hash_entry_size, output_bfd, dynsymcount,
+ s->contents + hash_entry_size);
elf_hash_table (info)->bucketcount = bucketcount;
@@ -3365,7 +3529,6 @@ elf_link_assign_sym_version (h, data)
&& info->shared
&& ! sinfo->export_dynamic)
{
- sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
h->elf_link_hash_flags &=~
ELF_LINK_HASH_NEEDS_PLT;
@@ -3481,7 +3644,6 @@ elf_link_assign_sym_version (h, data)
&& info->shared
&& ! sinfo->export_dynamic)
{
- sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
h->dynindx = -1;
@@ -3506,7 +3668,6 @@ elf_link_assign_sym_version (h, data)
&& info->shared
&& ! sinfo->export_dynamic)
{
- sinfo->removed_dynamic = true;
h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL;
h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT;
h->dynindx = -1;
@@ -3519,26 +3680,6 @@ elf_link_assign_sym_version (h, data)
return true;
}
-
-/* This function is used to renumber the dynamic symbols, if some of
- them are removed because they are marked as local. This is called
- via elf_link_hash_traverse. */
-
-static boolean
-elf_link_renumber_dynsyms (h, data)
- struct elf_link_hash_entry *h;
- PTR data;
-{
- struct bfd_link_info *info = (struct bfd_link_info *) data;
-
- if (h->dynindx != -1)
- {
- h->dynindx = elf_hash_table (info)->dynsymcount;
- ++elf_hash_table (info)->dynsymcount;
- }
-
- return true;
-}
/* Final phase of ELF linker. */
@@ -3606,6 +3747,97 @@ struct elf_outext_info
struct elf_final_link_info *finfo;
};
+/* Compute the size of, and allocate space for, REL_HDR which is the
+ section header for a section containing relocations for O. */
+
+static boolean
+elf_link_size_reloc_section (abfd, rel_hdr, o)
+ bfd *abfd;
+ Elf_Internal_Shdr *rel_hdr;
+ asection *o;
+{
+ register struct elf_link_hash_entry **p, **pend;
+
+ /* We are overestimating the size required for the relocation
+ sections, in the case that we are using both REL and RELA
+ relocations for a single section. In that case, RELOC_COUNT will
+ be the total number of relocations required, and we allocate
+ space for that many REL relocations as well as that many RELA
+ relocations. This approximation is wasteful of disk space.
+ However, until we keep track of how many of each kind of
+ relocation is required, it's difficult to calculate the right
+ value. */
+ rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
+
+ /* The contents field must last into write_object_contents, so we
+ allocate it with bfd_alloc rather than malloc. */
+ rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
+ if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
+ return false;
+
+ p = ((struct elf_link_hash_entry **)
+ bfd_malloc (o->reloc_count
+ * sizeof (struct elf_link_hash_entry *)));
+ if (p == NULL && o->reloc_count != 0)
+ return false;
+
+ elf_section_data (o)->rel_hashes = p;
+ pend = p + o->reloc_count;
+ for (; p < pend; p++)
+ *p = NULL;
+
+ return true;
+}
+
+/* When performing a relocateable link, the input relocations are
+ preserved. But, if they reference global symbols, the indices
+ referenced must be updated. Update all the relocations in
+ REL_HDR (there are COUNT of them), using the data in REL_HASH. */
+
+static void
+elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash)
+ bfd *abfd;
+ Elf_Internal_Shdr *rel_hdr;
+ unsigned int count;
+ struct elf_link_hash_entry **rel_hash;
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++, rel_hash++)
+ {
+ if (*rel_hash == NULL)
+ continue;
+
+ BFD_ASSERT ((*rel_hash)->indx >= 0);
+
+ if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+ Elf_Internal_Rel irel;
+
+ erel = (Elf_External_Rel *) rel_hdr->contents + i;
+ elf_swap_reloc_in (abfd, erel, &irel);
+ irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irel.r_info));
+ elf_swap_reloc_out (abfd, &irel, erel);
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+ Elf_Internal_Rela irela;
+
+ BFD_ASSERT (rel_hdr->sh_entsize
+ == sizeof (Elf_External_Rela));
+
+ erela = (Elf_External_Rela *) rel_hdr->contents + i;
+ elf_swap_reloca_in (abfd, erela, &irela);
+ irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
+ ELF_R_TYPE (irela.r_info));
+ elf_swap_reloca_out (abfd, &irela, erela);
+ }
+ }
+}
+
/* Do the final step of an ELF link. */
boolean
@@ -3767,32 +3999,16 @@ elf_bfd_final_link (abfd, info)
{
if ((o->flags & SEC_RELOC) != 0)
{
- Elf_Internal_Shdr *rel_hdr;
- register struct elf_link_hash_entry **p, **pend;
-
- rel_hdr = &elf_section_data (o)->rel_hdr;
-
- rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count;
-
- /* The contents field must last into write_object_contents,
- so we allocate it with bfd_alloc rather than malloc. */
- rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size);
- if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0)
+ if (!elf_link_size_reloc_section (abfd,
+ &elf_section_data (o)->rel_hdr,
+ o))
goto error_return;
- p = ((struct elf_link_hash_entry **)
- bfd_malloc (o->reloc_count
- * sizeof (struct elf_link_hash_entry *)));
- if (p == NULL && o->reloc_count != 0)
+ if (elf_section_data (o)->rel_hdr2
+ && !elf_link_size_reloc_section (abfd,
+ elf_section_data (o)->rel_hdr2,
+ o))
goto error_return;
- elf_section_data (o)->rel_hashes = p;
- pend = p + o->reloc_count;
- for (; p < pend; p++)
- *p = NULL;
-
- /* Use the reloc_count field as an index when outputting the
- relocs. */
- o->reloc_count = 0;
}
}
@@ -3895,7 +4111,8 @@ elf_bfd_final_link (abfd, info)
finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size);
finfo.internal_relocs = ((Elf_Internal_Rela *)
bfd_malloc (max_internal_reloc_count
- * sizeof (Elf_Internal_Rela)));
+ * sizeof (Elf_Internal_Rela)
+ * bed->s->int_rels_per_ext_rel));
finfo.external_syms = ((Elf_External_Sym *)
bfd_malloc (max_sym_count
* sizeof (Elf_External_Sym)));
@@ -3986,11 +4203,77 @@ elf_bfd_final_link (abfd, info)
return false;
}
- /* The sh_info field records the index of the first non local
- symbol. */
+ /* The sh_info field records the index of the first non local symbol. */
symtab_hdr->sh_info = bfd_get_symcount (abfd);
+
if (dynamic)
- elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1;
+ {
+ Elf_Internal_Sym sym;
+ Elf_External_Sym *dynsym =
+ (Elf_External_Sym *)finfo.dynsym_sec->contents;
+ unsigned long last_local = 0;
+
+ /* Write out the section symbols for the output sections. */
+ if (info->shared)
+ {
+ asection *s;
+
+ sym.st_size = 0;
+ sym.st_name = 0;
+ sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION);
+ sym.st_other = 0;
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ int indx;
+ indx = elf_section_data (s)->this_idx;
+ BFD_ASSERT (indx > 0);
+ sym.st_shndx = indx;
+ sym.st_value = s->vma;
+
+ elf_swap_symbol_out (abfd, &sym,
+ dynsym + elf_section_data (s)->dynindx);
+ }
+
+ last_local = bfd_count_sections (abfd);
+ }
+
+ /* Write out the local dynsyms. */
+ if (elf_hash_table (info)->dynlocal)
+ {
+ struct elf_link_local_dynamic_entry *e;
+ for (e = elf_hash_table (info)->dynlocal; e ; e = e->next)
+ {
+ asection *s;
+
+ sym.st_size = e->isym.st_size;
+ sym.st_other = e->isym.st_other;
+
+ /* Note that we saved a word of storage and overwrote
+ the original st_name with the dynstr_index. */
+ sym.st_name = e->isym.st_name;
+
+ /* Whatever binding the symbol had before, it's now local. */
+ sym.st_info = ELF_ST_INFO (STB_LOCAL,
+ ELF_ST_TYPE (e->isym.st_info));
+
+ s = bfd_section_from_elf_index (e->input_bfd, e->isym.st_shndx);
+
+ sym.st_shndx = elf_section_data (s->output_section)->this_idx;
+ sym.st_value = (s->output_section->vma
+ + s->output_offset
+ + e->isym.st_value);
+
+ if (last_local < e->dynindx)
+ last_local = e->dynindx;
+
+ elf_swap_symbol_out (abfd, &sym, dynsym + e->dynindx);
+ }
+ }
+
+ elf_section_data (finfo.dynsym_sec->output_section)
+ ->this_hdr.sh_info = last_local;
+ }
/* We get the global symbols from the hash table. */
eoinfo.failed = false;
@@ -4035,47 +4318,17 @@ elf_bfd_final_link (abfd, info)
/* Adjust the relocs to have the correct symbol indices. */
for (o = abfd->sections; o != NULL; o = o->next)
{
- struct elf_link_hash_entry **rel_hash;
- Elf_Internal_Shdr *rel_hdr;
-
if ((o->flags & SEC_RELOC) == 0)
continue;
- rel_hash = elf_section_data (o)->rel_hashes;
- rel_hdr = &elf_section_data (o)->rel_hdr;
- for (i = 0; i < o->reloc_count; i++, rel_hash++)
- {
- if (*rel_hash == NULL)
- continue;
-
- BFD_ASSERT ((*rel_hash)->indx >= 0);
-
- if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
- {
- Elf_External_Rel *erel;
- Elf_Internal_Rel irel;
-
- erel = (Elf_External_Rel *) rel_hdr->contents + i;
- elf_swap_reloc_in (abfd, erel, &irel);
- irel.r_info = ELF_R_INFO ((*rel_hash)->indx,
- ELF_R_TYPE (irel.r_info));
- elf_swap_reloc_out (abfd, &irel, erel);
- }
- else
- {
- Elf_External_Rela *erela;
- Elf_Internal_Rela irela;
-
- BFD_ASSERT (rel_hdr->sh_entsize
- == sizeof (Elf_External_Rela));
-
- erela = (Elf_External_Rela *) rel_hdr->contents + i;
- elf_swap_reloca_in (abfd, erela, &irela);
- irela.r_info = ELF_R_INFO ((*rel_hash)->indx,
- ELF_R_TYPE (irela.r_info));
- elf_swap_reloca_out (abfd, &irela, erela);
- }
- }
+ elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr,
+ elf_section_data (o)->rel_count,
+ elf_section_data (o)->rel_hashes);
+ if (elf_section_data (o)->rel_hdr2 != NULL)
+ elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2,
+ elf_section_data (o)->rel_count2,
+ (elf_section_data (o)->rel_hashes
+ + elf_section_data (o)->rel_count));
/* Set the reloc_count field to 0 to prevent write_relocs from
trying to swap the relocs out itself. */
@@ -4106,15 +4359,11 @@ elf_bfd_final_link (abfd, info)
{
default:
break;
-
- /* SVR4 linkers seem to set DT_INIT and DT_FINI based on
- magic _init and _fini symbols. This is pretty ugly,
- but we are compatible. */
case DT_INIT:
- name = "_init";
+ name = info->init_function;
goto get_sym;
case DT_FINI:
- name = "_fini";
+ name = info->fini_function;
get_sym:
{
struct elf_link_hash_entry *h;
@@ -4423,7 +4672,6 @@ elf_link_output_extsym (h, data)
warnings for them. */
if (! finfo->info->relocateable
&& ! (finfo->info->shared
- && !finfo->info->symbolic
&& !finfo->info->no_undefined)
&& h->root.type == bfd_link_hash_undefined
&& (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) != 0
@@ -4594,6 +4842,7 @@ elf_link_output_extsym (h, data)
{
size_t bucketcount;
size_t bucket;
+ size_t hash_entry_size;
bfd_byte *bucketpos;
bfd_vma chain;
@@ -4606,13 +4855,15 @@ elf_link_output_extsym (h, data)
bucketcount = elf_hash_table (finfo->info)->bucketcount;
bucket = h->elf_hash_value % bucketcount;
+ hash_entry_size
+ = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize;
bucketpos = ((bfd_byte *) finfo->hash_sec->contents
- + (bucket + 2) * (ARCH_SIZE / 8));
- chain = get_word (finfo->output_bfd, bucketpos);
- put_word (finfo->output_bfd, h->dynindx, bucketpos);
- put_word (finfo->output_bfd, chain,
- ((bfd_byte *) finfo->hash_sec->contents
- + (bucketcount + 2 + h->dynindx) * (ARCH_SIZE / 8)));
+ + (bucket + 2) * hash_entry_size);
+ chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos);
+ bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos);
+ bfd_put (8 * hash_entry_size, finfo->output_bfd, chain,
+ ((bfd_byte *) finfo->hash_sec->contents
+ + (bucketcount + 2 + h->dynindx) * hash_entry_size));
if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL)
{
@@ -4659,6 +4910,76 @@ elf_link_output_extsym (h, data)
return true;
}
+/* Copy the relocations indicated by the INTERNAL_RELOCS (which
+ originated from the section given by INPUT_REL_HDR) to the
+ OUTPUT_BFD. */
+
+static void
+elf_link_output_relocs (output_bfd, input_section, input_rel_hdr,
+ internal_relocs)
+ bfd *output_bfd;
+ asection *input_section;
+ Elf_Internal_Shdr *input_rel_hdr;
+ Elf_Internal_Rela *internal_relocs;
+{
+ Elf_Internal_Rela *irela;
+ Elf_Internal_Rela *irelaend;
+ Elf_Internal_Shdr *output_rel_hdr;
+ asection *output_section;
+ unsigned int *rel_countp = NULL;
+
+ output_section = input_section->output_section;
+ output_rel_hdr = NULL;
+
+ if (elf_section_data (output_section)->rel_hdr.sh_entsize
+ == input_rel_hdr->sh_entsize)
+ {
+ output_rel_hdr = &elf_section_data (output_section)->rel_hdr;
+ rel_countp = &elf_section_data (output_section)->rel_count;
+ }
+ else if (elf_section_data (output_section)->rel_hdr2
+ && (elf_section_data (output_section)->rel_hdr2->sh_entsize
+ == input_rel_hdr->sh_entsize))
+ {
+ output_rel_hdr = elf_section_data (output_section)->rel_hdr2;
+ rel_countp = &elf_section_data (output_section)->rel_count2;
+ }
+
+ BFD_ASSERT (output_rel_hdr != NULL);
+
+ irela = internal_relocs;
+ irelaend = irela + input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+ if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
+ {
+ Elf_External_Rel *erel;
+
+ erel = ((Elf_External_Rel *) output_rel_hdr->contents + *rel_countp);
+ for (; irela < irelaend; irela++, erel++)
+ {
+ Elf_Internal_Rel irel;
+
+ irel.r_offset = irela->r_offset;
+ irel.r_info = irela->r_info;
+ BFD_ASSERT (irela->r_addend == 0);
+ elf_swap_reloc_out (output_bfd, &irel, erel);
+ }
+ }
+ else
+ {
+ Elf_External_Rela *erela;
+
+ BFD_ASSERT (input_rel_hdr->sh_entsize
+ == sizeof (Elf_External_Rela));
+ erela = ((Elf_External_Rela *) output_rel_hdr->contents + *rel_countp);
+ for (; irela < irelaend; irela++, erela++)
+ elf_swap_reloca_out (output_bfd, irela, erela);
+ }
+
+ /* Bump the counter, so that we know where to add the next set of
+ relocations. */
+ *rel_countp += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+}
+
/* Link an input file into the linker output file. This function
handles all the sections and relocations of the input file at once.
This is so that we only have to read the local symbols once, and
@@ -4684,10 +5005,11 @@ elf_link_input_bfd (finfo, input_bfd)
long *pindex;
asection **ppsection;
asection *o;
+ struct elf_backend_data *bed;
output_bfd = finfo->output_bfd;
- relocate_section =
- get_elf_backend_data (output_bfd)->elf_backend_relocate_section;
+ bed = get_elf_backend_data (output_bfd);
+ relocate_section = bed->elf_backend_relocate_section;
/* If this is a dynamic object, we don't want to do anything here:
we don't want the local symbols, and we don't want the section
@@ -4920,14 +5242,15 @@ elf_link_input_bfd (finfo, input_bfd)
Elf_Internal_Rela *irelaend;
struct elf_link_hash_entry **rel_hash;
Elf_Internal_Shdr *input_rel_hdr;
- Elf_Internal_Shdr *output_rel_hdr;
/* Adjust the reloc addresses and symbol indices. */
irela = internal_relocs;
- irelaend = irela + o->reloc_count;
+ irelaend =
+ irela + o->reloc_count * bed->s->int_rels_per_ext_rel;
rel_hash = (elf_section_data (o->output_section)->rel_hashes
- + o->output_section->reloc_count);
+ + elf_section_data (o->output_section)->rel_count
+ + elf_section_data (o->output_section)->rel_count2);
for (; irela < irelaend; irela++, rel_hash++)
{
unsigned long r_symndx;
@@ -5051,40 +5374,16 @@ elf_link_input_bfd (finfo, input_bfd)
/* Swap out the relocs. */
input_rel_hdr = &elf_section_data (o)->rel_hdr;
- output_rel_hdr = &elf_section_data (o->output_section)->rel_hdr;
- BFD_ASSERT (output_rel_hdr->sh_entsize
- == input_rel_hdr->sh_entsize);
- irela = internal_relocs;
- irelaend = irela + o->reloc_count;
- if (input_rel_hdr->sh_entsize == sizeof (Elf_External_Rel))
- {
- Elf_External_Rel *erel;
-
- erel = ((Elf_External_Rel *) output_rel_hdr->contents
- + o->output_section->reloc_count);
- for (; irela < irelaend; irela++, erel++)
- {
- Elf_Internal_Rel irel;
-
- irel.r_offset = irela->r_offset;
- irel.r_info = irela->r_info;
- BFD_ASSERT (irela->r_addend == 0);
- elf_swap_reloc_out (output_bfd, &irel, erel);
- }
- }
- else
- {
- Elf_External_Rela *erela;
-
- BFD_ASSERT (input_rel_hdr->sh_entsize
- == sizeof (Elf_External_Rela));
- erela = ((Elf_External_Rela *) output_rel_hdr->contents
- + o->output_section->reloc_count);
- for (; irela < irelaend; irela++, erela++)
- elf_swap_reloca_out (output_bfd, irela, erela);
- }
-
- o->output_section->reloc_count += o->reloc_count;
+ elf_link_output_relocs (output_bfd, o,
+ input_rel_hdr,
+ internal_relocs);
+ internal_relocs
+ += input_rel_hdr->sh_size / input_rel_hdr->sh_entsize;
+ input_rel_hdr = elf_section_data (o)->rel_hdr2;
+ if (input_rel_hdr)
+ elf_link_output_relocs (output_bfd, o,
+ input_rel_hdr,
+ internal_relocs);
}
}
@@ -5141,7 +5440,8 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
/* Figure out the symbol index. */
rel_hash_ptr = (elf_section_data (output_section)->rel_hashes
- + output_section->reloc_count);
+ + elf_section_data (output_section)->rel_count
+ + elf_section_data (output_section)->rel_count2);
if (link_order->type == bfd_section_reloc_link_order)
{
indx = link_order->u.reloc.p->u.section->target_index;
@@ -5250,7 +5550,7 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
irel.r_offset = offset;
irel.r_info = ELF_R_INFO (indx, howto->type);
erel = ((Elf_External_Rel *) rel_hdr->contents
- + output_section->reloc_count);
+ + elf_section_data (output_section)->rel_count);
elf_swap_reloc_out (output_bfd, &irel, erel);
}
else
@@ -5262,11 +5562,11 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order)
irela.r_info = ELF_R_INFO (indx, howto->type);
irela.r_addend = addend;
erela = ((Elf_External_Rela *) rel_hdr->contents
- + output_section->reloc_count);
+ + elf_section_data (output_section)->rel_count);
elf_swap_reloca_out (output_bfd, &irela, erela);
}
- ++output_section->reloc_count;
+ ++elf_section_data (output_section)->rel_count;
return true;
}
@@ -5486,8 +5786,8 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca
elf_swap_reloca_out (output_bfd, &outrel,
(((Elf_External_Rela *)
lsect->section->contents)
- + lsect->section->reloc_count));
- ++lsect->section->reloc_count;
+ + elf_section_data (lsect->section)->rel_count));
+ ++elf_section_data (lsect->section)->rel_count;
}
}
}
@@ -5559,6 +5859,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
size_t extsymoff;
Elf_External_Sym *locsyms, *freesyms = NULL;
bfd *input_bfd = sec->owner;
+ struct elf_backend_data *bed = get_elf_backend_data (input_bfd);
/* GCFIXME: how to arrange so that relocs and symbols are not
reread continually? */
@@ -5602,7 +5903,7 @@ elf_gc_mark (info, sec, gc_mark_hook)
ret = false;
goto out1;
}
- relend = relstart + sec->reloc_count;
+ relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
for (rel = relstart; rel < relend; rel++)
{
@@ -5808,6 +6109,7 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
asection *sec;
bfd_vma hstart, hend;
Elf_Internal_Rela *relstart, *relend, *rel;
+ struct elf_backend_data *bed;
/* Take care of both those symbols that do not describe vtables as
well as those that are not loaded. */
@@ -5825,7 +6127,8 @@ elf_gc_smash_unused_vtentry_relocs (h, okp)
(sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, true));
if (!relstart)
return *(boolean *)okp = false;
- relend = relstart + sec->reloc_count;
+ bed = get_elf_backend_data (sec->owner);
+ relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel;
for (rel = relstart; rel < relend; ++rel)
if (rel->r_offset >= hstart && rel->r_offset < hend)
@@ -5959,8 +6262,8 @@ win:
boolean
elf_gc_record_vtentry (abfd, sec, h, addend)
- bfd *abfd;
- asection *sec;
+ bfd *abfd ATTRIBUTE_UNUSED;
+ asection *sec ATTRIBUTE_UNUSED;
struct elf_link_hash_entry *h;
bfd_vma addend;
{