diff options
-rw-r--r-- | bfd/Makefile.am | 4 | ||||
-rw-r--r-- | bfd/Makefile.in | 5 | ||||
-rwxr-xr-x | bfd/configure | 34 | ||||
-rw-r--r-- | bfd/configure.ac | 34 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 1135 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 1143 | ||||
-rw-r--r-- | bfd/elfxx-x86.c | 580 | ||||
-rw-r--r-- | bfd/elfxx-x86.h | 283 |
8 files changed, 1392 insertions, 1826 deletions
diff --git a/bfd/Makefile.am b/bfd/Makefile.am index 97b608c..f7007a7 100644 --- a/bfd/Makefile.am +++ b/bfd/Makefile.am @@ -346,6 +346,7 @@ BFD32_BACKENDS = \ elf32-hppa.lo \ elf32-i370.lo \ elf32-i386.lo \ + elfxx-x86.lo \ elf32-i860.lo \ elf32-i960.lo \ elf32-ip2k.lo \ @@ -542,6 +543,7 @@ BFD32_BACKENDS_CFILES = \ elf32-hppa.c \ elf32-i370.c \ elf32-i386.c \ + elfxx-x86.c \ elf32-i860.c \ elf32-i960.c \ elf32-ip2k.c \ @@ -699,6 +701,7 @@ BFD64_BACKENDS = \ elf64-sparc.lo \ elf64-tilegx.lo \ elf64-x86-64.lo \ + elfxx-x86.lo \ elf64.lo \ mach-o-aarch64.lo \ mach-o-x86-64.lo \ @@ -734,6 +737,7 @@ BFD64_BACKENDS_CFILES = \ elf64-sparc.c \ elf64-tilegx.c \ elf64-x86-64.c \ + elfxx-x86.c \ elf64.c \ elfn32-mips.c \ elfxx-aarch64.c \ diff --git a/bfd/Makefile.in b/bfd/Makefile.in index e48abaf..86f0dc2 100644 --- a/bfd/Makefile.in +++ b/bfd/Makefile.in @@ -680,6 +680,7 @@ BFD32_BACKENDS = \ elf32-hppa.lo \ elf32-i370.lo \ elf32-i386.lo \ + elfxx-x86.lo \ elf32-i860.lo \ elf32-i960.lo \ elf32-ip2k.lo \ @@ -876,6 +877,7 @@ BFD32_BACKENDS_CFILES = \ elf32-hppa.c \ elf32-i370.c \ elf32-i386.c \ + elfxx-x86.c \ elf32-i860.c \ elf32-i960.c \ elf32-ip2k.c \ @@ -1034,6 +1036,7 @@ BFD64_BACKENDS = \ elf64-sparc.lo \ elf64-tilegx.lo \ elf64-x86-64.lo \ + elfxx-x86.lo \ elf64.lo \ mach-o-aarch64.lo \ mach-o-x86-64.lo \ @@ -1069,6 +1072,7 @@ BFD64_BACKENDS_CFILES = \ elf64-sparc.c \ elf64-tilegx.c \ elf64-x86-64.c \ + elfxx-x86.c \ elf64.c \ elfn32-mips.c \ elfxx-aarch64.c \ @@ -1574,6 +1578,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-riscv.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-sparc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-tilegx.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/elfxx-x86.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epoc-pe-arm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/epoc-pei-arm.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/format.Plo@am__quote@ diff --git a/bfd/configure b/bfd/configure index 4827659..32ee062 100755 --- a/bfd/configure +++ b/bfd/configure @@ -14391,17 +14391,17 @@ do i386_coff_go32_vec) tb="$tb coff-go32.lo $coff" ;; i386_coff_go32stubbed_vec) tb="$tb coff-stgo32.lo $coff" ;; i386_coff_lynx_vec) tb="$tb cf-i386lynx.lo lynx-core.lo $coff" ;; - i386_elf32_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_fbsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_nacl_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_vxworks_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_fbsd_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_nacl_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_sol2_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_vxworks_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; i386_mach_o_vec) tb="$tb mach-o-i386.lo" ;; i386_msdos_vec) tb="$tb i386msdos.lo" ;; i386_nlm32_vec) tb="$tb nlm32-i386.lo nlm32.lo nlm.lo" ;; i386_pe_vec) tb="$tb pe-i386.lo peigen.lo $coff" ;; i386_pei_vec) tb="$tb pei-i386.lo peigen.lo $coff" ;; - iamcu_elf32_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + iamcu_elf32_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; i860_coff_vec) tb="$tb coff-i860.lo $coff" ;; i860_elf32_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; i860_elf32_le_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; @@ -14418,10 +14418,10 @@ do ieee_vec) tb="$tb ieee.lo" ;; ip2k_elf32_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;; iq2000_elf32_vec) tb="$tb elf32-iq2000.lo elf32.lo $elf" ;; - k1om_elf64_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - k1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - l1om_elf64_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - l1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + k1om_elf64_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + k1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + l1om_elf64_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + l1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; lm32_elf32_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; lm32_elf32_fdpic_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; m32c_elf32_vec) tb="$tb elf32-m32c.lo elf32.lo $elf" ;; @@ -14623,13 +14623,13 @@ do wasm32_elf32_vec) tb="$tb elf32-wasm32.lo elf32.lo $elf" ;; we32k_coff_vec) tb="$tb coff-we32k.lo $coffgen" ;; x86_64_coff_vec) tb="$tb coff-x86_64.lo $coff"; target_size=64 ;; - x86_64_elf32_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; - x86_64_elf32_nacl_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; - x86_64_elf64_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_cloudabi_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_nacl_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_sol2_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf32_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; + x86_64_elf32_nacl_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; + x86_64_elf64_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_cloudabi_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_nacl_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_sol2_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; x86_64_mach_o_vec) tb="$tb mach-o-x86-64.lo" ;; x86_64_pe_vec) tb="$tb pe-x86_64.lo pex64igen.lo $coff"; target_size=64 ;; x86_64_pe_be_vec) tb="$tb pe-x86_64.lo pex64igen.lo $coff"; target_size=64 ;; diff --git a/bfd/configure.ac b/bfd/configure.ac index 8fd03a7..0e4c669 100644 --- a/bfd/configure.ac +++ b/bfd/configure.ac @@ -473,17 +473,17 @@ do i386_coff_go32_vec) tb="$tb coff-go32.lo $coff" ;; i386_coff_go32stubbed_vec) tb="$tb coff-stgo32.lo $coff" ;; i386_coff_lynx_vec) tb="$tb cf-i386lynx.lo lynx-core.lo $coff" ;; - i386_elf32_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_fbsd_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_nacl_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_sol2_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; - i386_elf32_vxworks_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_fbsd_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_nacl_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_sol2_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + i386_elf32_vxworks_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; i386_mach_o_vec) tb="$tb mach-o-i386.lo" ;; i386_msdos_vec) tb="$tb i386msdos.lo" ;; i386_nlm32_vec) tb="$tb nlm32-i386.lo nlm32.lo nlm.lo" ;; i386_pe_vec) tb="$tb pe-i386.lo peigen.lo $coff" ;; i386_pei_vec) tb="$tb pei-i386.lo peigen.lo $coff" ;; - iamcu_elf32_vec) tb="$tb elf32-i386.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; + iamcu_elf32_vec) tb="$tb elf32-i386.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf-vxworks.lo elf32.lo $elf" ;; i860_coff_vec) tb="$tb coff-i860.lo $coff" ;; i860_elf32_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; i860_elf32_le_vec) tb="$tb elf32-i860.lo elf32.lo $elf" ;; @@ -500,10 +500,10 @@ do ieee_vec) tb="$tb ieee.lo" ;; ip2k_elf32_vec) tb="$tb elf32-ip2k.lo elf32.lo $elf" ;; iq2000_elf32_vec) tb="$tb elf32-iq2000.lo elf32.lo $elf" ;; - k1om_elf64_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - k1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - l1om_elf64_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - l1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + k1om_elf64_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + k1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + l1om_elf64_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + l1om_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; lm32_elf32_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; lm32_elf32_fdpic_vec) tb="$tb elf32-lm32.lo elf32.lo $elf" ;; m32c_elf32_vec) tb="$tb elf32-m32c.lo elf32.lo $elf" ;; @@ -705,13 +705,13 @@ do wasm32_elf32_vec) tb="$tb elf32-wasm32.lo elf32.lo $elf" ;; we32k_coff_vec) tb="$tb coff-we32k.lo $coffgen" ;; x86_64_coff_vec) tb="$tb coff-x86_64.lo $coff"; target_size=64 ;; - x86_64_elf32_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; - x86_64_elf32_nacl_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; - x86_64_elf64_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_cloudabi_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_nacl_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; - x86_64_elf64_sol2_vec) tb="$tb elf64-x86-64.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf32_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; + x86_64_elf32_nacl_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo elf32.lo $elf"; target_size=64 ;; + x86_64_elf64_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_cloudabi_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_fbsd_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_nacl_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; + x86_64_elf64_sol2_vec) tb="$tb elf64-x86-64.lo elfxx-x86.lo elf-ifunc.lo elf-nacl.lo elf64.lo $elf"; target_size=64 ;; x86_64_mach_o_vec) tb="$tb mach-o-x86-64.lo" ;; x86_64_pe_vec) tb="$tb pe-x86_64.lo pex64igen.lo $coff"; target_size=64 ;; x86_64_pe_be_vec) tb="$tb pe-x86_64.lo pex64igen.lo $coff"; target_size=64 ;; diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 2826272..ebba75c 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -18,16 +18,9 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" +#include "elfxx-x86.h" #include "elf-nacl.h" #include "elf-vxworks.h" -#include "bfd_stdint.h" -#include "objalloc.h" -#include "hashtab.h" #include "dwarf2.h" #include "opcode/i386.h" @@ -535,12 +528,6 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) #define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" -/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid - copying dynamic variables from a shared lib into an app's dynbss - section, and instead use a dynamic relocation to point into the - shared lib. */ -#define ELIMINATE_COPY_RELOCS 1 - /* The size in bytes of an entry in the lazy procedure linkage table. */ #define LAZY_PLT_ENTRY_SIZE 16 @@ -940,46 +927,7 @@ static const struct elf_i386_backend_data elf_i386_arch_bed = #define elf_backend_arch_data &elf_i386_arch_bed -/* Is a undefined weak symbol which is resolved to 0. Reference to an - undefined weak symbol is resolved to 0 when building executable if - it isn't dynamic and - 1. Has non-GOT/non-PLT relocations in text section. Or - 2. Has no GOT/PLT relocation. - Local undefined weak symbol is always resolved to 0. - */ -#define UNDEFINED_WEAK_RESOLVED_TO_ZERO(INFO, GOT_RELOC, EH) \ - ((EH)->elf.root.type == bfd_link_hash_undefweak \ - && ((EH)->elf.forced_local \ - || (bfd_link_executable (INFO) \ - && (elf_i386_hash_table (INFO)->interp == NULL \ - || !(GOT_RELOC) \ - || (EH)->has_non_got_reloc \ - || !(INFO)->dynamic_undefined_weak)))) - -/* Should copy relocation be generated for a symbol. Don't generate - copy relocation against a protected symbol defined in a shared - object with GNU_PROPERTY_NO_COPY_ON_PROTECTED. */ -#define SYMBOL_NO_COPYRELOC(INFO, EH) \ - ((EH)->def_protected \ - && ((EH)->elf.root.type == bfd_link_hash_defined \ - || (EH)->elf.root.type == bfd_link_hash_defweak) \ - && elf_has_no_copy_on_protected ((EH)->elf.root.u.def.section->owner) \ - && ((EH)->elf.root.u.def.section->owner->flags & DYNAMIC) != 0 \ - && ((EH)->elf.root.u.def.section->flags & SEC_CODE) == 0) - - -/* i386 ELF linker hash entry. */ - -struct elf_i386_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 +/* Values in tls_type of x86 ELF linker hash entry. */ #define GOT_TLS_IE 4 #define GOT_TLS_IE_POS 5 #define GOT_TLS_IE_NEG 6 @@ -993,63 +941,6 @@ struct elf_i386_link_hash_entry ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type)) #define GOT_TLS_GD_ANY_P(type) \ (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) - unsigned char tls_type; - - /* Symbol is referenced by R_386_GOTOFF relocation. */ - unsigned int gotoff_ref : 1; - - /* Symbol has GOT or PLT relocations. */ - unsigned int has_got_reloc : 1; - - /* Symbol has non-GOT/non-PLT relocations in text sections. */ - unsigned int has_non_got_reloc : 1; - - /* Don't call finish_dynamic_symbol on this symbol. */ - unsigned int no_finish_dynamic_symbol : 1; - - /* TRUE if symbol is __tls_get_addr. */ - unsigned int tls_get_addr : 1; - - /* TRUE if symbol is defined as a protected symbol. */ - unsigned int def_protected : 1; - - /* Reference count of C/C++ function pointer relocations in read-write - section which can be resolved at run-time. */ - bfd_signed_vma func_pointer_refcount; - - /* Information about the GOT PLT entry. Filled when there are both - GOT and PLT relocations against the same function. */ - union gotplt_union plt_got; - - /* Information about the second PLT entry. */ - union gotplt_union plt_second; - - /* Offset of the GOTPLT entry reserved for the TLS descriptor, - starting at the end of the jump table. */ - bfd_vma tlsdesc_got; -}; - -#define elf_i386_hash_entry(ent) ((struct elf_i386_link_hash_entry *)(ent)) - -struct elf_i386_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - char *local_got_tls_type; - - /* GOTPLT entries for TLS descriptors. */ - bfd_vma *local_tlsdesc_gotent; -}; - -#define elf_i386_tdata(abfd) \ - ((struct elf_i386_obj_tdata *) (abfd)->tdata.any) - -#define elf_i386_local_got_tls_type(abfd) \ - (elf_i386_tdata (abfd)->local_got_tls_type) - -#define elf_i386_local_tlsdesc_gotent(abfd) \ - (elf_i386_tdata (abfd)->local_tlsdesc_gotent) #define is_i386_elf(bfd) \ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ @@ -1059,7 +950,8 @@ struct elf_i386_obj_tdata static bfd_boolean elf_i386_mkobject (bfd *abfd) { - return bfd_elf_allocate_object (abfd, sizeof (struct elf_i386_obj_tdata), + return bfd_elf_allocate_object (abfd, + sizeof (struct elf_x86_obj_tdata), I386_ELF_DATA); } @@ -1067,17 +959,9 @@ elf_i386_mkobject (bfd *abfd) struct elf_i386_link_hash_table { - struct elf_link_hash_table elf; - - /* Short-cuts to get to dynamic linker sections. */ - asection *interp; - asection *plt_eh_frame; - asection *plt_second; - asection *plt_second_eh_frame; - asection *plt_got; - asection *plt_got_eh_frame; + struct elf_x86_link_hash_table x86; - /* Parameters describing PLT generation. */ + /* Parameters describing PLT generation, lazy or non-lazy. */ struct elf_i386_plt_layout plt; /* Parameters describing lazy PLT generation. */ @@ -1086,295 +970,73 @@ struct elf_i386_link_hash_table /* Parameters describing non-lazy PLT generation. */ const struct elf_i386_non_lazy_plt_layout *non_lazy_plt; - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ldm_got; - - /* The amount of space used by the reserved portion of the sgotplt - section, plus whatever space is used by the jump slots. */ - bfd_vma sgotplt_jump_table_size; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - /* _TLS_MODULE_BASE_ symbol. */ - struct bfd_link_hash_entry *tls_module_base; - - /* Used by local STT_GNU_IFUNC symbols. */ - htab_t loc_hash_table; - void * loc_hash_memory; - /* The (unloaded but important) .rel.plt.unloaded section on VxWorks. */ asection *srelplt2; /* The index of the next unused R_386_TLS_DESC slot in .rel.plt. */ bfd_vma next_tls_desc_index; +}; - /* The index of the next unused R_386_JUMP_SLOT slot in .rel.plt. */ - bfd_vma next_jump_slot_index; +#define elf_i386_next_tls_desc_index(htab) \ + ((struct elf_i386_link_hash_table *) (htab))->next_tls_desc_index - /* The index of the next unused R_386_IRELATIVE slot in .rel.plt. */ - bfd_vma next_irelative_index; +#define elf_i386_srelplt2(htab) \ + ((struct elf_i386_link_hash_table *) (htab))->srelplt2 - /* TRUE if there are dynamic relocs against IFUNC symbols that apply - to read-only sections. */ - bfd_boolean readonly_dynrelocs_against_ifunc; -}; +#define elf_i386_plt(htab) \ + ((struct elf_i386_link_hash_table *) (htab))->plt -/* Get the i386 ELF linker hash table from a link_info structure. */ +#define elf_i386_lazy_plt(htab) \ + ((struct elf_i386_link_hash_table *) (htab))->lazy_plt -#define elf_i386_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == I386_ELF_DATA ? ((struct elf_i386_link_hash_table *) ((p)->hash)) : NULL) +#define elf_i386_non_lazy_plt(htab) \ + ((struct elf_i386_link_hash_table *) (htab))->non_lazy_plt #define elf_i386_compute_jump_table_size(htab) \ ((htab)->elf.srelplt->reloc_count * 4) -/* Create an entry in an i386 ELF linker hash table. */ - -static struct bfd_hash_entry * -elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (entry == NULL) - { - entry = (struct bfd_hash_entry *) - bfd_hash_allocate (table, sizeof (struct elf_i386_link_hash_entry)); - if (entry == NULL) - return entry; - } - - /* Call the allocation method of the superclass. */ - entry = _bfd_elf_link_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf_i386_link_hash_entry *eh; - - eh = (struct elf_i386_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - eh->tls_type = GOT_UNKNOWN; - eh->gotoff_ref = 0; - eh->has_got_reloc = 0; - eh->has_non_got_reloc = 0; - eh->no_finish_dynamic_symbol = 0; - eh->tls_get_addr = 0; - eh->def_protected = 0; - eh->func_pointer_refcount = 0; - eh->plt_got.offset = (bfd_vma) -1; - eh->tlsdesc_got = (bfd_vma) -1; - } - - return entry; -} - -/* Compute a hash of a local hash entry. We use elf_link_hash_entry - for local symbol so that we can handle local STT_GNU_IFUNC symbols - as global symbol. We reuse indx and dynstr_index for local symbol - hash since they aren't used by global symbols in this backend. */ - -static hashval_t -elf_i386_local_htab_hash (const void *ptr) -{ - struct elf_link_hash_entry *h - = (struct elf_link_hash_entry *) ptr; - return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index); -} - -/* Compare local hash entries. */ - -static int -elf_i386_local_htab_eq (const void *ptr1, const void *ptr2) -{ - struct elf_link_hash_entry *h1 - = (struct elf_link_hash_entry *) ptr1; - struct elf_link_hash_entry *h2 - = (struct elf_link_hash_entry *) ptr2; - - return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index; -} - -/* Find and/or create a hash entry for local symbol. */ - -static struct elf_link_hash_entry * -elf_i386_get_local_sym_hash (struct elf_i386_link_hash_table *htab, - bfd *abfd, const Elf_Internal_Rela *rel, - bfd_boolean create) -{ - struct elf_i386_link_hash_entry e, *ret; - asection *sec = abfd->sections; - hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id, - ELF32_R_SYM (rel->r_info)); - void **slot; - - e.elf.indx = sec->id; - e.elf.dynstr_index = ELF32_R_SYM (rel->r_info); - slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h, - create ? INSERT : NO_INSERT); - - if (!slot) - return NULL; - - if (*slot) - { - ret = (struct elf_i386_link_hash_entry *) *slot; - return &ret->elf; - } - - ret = (struct elf_i386_link_hash_entry *) - objalloc_alloc ((struct objalloc *) htab->loc_hash_memory, - sizeof (struct elf_i386_link_hash_entry)); - if (ret) - { - memset (ret, 0, sizeof (*ret)); - ret->elf.indx = sec->id; - ret->elf.dynstr_index = ELF32_R_SYM (rel->r_info); - ret->elf.dynindx = -1; - ret->func_pointer_refcount = 0; - ret->plt_got.offset = (bfd_vma) -1; - *slot = ret; - } - return &ret->elf; -} - -/* Destroy an i386 ELF linker hash table. */ - -static void -elf_i386_link_hash_table_free (bfd *obfd) -{ - struct elf_i386_link_hash_table *htab - = (struct elf_i386_link_hash_table *) obfd->link.hash; - - if (htab->loc_hash_table) - htab_delete (htab->loc_hash_table); - if (htab->loc_hash_memory) - objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_elf_link_hash_table_free (obfd); -} - /* Create an i386 ELF linker hash table. */ static struct bfd_link_hash_table * elf_i386_link_hash_table_create (bfd *abfd) { - struct elf_i386_link_hash_table *ret; + struct elf_x86_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf_i386_link_hash_table); - ret = (struct elf_i386_link_hash_table *) bfd_zmalloc (amt); + ret = (struct elf_x86_link_hash_table *) bfd_zmalloc (amt); if (ret == NULL) return NULL; if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - elf_i386_link_hash_newfunc, - sizeof (struct elf_i386_link_hash_entry), + _bfd_x86_elf_link_hash_newfunc, + sizeof (struct elf_x86_link_hash_entry), I386_ELF_DATA)) { free (ret); return NULL; } + ret->r_info = elf32_r_info; + ret->r_sym = elf32_r_sym; + ret->pointer_r_type = R_386_32; + ret->dynamic_interpreter_size = sizeof ELF_DYNAMIC_INTERPRETER; + ret->dynamic_interpreter = ELF_DYNAMIC_INTERPRETER; + ret->tls_get_addr = "___tls_get_addr"; ret->loc_hash_table = htab_try_create (1024, - elf_i386_local_htab_hash, - elf_i386_local_htab_eq, + _bfd_x86_elf_local_htab_hash, + _bfd_x86_elf_local_htab_eq, NULL); ret->loc_hash_memory = objalloc_create (); if (!ret->loc_hash_table || !ret->loc_hash_memory) { - elf_i386_link_hash_table_free (abfd); + _bfd_x86_elf_link_hash_table_free (abfd); return NULL; } - ret->elf.root.hash_table_free = elf_i386_link_hash_table_free; + ret->elf.root.hash_table_free = _bfd_x86_elf_link_hash_table_free; return &ret->elf.root; } -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf_i386_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_i386_link_hash_entry *edir, *eind; - - edir = (struct elf_i386_link_hash_entry *) dir; - eind = (struct elf_i386_link_hash_entry *) ind; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_dyn_relocs *p; - - /* Add reloc counts against the indirect sym to the direct sym - list. Merge any entries against the same section. */ - for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) - { - struct elf_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - - if (ind->root.type == bfd_link_hash_indirect - && dir->got.refcount <= 0) - { - edir->tls_type = eind->tls_type; - eind->tls_type = GOT_UNKNOWN; - } - - /* Copy gotoff_ref so that elf_i386_adjust_dynamic_symbol will - generate a R_386_COPY reloc. */ - edir->gotoff_ref |= eind->gotoff_ref; - - edir->has_got_reloc |= eind->has_got_reloc; - edir->has_non_got_reloc |= eind->has_non_got_reloc; - - if (ELIMINATE_COPY_RELOCS - && ind->root.type != bfd_link_hash_indirect - && dir->dynamic_adjusted) - { - /* If called to transfer flags for a weakdef during processing - of elf_adjust_dynamic_symbol, don't copy non_got_ref. - We clear it ourselves for ELIMINATE_COPY_RELOCS. */ - if (dir->versioned != versioned_hidden) - dir->ref_dynamic |= ind->ref_dynamic; - dir->ref_regular |= ind->ref_regular; - dir->ref_regular_nonweak |= ind->ref_regular_nonweak; - dir->needs_plt |= ind->needs_plt; - dir->pointer_equality_needed |= ind->pointer_equality_needed; - } - else - { - if (eind->func_pointer_refcount > 0) - { - edir->func_pointer_refcount += eind->func_pointer_refcount; - eind->func_pointer_refcount = 0; - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); - } -} - /* Return TRUE if the TLS access code sequence support transition from R_TYPE. */ @@ -1499,7 +1161,7 @@ elf_i386_check_tls_transition (asection *sec, h = sym_hashes[r_symndx - symtab_hdr->sh_info]; if (h == NULL - || !((struct elf_i386_link_hash_entry *) h)->tls_get_addr) + || !((struct elf_x86_link_hash_entry *) h)->tls_get_addr) return FALSE; else if (indirect_call) return (ELF32_R_TYPE (rel[1].r_info) == R_386_GOT32X); @@ -1685,9 +1347,9 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, name = h->root.root.string; else { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) name = "*unknown*"; else @@ -1742,7 +1404,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, bfd_boolean *converted, struct bfd_link_info *link_info) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; unsigned int opcode; unsigned int modrm; bfd_boolean baseless; @@ -1764,7 +1426,7 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, if (addend != 0) return TRUE; - htab = elf_i386_hash_table (link_info); + htab = elf_x86_hash_table (link_info, I386_ELF_DATA); is_pic = bfd_link_pic (link_info); r_type = ELF32_R_TYPE (irel->r_info); @@ -1818,8 +1480,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, /* Undefined weak symbol is only bound locally in executable and its reference is resolved as 0. */ - if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info, TRUE, - elf_i386_hash_entry (h))) + if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info, I386_ELF_DATA, TRUE, + elf_x86_hash_entry (h))) { if (opcode == 0xff) { @@ -1849,8 +1511,8 @@ convert_branch: /* Convert R_386_GOT32X to R_386_PC32. */ if (modrm == 0x15 || (modrm & 0xf8) == 0x90) { - struct elf_i386_link_hash_entry *eh - = (struct elf_i386_link_hash_entry *) h; + struct elf_x86_link_hash_entry *eh + = (struct elf_x86_link_hash_entry *) h; /* Convert to "nop call foo". ADDR_PREFIX_OPCODE is a nop prefix. */ @@ -1984,7 +1646,7 @@ elf_i386_check_relocs (bfd *abfd, asection *sec, const Elf_Internal_Rela *relocs) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; const Elf_Internal_Rela *rel; @@ -2006,7 +1668,7 @@ elf_i386_check_relocs (bfd *abfd, BFD_ASSERT (is_i386_elf (abfd)); - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) { sec->check_relocs_failed = 1; @@ -2033,7 +1695,7 @@ elf_i386_check_relocs (bfd *abfd, unsigned int r_type; unsigned int r_symndx; struct elf_link_hash_entry *h; - struct elf_i386_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; Elf_Internal_Sym *isym; const char *name; bfd_boolean size_reloc; @@ -2060,7 +1722,7 @@ elf_i386_check_relocs (bfd *abfd, /* Check relocation against local STT_GNU_IFUNC symbol. */ if (ELF32_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { - h = elf_i386_get_local_sym_hash (htab, abfd, rel, TRUE); + h = _bfd_elf_x86_get_local_sym_hash (htab, abfd, rel, TRUE); if (h == NULL) goto error_return; @@ -2085,7 +1747,7 @@ elf_i386_check_relocs (bfd *abfd, h = (struct elf_link_hash_entry *) h->root.u.i.link; } - eh = (struct elf_i386_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; if (h != NULL) { if (r_type == R_386_GOTOFF) @@ -2109,7 +1771,7 @@ elf_i386_check_relocs (bfd *abfd, switch (r_type) { case R_386_TLS_LDM: - htab->tls_ldm_got.refcount += 1; + htab->tls_ld_or_ldm_got.refcount += 1; goto create_got; case R_386_PLT32: @@ -2177,7 +1839,7 @@ elf_i386_check_relocs (bfd *abfd, if (h != NULL) { h->got.refcount += 1; - old_tls_type = elf_i386_hash_entry(h)->tls_type; + old_tls_type = elf_x86_hash_entry (h)->tls_type; } else { @@ -2197,13 +1859,13 @@ elf_i386_check_relocs (bfd *abfd, if (local_got_refcounts == NULL) goto error_return; elf_local_got_refcounts (abfd) = local_got_refcounts; - elf_i386_local_tlsdesc_gotent (abfd) + elf_x86_local_tlsdesc_gotent (abfd) = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); - elf_i386_local_got_tls_type (abfd) + elf_x86_local_got_tls_type (abfd) = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); } local_got_refcounts[r_symndx] += 1; - old_tls_type = elf_i386_local_got_tls_type (abfd) [r_symndx]; + old_tls_type = elf_x86_local_got_tls_type (abfd) [r_symndx]; } if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_IE)) @@ -2239,9 +1901,9 @@ elf_i386_check_relocs (bfd *abfd, if (old_tls_type != tls_type) { if (h != NULL) - elf_i386_hash_entry (h)->tls_type = tls_type; + elf_x86_hash_entry (h)->tls_type = tls_type; else - elf_i386_local_got_tls_type (abfd) [r_symndx] = tls_type; + elf_x86_local_got_tls_type (abfd) [r_symndx] = tls_type; } } /* Fall through */ @@ -2494,25 +2156,6 @@ elf_i386_gc_mark_hook (asection *sec, return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } -/* Remove undefined weak symbol from the dynamic symbol table if it - is resolved to 0. */ - -static bfd_boolean -elf_i386_fixup_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - if (h->dynindx != -1 - && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, - elf_i386_hash_entry (h)->has_got_reloc, - elf_i386_hash_entry (h))) - { - h->dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - h->dynstr_index); - } - return TRUE; -} - /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -2523,9 +2166,9 @@ static bfd_boolean elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; asection *s, *srel; - struct elf_i386_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; struct elf_dyn_relocs *p; /* STT_GNU_IFUNC symbol must go through PLT. */ @@ -2539,7 +2182,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, bfd_size_type pc_count = 0, count = 0; struct elf_dyn_relocs **pp; - eh = (struct elf_i386_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { pc_count += p->pc_count; @@ -2606,7 +2249,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, the link may change h->type. So fix it now. */ h->plt.offset = (bfd_vma) -1; - eh = (struct elf_i386_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the @@ -2647,7 +2290,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, return TRUE; } - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return FALSE; @@ -2713,28 +2356,33 @@ static bfd_boolean elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info; - struct elf_i386_link_hash_table *htab; - struct elf_i386_link_hash_entry *eh; + struct elf_x86_link_hash_table *htab; + struct elf_x86_link_hash_entry *eh; struct elf_dyn_relocs *p; unsigned plt_entry_size; bfd_boolean resolved_to_zero; const struct elf_i386_backend_data *bed; + const struct elf_i386_plt_layout *plt_layout; + const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout; if (h->root.type == bfd_link_hash_indirect) return TRUE; - eh = (struct elf_i386_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; info = (struct bfd_link_info *) inf; - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return FALSE; bed = get_elf_i386_backend_data (info->output_bfd); - plt_entry_size = htab->plt.plt_entry_size; + plt_layout = &elf_i386_plt (htab); + non_lazy_plt_layout = elf_i386_non_lazy_plt (htab); + plt_entry_size = plt_layout->plt_entry_size; resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + I386_ELF_DATA, eh->has_got_reloc, eh); @@ -2769,8 +2417,8 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (_bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, &htab->readonly_dynrelocs_against_ifunc, plt_entry_size, - (htab->plt.has_plt0 * - plt_entry_size), + (plt_layout->has_plt0 + * plt_entry_size), 4, TRUE)) { asection *s = htab->plt_second; @@ -2780,7 +2428,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) eh->plt_second.offset = s->size; /* Make room for this entry in the second PLT section. */ - s->size += htab->non_lazy_plt->plt_entry_size; + s->size += non_lazy_plt_layout->plt_entry_size; } return TRUE; @@ -2822,7 +2470,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) first entry. The .plt section is used by prelink to undo prelinking for dynamic relocations. */ if (s->size == 0) - s->size = htab->plt.has_plt0 * plt_entry_size; + s->size = plt_layout->has_plt0 * plt_entry_size; if (use_plt_got) eh->plt_got.offset = got_s->size; @@ -2867,12 +2515,12 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* Make room for this entry. */ if (use_plt_got) - got_s->size += htab->non_lazy_plt->plt_entry_size; + got_s->size += non_lazy_plt_layout->plt_entry_size; else { s->size += plt_entry_size; if (second_s) - second_s->size += htab->non_lazy_plt->plt_entry_size; + second_s->size += non_lazy_plt_layout->plt_entry_size; /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker @@ -2900,14 +2548,15 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 4 and an R_386_32 relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ + asection *srelplt2 = elf_i386_srelplt2 (htab); if (h->plt.offset == plt_entry_size) - htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); + srelplt2->size += (sizeof (Elf32_External_Rel) * 2); /* There are two extra relocations for each subsequent PLT entry: an R_386_32 relocation for the GOT entry, and an R_386_32 relocation for the PLT entry. */ - htab->srelplt2->size += (sizeof (Elf32_External_Rel) * 2); + srelplt2->size += (sizeof (Elf32_External_Rel) * 2); } } else @@ -2931,13 +2580,13 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (h->got.refcount > 0 && bfd_link_executable (info) && h->dynindx == -1 - && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE)) + && (elf_x86_hash_entry (h)->tls_type & GOT_TLS_IE)) h->got.offset = (bfd_vma) -1; else if (h->got.refcount > 0) { asection *s; bfd_boolean dyn; - int tls_type = elf_i386_hash_entry(h)->tls_type; + int tls_type = elf_x86_hash_entry (h)->tls_type; /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -3157,50 +2806,13 @@ elf_i386_allocate_local_dynrelocs (void **slot, void *inf) return elf_i386_allocate_dynrelocs (h, inf); } -/* Find any dynamic relocs that apply to read-only sections. */ - -static bfd_boolean -elf_i386_readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) -{ - struct elf_i386_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - /* Skip local IFUNC symbols. */ - if (h->forced_local && h->type == STT_GNU_IFUNC) - return TRUE; - - eh = (struct elf_i386_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - { - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - info->flags |= DF_TEXTREL; - - if ((info->warn_shared_textrel && bfd_link_pic (info)) - || info->error_textrel) - /* xgettext:c-format */ - info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"), - p->sec->owner, h->root.root.string, - p->sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - } - return TRUE; -} - /* Convert load via the GOT slot to load immediate. */ static bfd_boolean elf_i386_convert_load (bfd *abfd, asection *sec, struct bfd_link_info *link_info) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *irel, *irelend; @@ -3228,7 +2840,7 @@ elf_i386_convert_load (bfd *abfd, asection *sec, return FALSE; changed = FALSE; - htab = elf_i386_hash_table (link_info); + htab = elf_x86_hash_table (link_info, I386_ELF_DATA); local_got_refcounts = elf_local_got_refcounts (abfd); /* Get the section contents. */ @@ -3255,9 +2867,9 @@ elf_i386_convert_load (bfd *abfd, asection *sec, r_symndx = ELF32_R_SYM (irel->r_info); if (r_symndx < symtab_hdr->sh_info) - h = elf_i386_get_local_sym_hash (htab, sec->owner, - (const Elf_Internal_Rela *) irel, - FALSE); + h = _bfd_elf_x86_get_local_sym_hash (htab, sec->owner, + (const Elf_Internal_Rela *) irel, + FALSE); else { h = elf_sym_hashes (abfd)[r_symndx - symtab_hdr->sh_info]; @@ -3329,13 +2941,13 @@ elf_i386_convert_load (bfd *abfd, asection *sec, static bfd_boolean elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd *dynobj; asection *s; bfd_boolean relocs; bfd *ibfd; - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return FALSE; dynobj = htab->elf.dynobj; @@ -3410,8 +3022,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) symtab_hdr = &elf_symtab_hdr (ibfd); locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; - local_tls_type = elf_i386_local_got_tls_type (ibfd); - local_tlsdesc_gotent = elf_i386_local_tlsdesc_gotent (ibfd); + local_tls_type = elf_x86_local_got_tls_type (ibfd); + local_tlsdesc_gotent = elf_x86_local_tlsdesc_gotent (ibfd); s = htab->elf.sgot; srel = htab->elf.srelgot; for (; local_got < end_local_got; @@ -3454,16 +3066,16 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) } } - if (htab->tls_ldm_got.refcount > 0) + if (htab->tls_ld_or_ldm_got.refcount > 0) { /* Allocate 2 got entries and 1 dynamic reloc for R_386_TLS_LDM relocs. */ - htab->tls_ldm_got.offset = htab->elf.sgot->size; + htab->tls_ld_or_ldm_got.offset = htab->elf.sgot->size; htab->elf.sgot->size += 8; htab->elf.srelgot->size += sizeof (Elf32_External_Rel); } else - htab->tls_ldm_got.offset = -1; + htab->tls_ld_or_ldm_got.offset = -1; /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ @@ -3484,8 +3096,10 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) so that R_386_IRELATIVE entries come last. */ if (htab->elf.srelplt) { - htab->next_tls_desc_index = htab->elf.srelplt->reloc_count; - htab->sgotplt_jump_table_size = htab->next_tls_desc_index * 4; + elf_i386_next_tls_desc_index(htab) + = htab->elf.srelplt->reloc_count; + htab->sgotplt_jump_table_size + = elf_i386_next_tls_desc_index(htab) * 4; htab->next_irelative_index = htab->elf.srelplt->reloc_count - 1; } else if (htab->elf.irelplt) @@ -3517,14 +3131,14 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) && htab->elf.splt != NULL && htab->elf.splt->size != 0 && !bfd_is_abs_section (htab->elf.splt->output_section)) - htab->plt_eh_frame->size = htab->plt.eh_frame_plt_size; + htab->plt_eh_frame->size = elf_i386_plt (htab).eh_frame_plt_size; if (htab->plt_got_eh_frame != NULL && htab->plt_got != NULL && htab->plt_got->size != 0 && !bfd_is_abs_section (htab->plt_got->output_section)) htab->plt_got_eh_frame->size - = htab->non_lazy_plt->eh_frame_plt_size; + = elf_i386_non_lazy_plt (htab)->eh_frame_plt_size; /* Unwind info for the second PLT and .plt.got sections are identical. */ @@ -3533,7 +3147,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) && htab->plt_second->size != 0 && !bfd_is_abs_section (htab->plt_second->output_section)) htab->plt_second_eh_frame->size - = htab->non_lazy_plt->eh_frame_plt_size; + = elf_i386_non_lazy_plt (htab)->eh_frame_plt_size; } /* We now have determined the sizes of the various dynamic sections. @@ -3575,7 +3189,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { if (s->size != 0 && s != htab->elf.srelplt - && s != htab->srelplt2) + && s != elf_i386_srelplt2 (htab)) relocs = TRUE; /* We use the reloc_count field as a counter if we need @@ -3621,7 +3235,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) && htab->plt_eh_frame->contents != NULL) { memcpy (htab->plt_eh_frame->contents, - htab->plt.eh_frame_plt, + elf_i386_plt (htab).eh_frame_plt, htab->plt_eh_frame->size); bfd_put_32 (dynobj, htab->elf.splt->size, htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); @@ -3631,7 +3245,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) && htab->plt_got_eh_frame->contents != NULL) { memcpy (htab->plt_got_eh_frame->contents, - htab->non_lazy_plt->eh_frame_plt, + elf_i386_non_lazy_plt (htab)->eh_frame_plt, htab->plt_got_eh_frame->size); bfd_put_32 (dynobj, htab->plt_got->size, (htab->plt_got_eh_frame->contents @@ -3642,7 +3256,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) && htab->plt_second_eh_frame->contents != NULL) { memcpy (htab->plt_second_eh_frame->contents, - htab->non_lazy_plt->eh_frame_plt, + elf_i386_non_lazy_plt (htab)->eh_frame_plt, htab->plt_second_eh_frame->size); bfd_put_32 (dynobj, htab->plt_second->size, (htab->plt_second_eh_frame->contents @@ -3692,7 +3306,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) elf_link_hash_traverse (&htab->elf, - elf_i386_readonly_dynrelocs, info); + _bfd_x86_elf_readonly_dynrelocs, + info); if ((info->flags & DF_TEXTREL) != 0) { @@ -3717,50 +3332,6 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) return TRUE; } -static bfd_boolean -elf_i386_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - asection *tls_sec = elf_hash_table (info)->tls_sec; - - if (tls_sec) - { - struct elf_link_hash_entry *tlsbase; - - tlsbase = elf_link_hash_lookup (elf_hash_table (info), - "_TLS_MODULE_BASE_", - FALSE, FALSE, FALSE); - - if (tlsbase && tlsbase->type == STT_TLS) - { - struct elf_i386_link_hash_table *htab; - struct bfd_link_hash_entry *bh = NULL; - const struct elf_backend_data *bed - = get_elf_backend_data (output_bfd); - - htab = elf_i386_hash_table (info); - if (htab == NULL) - return FALSE; - - if (!(_bfd_generic_link_add_one_symbol - (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, - tls_sec, 0, NULL, FALSE, - bed->collect, &bh))) - return FALSE; - - htab->tls_module_base = bh; - - tlsbase = (struct elf_link_hash_entry *)bh; - tlsbase->def_regular = 1; - tlsbase->other = STV_HIDDEN; - tlsbase->root.linker_def = 1; - (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); - } - } - - return TRUE; -} - /* Set the correct type for an x86 ELF section. We do this by the section name, which is a hack, but ought to work. */ @@ -3795,44 +3366,6 @@ elf_i386_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, return TRUE; } -/* _TLS_MODULE_BASE_ needs to be treated especially when linking - executables. Rather than setting it to the beginning of the TLS - section, we have to set it to the end. This function may be called - multiple times, it is idempotent. */ - -static void -elf_i386_set_tls_module_base (struct bfd_link_info *info) -{ - struct elf_i386_link_hash_table *htab; - struct bfd_link_hash_entry *base; - - if (!bfd_link_executable (info)) - return; - - htab = elf_i386_hash_table (info); - if (htab == NULL) - return; - - base = htab->tls_module_base; - if (base == NULL) - return; - - base->u.def.value = htab->elf.tls_size; -} - -/* Return the base VMA address which should be subtracted from real addresses - when resolving @dtpoff relocation. - This is PT_TLS segment p_vaddr. */ - -static bfd_vma -elf_i386_dtpoff_base (struct bfd_link_info *info) -{ - /* If tls_sec is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_sec == NULL) - return 0; - return elf_hash_table (info)->tls_sec->vma; -} - /* Return the relocation value for @tpoff relocation if STT_TLS virtual address is ADDRESS. */ @@ -3864,7 +3397,7 @@ elf_i386_relocate_section (bfd *output_bfd, Elf_Internal_Sym *local_syms, asection **local_sections) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_vma *local_got_offsets; @@ -3881,13 +3414,13 @@ elf_i386_relocate_section (bfd *output_bfd, if (input_section->check_relocs_failed) return FALSE; - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return FALSE; symtab_hdr = &elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); - local_tlsdesc_gotents = elf_i386_local_tlsdesc_gotent (input_bfd); + local_tlsdesc_gotents = elf_x86_local_tlsdesc_gotent (input_bfd); /* We have to handle relocations in vxworks .tls_vars sections specially, because the dynamic loader is 'weird'. */ is_vxworks_tls = ((get_elf_i386_backend_data (output_bfd)->os @@ -3896,9 +3429,9 @@ elf_i386_relocate_section (bfd *output_bfd, && !strcmp (input_section->output_section->name, ".tls_vars")); - elf_i386_set_tls_module_base (info); + _bfd_x86_elf_set_tls_module_base (info); - plt_entry_size = htab->plt.plt_entry_size; + plt_entry_size = elf_i386_plt (htab).plt_entry_size; rel = wrel = relocs; relend = relocs + input_section->reloc_count; @@ -3908,7 +3441,7 @@ elf_i386_relocate_section (bfd *output_bfd, reloc_howto_type *howto; unsigned long r_symndx; struct elf_link_hash_entry *h; - struct elf_i386_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; Elf_Internal_Sym *sym; asection *sec; bfd_vma off, offplt, plt_offset; @@ -4027,8 +3560,8 @@ elf_i386_relocate_section (bfd *output_bfd, && ELF32_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) { /* Relocate against local STT_GNU_IFUNC symbol. */ - h = elf_i386_get_local_sym_hash (htab, input_bfd, rel, - FALSE); + h = _bfd_elf_x86_get_local_sym_hash (htab, input_bfd, rel, + FALSE); if (h == NULL) abort (); @@ -4074,7 +3607,7 @@ elf_i386_relocate_section (bfd *output_bfd, continue; } - eh = (struct elf_i386_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined in a non-shared object. */ @@ -4143,7 +3676,7 @@ elf_i386_relocate_section (bfd *output_bfd, if (htab->elf.splt != NULL) { plt_index = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0); + - elf_i386_plt (htab).has_plt0); off = (plt_index + 3) * 4; base_got = htab->elf.sgotplt; } @@ -4311,6 +3844,7 @@ do_ifunc_pointer: resolved_to_zero = (eh != NULL && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + I386_ELF_DATA, eh->has_got_reloc, eh)); @@ -4360,7 +3894,7 @@ do_ifunc_pointer: else /* Use GOTPLT entry. */ relocation = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0 + 3) * 4; + - elf_i386_plt (htab).has_plt0 + 3) * 4; if (!bfd_link_pic (info)) { @@ -4744,9 +4278,9 @@ disallow_got32: case R_386_TLS_GOTIE: tls_type = GOT_UNKNOWN; if (h == NULL && local_got_offsets) - tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx]; + tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx]; else if (h != NULL) - tls_type = elf_i386_hash_entry(h)->tls_type; + tls_type = elf_x86_hash_entry(h)->tls_type; if (tls_type == GOT_TLS_IE) tls_type = GOT_TLS_IE_NEG; @@ -4953,7 +4487,7 @@ disallow_got32: if (h != NULL) { off = h->got.offset; - offplt = elf_i386_hash_entry (h)->tlsdesc_got; + offplt = elf_x86_hash_entry (h)->tlsdesc_got; } else { @@ -4989,7 +4523,7 @@ disallow_got32: + htab->sgotplt_jump_table_size); sreloc = htab->elf.srelplt; loc = sreloc->contents; - loc += (htab->next_tls_desc_index++ + loc += (elf_i386_next_tls_desc_index (htab)++ * sizeof (Elf32_External_Rel)); BFD_ASSERT (loc + sizeof (Elf32_External_Rel) <= sreloc->contents + sreloc->size); @@ -4998,7 +4532,7 @@ disallow_got32: { BFD_ASSERT (! unresolved_reloc); bfd_put_32 (output_bfd, - relocation - elf_i386_dtpoff_base (info), + relocation - _bfd_x86_elf_dtpoff_base (info), htab->elf.sgotplt->contents + offplt + htab->sgotplt_jump_table_size + 4); } @@ -5026,11 +4560,11 @@ disallow_got32: if (dr_type == R_386_TLS_TPOFF && indx == 0) bfd_put_32 (output_bfd, - relocation - elf_i386_dtpoff_base (info), + relocation - _bfd_x86_elf_dtpoff_base (info), htab->elf.sgot->contents + off); else if (dr_type == R_386_TLS_TPOFF32 && indx == 0) bfd_put_32 (output_bfd, - elf_i386_dtpoff_base (info) - relocation, + _bfd_x86_elf_dtpoff_base (info) - relocation, htab->elf.sgot->contents + off); else if (dr_type != R_386_TLS_DESC) bfd_put_32 (output_bfd, 0, @@ -5045,7 +4579,7 @@ disallow_got32: { BFD_ASSERT (! unresolved_reloc); bfd_put_32 (output_bfd, - relocation - elf_i386_dtpoff_base (info), + relocation - _bfd_x86_elf_dtpoff_base (info), htab->elf.sgot->contents + off + 4); } else @@ -5062,7 +4596,7 @@ disallow_got32: { bfd_put_32 (output_bfd, (indx == 0 - ? relocation - elf_i386_dtpoff_base (info) + ? relocation - _bfd_x86_elf_dtpoff_base (info) : 0), htab->elf.sgot->contents + off + 4); outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); @@ -5273,7 +4807,7 @@ disallow_got32: if (htab->elf.sgot == NULL) abort (); - off = htab->tls_ldm_got.offset; + off = htab->tls_ld_or_ldm_got.offset; if (off & 1) off &= ~1; else @@ -5292,7 +4826,7 @@ disallow_got32: htab->elf.sgot->contents + off + 4); outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32); elf_append_rel (output_bfd, htab->elf.srelgot, &outrel); - htab->tls_ldm_got.offset |= 1; + htab->tls_ld_or_ldm_got.offset |= 1; } relocation = htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset + off @@ -5304,7 +4838,7 @@ disallow_got32: case R_386_TLS_LDO_32: if (!bfd_link_executable (info) || (input_section->flags & SEC_CODE) == 0) - relocation -= elf_i386_dtpoff_base (info); + relocation -= _bfd_x86_elf_dtpoff_base (info); else /* When converting LDO to LE, we must negate. */ relocation = -elf_i386_tpoff (info, relocation); @@ -5335,9 +4869,9 @@ disallow_got32: if (indx) continue; else if (r_type == R_386_TLS_LE_32) - relocation = elf_i386_dtpoff_base (info) - relocation; + relocation = _bfd_x86_elf_dtpoff_base (info) - relocation; else - relocation -= elf_i386_dtpoff_base (info); + relocation -= _bfd_x86_elf_dtpoff_base (info); } else if (r_type == R_386_TLS_LE_32) relocation = elf_i386_tpoff (info, relocation); @@ -5443,31 +4977,37 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; unsigned plt_entry_size; const struct elf_i386_backend_data *abed; - struct elf_i386_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; bfd_boolean local_undefweak; bfd_boolean use_plt_second; + const struct elf_i386_plt_layout *plt_layout; + const struct elf_i386_lazy_plt_layout *lazy_plt_layout; + const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout; - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return FALSE; abed = get_elf_i386_backend_data (output_bfd); - plt_entry_size = htab->plt.plt_entry_size; + plt_layout = &elf_i386_plt (htab); + lazy_plt_layout = elf_i386_lazy_plt (htab); + non_lazy_plt_layout = elf_i386_non_lazy_plt (htab); + plt_entry_size = plt_layout->plt_entry_size; /* Use the second PLT section only if there is .plt section. */ use_plt_second = htab->elf.splt != NULL && htab->plt_second != NULL; - eh = (struct elf_i386_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; if (eh->no_finish_dynamic_symbol) abort (); /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for resolved undefined weak symbols in executable so that their references have value 0 at run-time. */ - local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, I386_ELF_DATA, eh->has_got_reloc, eh); @@ -5521,7 +5061,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, if (plt == htab->elf.splt) { got_offset = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0); + - plt_layout->has_plt0); got_offset = (got_offset + 3) * 4; } else @@ -5532,18 +5072,18 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, /* Fill in the entry in the procedure linkage table and update the first slot. */ - memcpy (plt->contents + h->plt.offset, htab->plt.plt_entry, + memcpy (plt->contents + h->plt.offset, plt_layout->plt_entry, plt_entry_size); if (use_plt_second) { const bfd_byte *plt_entry; if (bfd_link_pic (info)) - plt_entry = htab->non_lazy_plt->pic_plt_entry; + plt_entry = non_lazy_plt_layout->pic_plt_entry; else - plt_entry = htab->non_lazy_plt->plt_entry; + plt_entry = non_lazy_plt_layout->plt_entry; memcpy (htab->plt_second->contents + eh->plt_second.offset, - plt_entry, htab->non_lazy_plt->plt_entry_size); + plt_entry, non_lazy_plt_layout->plt_entry_size); resolved_plt = htab->plt_second; plt_offset = eh->plt_second.offset; @@ -5561,7 +5101,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, + gotplt->output_offset + got_offset), resolved_plt->contents + plt_offset - + htab->plt.plt_got_offset); + + plt_layout->plt_got_offset); if (abed->os == is_vxworks) { @@ -5571,8 +5111,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, for this PLT entry. */ /* S: Current slot number (zero-based). */ - s = ((h->plt.offset - htab->plt.plt_entry_size) - / htab->plt.plt_entry_size); + s = ((h->plt.offset - plt_layout->plt_entry_size) + / plt_layout->plt_entry_size); /* K: Number of relocations for PLTResolve. */ if (bfd_link_pic (info)) k = PLTRESOLVE_RELOCS_SHLIB; @@ -5581,7 +5121,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, /* Skip the PLTresolve relocations, and the relocations for the other PLT slots. */ reloc_index = k + s * PLT_NON_JUMP_SLOT_RELOCS; - loc = (htab->srelplt2->contents + reloc_index + loc = (elf_i386_srelplt2 (htab)->contents + reloc_index * sizeof (Elf32_External_Rel)); rel.r_offset = (plt->output_section->vma @@ -5604,7 +5144,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, { bfd_put_32 (output_bfd, got_offset, resolved_plt->contents + plt_offset - + htab->plt.plt_got_offset); + + plt_layout->plt_got_offset); } /* Fill in the entry in the global offset table. Leave the entry @@ -5612,12 +5152,12 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, against undefined weak symbol in PIE. */ if (!local_undefweak) { - if (htab->plt.has_plt0) + if (plt_layout->has_plt0) bfd_put_32 (output_bfd, (plt->output_section->vma + plt->output_offset + h->plt.offset - + htab->lazy_plt->plt_lazy_offset), + + lazy_plt_layout->plt_lazy_offset), gotplt->contents + got_offset); /* Fill in the entry in the .rel.plt section. */ @@ -5657,17 +5197,17 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, /* Don't fill the second and third slots in PLT entry for static executables nor without PLT0. */ - if (plt == htab->elf.splt && htab->plt.has_plt0) + if (plt == htab->elf.splt && plt_layout->has_plt0) { bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), plt->contents + h->plt.offset - + htab->lazy_plt->plt_reloc_offset); + + lazy_plt_layout->plt_reloc_offset); bfd_put_32 (output_bfd, - (h->plt.offset - + htab->lazy_plt->plt_plt_offset + 4), + + lazy_plt_layout->plt_plt_offset + 4), (plt->contents + h->plt.offset - + htab->lazy_plt->plt_plt_offset)); + + lazy_plt_layout->plt_plt_offset)); } } } @@ -5692,12 +5232,12 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, /* Fill in the entry in the GOT procedure linkage table. */ if (! bfd_link_pic (info)) { - got_plt_entry = htab->non_lazy_plt->plt_entry; + got_plt_entry = non_lazy_plt_layout->plt_entry; got_offset += got->output_section->vma + got->output_offset; } else { - got_plt_entry = htab->non_lazy_plt->pic_plt_entry; + got_plt_entry = non_lazy_plt_layout->pic_plt_entry; got_offset += (got->output_section->vma + got->output_offset - gotplt->output_section->vma @@ -5706,10 +5246,10 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, plt_offset = eh->plt_got.offset; memcpy (plt->contents + plt_offset, got_plt_entry, - htab->non_lazy_plt->plt_entry_size); + non_lazy_plt_layout->plt_entry_size); bfd_put_32 (output_bfd, got_offset, (plt->contents + plt_offset - + htab->non_lazy_plt->plt_got_offset)); + + non_lazy_plt_layout->plt_got_offset)); } if (!local_undefweak @@ -5733,8 +5273,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, /* Don't generate dynamic GOT relocation against undefined weak symbol in executable. */ if (h->got.offset != (bfd_vma) -1 - && ! GOT_TLS_GD_ANY_P (elf_i386_hash_entry(h)->tls_type) - && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0 + && ! GOT_TLS_GD_ANY_P (elf_x86_hash_entry(h)->tls_type) + && (elf_x86_hash_entry(h)->tls_type & GOT_TLS_IE) == 0 && !local_undefweak) { Elf_Internal_Rela rel; @@ -5949,12 +5489,12 @@ static bfd_boolean elf_i386_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd *dynobj; asection *sdyn; const struct elf_i386_backend_data *abed; - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return FALSE; @@ -5965,6 +5505,9 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, if (htab->elf.dynamic_sections_created) { Elf32_External_Dyn *dyncon, *dynconend; + const struct elf_i386_plt_layout *plt_layout; + const struct elf_i386_lazy_plt_layout *lazy_plt_layout; + const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout; if (sdyn == NULL || htab->elf.sgot == NULL) abort (); @@ -6005,6 +5548,10 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); } + plt_layout = &elf_i386_plt (htab); + lazy_plt_layout = elf_i386_lazy_plt (htab); + non_lazy_plt_layout = elf_i386_non_lazy_plt (htab); + if (htab->elf.splt && htab->elf.splt->size > 0) { /* UnixWare sets the entsize of .plt to 4, although that doesn't @@ -6012,15 +5559,15 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, elf_section_data (htab->elf.splt->output_section) ->this_hdr.sh_entsize = 4; - if (htab->plt.has_plt0) + if (plt_layout->has_plt0) { /* Fill in the special first entry in the procedure linkage table. */ - memcpy (htab->elf.splt->contents, htab->plt.plt0_entry, - htab->lazy_plt->plt0_entry_size); - memset (htab->elf.splt->contents + htab->lazy_plt->plt0_entry_size, + memcpy (htab->elf.splt->contents, plt_layout->plt0_entry, + lazy_plt_layout->plt0_entry_size); + memset (htab->elf.splt->contents + lazy_plt_layout->plt0_entry_size, abed->plt0_pad_byte, - htab->plt.plt_entry_size - htab->lazy_plt->plt0_entry_size); + plt_layout->plt_entry_size - lazy_plt_layout->plt0_entry_size); if (!bfd_link_pic (info)) { bfd_put_32 (output_bfd, @@ -6028,43 +5575,44 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, + htab->elf.sgotplt->output_offset + 4), htab->elf.splt->contents - + htab->lazy_plt->plt0_got1_offset); + + lazy_plt_layout->plt0_got1_offset); bfd_put_32 (output_bfd, (htab->elf.sgotplt->output_section->vma + htab->elf.sgotplt->output_offset + 8), htab->elf.splt->contents - + htab->lazy_plt->plt0_got2_offset); + + lazy_plt_layout->plt0_got2_offset); if (abed->os == is_vxworks) { Elf_Internal_Rela rel; int num_plts = (htab->elf.splt->size - / htab->plt.plt_entry_size) - 1; + / plt_layout->plt_entry_size) - 1; unsigned char *p; + asection *srelplt2 = elf_i386_srelplt2 (htab); /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 4. On IA32 we use REL relocations so the addend goes in the PLT directly. */ rel.r_offset = (htab->elf.splt->output_section->vma + htab->elf.splt->output_offset - + htab->lazy_plt->plt0_got1_offset); + + lazy_plt_layout->plt0_got1_offset); rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); bfd_elf32_swap_reloc_out (output_bfd, &rel, - htab->srelplt2->contents); + srelplt2->contents); /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ rel.r_offset = (htab->elf.splt->output_section->vma + htab->elf.splt->output_offset - + htab->lazy_plt->plt0_got2_offset); + + lazy_plt_layout->plt0_got2_offset); rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); bfd_elf32_swap_reloc_out (output_bfd, &rel, - htab->srelplt2->contents + + srelplt2->contents + sizeof (Elf32_External_Rel)); /* Correct the .rel.plt.unloaded relocations. */ - p = htab->srelplt2->contents; + p = srelplt2->contents; if (bfd_link_pic (info)) p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel); else @@ -6091,11 +5639,11 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, if (htab->plt_got != NULL && htab->plt_got->size > 0) elf_section_data (htab->plt_got->output_section) - ->this_hdr.sh_entsize = htab->non_lazy_plt->plt_entry_size; + ->this_hdr.sh_entsize = non_lazy_plt_layout->plt_entry_size; if (htab->plt_second != NULL && htab->plt_second->size > 0) elf_section_data (htab->plt_second->output_section) - ->this_hdr.sh_entsize = htab->non_lazy_plt->plt_entry_size; + ->this_hdr.sh_entsize = non_lazy_plt_layout->plt_entry_size; } /* Fill in the first three entries in the global offset table. */ @@ -6229,7 +5777,8 @@ elf_i386_output_arch_local_syms asection *, struct elf_link_hash_entry *) ATTRIBUTE_UNUSED) { - struct elf_i386_link_hash_table *htab = elf_i386_hash_table (info); + struct elf_x86_link_hash_table *htab + = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return FALSE; @@ -6241,22 +5790,6 @@ elf_i386_output_arch_local_syms return TRUE; } -/* Sort relocs into address order. */ - -static int -compare_relocs (const void *ap, const void *bp) -{ - const arelent *a = * (const arelent **) ap; - const arelent *b = * (const arelent **) bp; - - if (a->address > b->address) - return 1; - else if (a->address < b->address) - return -1; - else - return 0; -} - enum elf_i386_plt_type { plt_non_lazy = 0, @@ -6488,7 +6021,8 @@ elf_i386_get_synthetic_symtab (bfd *abfd, dynsyms); /* Sort the relocs by address. */ - qsort (dynrelbuf, dynrelcount, sizeof (arelent *), compare_relocs); + qsort (dynrelbuf, dynrelcount, sizeof (arelent *), + _bfd_x86_elf_compare_relocs); size = count * sizeof (asymbol); @@ -6648,149 +6182,6 @@ bad_return: return count; } -/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ - -static bfd_boolean -elf_i386_hash_symbol (struct elf_link_hash_entry *h) -{ - if (h->plt.offset != (bfd_vma) -1 - && !h->def_regular - && !h->pointer_equality_needed) - return FALSE; - - return _bfd_elf_hash_symbol (h); -} - -/* Parse i386 GNU properties. */ - -static enum elf_property_kind -elf_i386_parse_gnu_properties (bfd *abfd, unsigned int type, - bfd_byte *ptr, unsigned int datasz) -{ - elf_property *prop; - - switch (type) - { - case GNU_PROPERTY_X86_ISA_1_USED: - case GNU_PROPERTY_X86_ISA_1_NEEDED: - case GNU_PROPERTY_X86_FEATURE_1_AND: - if (datasz != 4) - { - _bfd_error_handler - ((type == GNU_PROPERTY_X86_ISA_1_USED - ? _("error: %B: <corrupt x86 ISA used size: 0x%x>") - : (type == GNU_PROPERTY_X86_ISA_1_NEEDED - ? _("error: %B: <corrupt x86 ISA needed size: 0x%x>") - : _("error: %B: <corrupt x86 feature size: 0x%x>"))), - abfd, datasz); - return property_corrupt; - } - prop = _bfd_elf_get_property (abfd, type, datasz); - /* Combine properties of the same type. */ - prop->u.number |= bfd_h_get_32 (abfd, ptr); - prop->pr_kind = property_number; - break; - - default: - return property_ignored; - } - - return property_number; -} - -/* Merge i386 GNU property BPROP with APROP. If APROP isn't NULL, - return TRUE if APROP is updated. Otherwise, return TRUE if BPROP - should be merged with ABFD. */ - -static bfd_boolean -elf_i386_merge_gnu_properties (struct bfd_link_info *info, - bfd *abfd ATTRIBUTE_UNUSED, - elf_property *aprop, - elf_property *bprop) -{ - unsigned int number, features; - bfd_boolean updated = FALSE; - unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; - - switch (pr_type) - { - case GNU_PROPERTY_X86_ISA_1_USED: - case GNU_PROPERTY_X86_ISA_1_NEEDED: - if (aprop != NULL && bprop != NULL) - { - number = aprop->u.number; - aprop->u.number = number | bprop->u.number; - updated = number != (unsigned int) aprop->u.number; - } - else - { - /* Return TRUE if APROP is NULL to indicate that BPROP should - be added to ABFD. */ - updated = aprop == NULL; - } - break; - - case GNU_PROPERTY_X86_FEATURE_1_AND: - /* Only one of APROP and BPROP can be NULL: - 1. APROP & BPROP when both APROP and BPROP aren't NULL. - 2. If APROP is NULL, remove x86 feature. - 3. Otherwise, do nothing. - */ - if (aprop != NULL && bprop != NULL) - { - features = 0; - if (info->ibt) - features = GNU_PROPERTY_X86_FEATURE_1_IBT; - if (info->shstk) - features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; - number = aprop->u.number; - /* Add GNU_PROPERTY_X86_FEATURE_1_IBT and - GNU_PROPERTY_X86_FEATURE_1_SHSTK. */ - aprop->u.number = (number & bprop->u.number) | features; - updated = number != (unsigned int) aprop->u.number; - /* Remove the property if all feature bits are cleared. */ - if (aprop->u.number == 0) - aprop->pr_kind = property_remove; - } - else - { - features = 0; - if (info->ibt) - features = GNU_PROPERTY_X86_FEATURE_1_IBT; - if (info->shstk) - features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; - if (features) - { - /* Add GNU_PROPERTY_X86_FEATURE_1_IBT and - GNU_PROPERTY_X86_FEATURE_1_SHSTK. */ - if (aprop != NULL) - { - number = aprop->u.number; - aprop->u.number = number | features; - updated = number != (unsigned int) aprop->u.number; - } - else - { - bprop->u.number |= features; - updated = TRUE; - } - } - else if (aprop != NULL) - { - aprop->pr_kind = property_remove; - updated = TRUE; - } - } - break; - - default: - /* Never should happen. */ - abort (); - } - - return updated; -} - /* Set up i386 GNU properties. Return the first relocatable ELF input with GNU properties if found. Otherwise, return NULL. */ @@ -6803,10 +6194,13 @@ elf_i386_link_setup_gnu_properties (struct bfd_link_info *info) bfd *dynobj; bfd_boolean use_ibt_plt; unsigned int plt_alignment, features; - struct elf_i386_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd *pbfd; bfd *ebfd = NULL; elf_property *prop; + struct elf_i386_plt_layout *plt_layout; + const struct elf_i386_lazy_plt_layout *lazy_plt_layout; + const struct elf_i386_non_lazy_plt_layout *non_lazy_plt_layout; features = 0; if (info->ibt) @@ -6867,7 +6261,7 @@ error_alignment: if (bfd_link_relocatable (info)) return pbfd; - htab = elf_i386_hash_table (info); + htab = elf_x86_hash_table (info, I386_ELF_DATA); if (htab == NULL) return pbfd; @@ -6922,10 +6316,12 @@ error_alignment: } } + plt_layout = &elf_i386_plt (htab); + /* Even when lazy binding is disabled by "-z now", the PLT0 entry may still be used with LD_AUDIT or LD_PROFILE if PLT entry is used for canonical function address. */ - htab->plt.has_plt0 = 1; + plt_layout->has_plt0 = 1; normal_target = FALSE; switch (get_elf_i386_backend_data (info->output_bfd)->os) @@ -6933,77 +6329,80 @@ error_alignment: case is_normal: if (use_ibt_plt) { - htab->lazy_plt = &elf_i386_lazy_ibt_plt; - htab->non_lazy_plt = &elf_i386_non_lazy_ibt_plt; + elf_i386_lazy_plt (htab) = &elf_i386_lazy_ibt_plt; + elf_i386_non_lazy_plt (htab) = &elf_i386_non_lazy_ibt_plt; } else { - htab->lazy_plt = &elf_i386_lazy_plt; - htab->non_lazy_plt = &elf_i386_non_lazy_plt; + elf_i386_lazy_plt (htab) = &elf_i386_lazy_plt; + elf_i386_non_lazy_plt (htab) = &elf_i386_non_lazy_plt; } normal_target = TRUE; break; case is_vxworks: - htab->lazy_plt = &elf_i386_lazy_plt; - htab->non_lazy_plt = NULL; + elf_i386_lazy_plt (htab) = &elf_i386_lazy_plt; + elf_i386_non_lazy_plt (htab) = NULL; if (!elf_vxworks_create_dynamic_sections (dynobj, info, - &htab->srelplt2)) + &elf_i386_srelplt2 (htab))) info->callbacks->einfo (_("%F: failed to create VxWorks dynamic sections\n")); break; case is_nacl: - htab->lazy_plt = &elf_i386_nacl_plt; - htab->non_lazy_plt = NULL; + elf_i386_lazy_plt (htab) = &elf_i386_nacl_plt; + elf_i386_non_lazy_plt (htab) = NULL; break; } + lazy_plt_layout = elf_i386_lazy_plt (htab); + non_lazy_plt_layout = elf_i386_non_lazy_plt (htab); + pltsec = htab->elf.splt; /* If the non-lazy PLT is available, use it for all PLT entries if there are no PLT0 or no .plt section. */ - if (htab->non_lazy_plt != NULL - && (!htab->plt.has_plt0 || pltsec == NULL)) + if (non_lazy_plt_layout != NULL + && (!plt_layout->has_plt0 || pltsec == NULL)) { lazy_plt = FALSE; if (bfd_link_pic (info)) - htab->plt.plt_entry - = htab->non_lazy_plt->pic_plt_entry; + plt_layout->plt_entry + = non_lazy_plt_layout->pic_plt_entry; else - htab->plt.plt_entry - = htab->non_lazy_plt->plt_entry; - htab->plt.plt_entry_size - = htab->non_lazy_plt->plt_entry_size; - htab->plt.plt_got_offset - = htab->non_lazy_plt->plt_got_offset; - htab->plt.eh_frame_plt_size - = htab->non_lazy_plt->eh_frame_plt_size; - htab->plt.eh_frame_plt - = htab->non_lazy_plt->eh_frame_plt; + plt_layout->plt_entry + = non_lazy_plt_layout->plt_entry; + plt_layout->plt_entry_size + = non_lazy_plt_layout->plt_entry_size; + plt_layout->plt_got_offset + = non_lazy_plt_layout->plt_got_offset; + plt_layout->eh_frame_plt_size + = non_lazy_plt_layout->eh_frame_plt_size; + plt_layout->eh_frame_plt + = non_lazy_plt_layout->eh_frame_plt; } else { lazy_plt = TRUE; if (bfd_link_pic (info)) { - htab->plt.plt0_entry - = htab->lazy_plt->pic_plt0_entry; - htab->plt.plt_entry - = htab->lazy_plt->pic_plt_entry; + plt_layout->plt0_entry + = lazy_plt_layout->pic_plt0_entry; + plt_layout->plt_entry + = lazy_plt_layout->pic_plt_entry; } else { - htab->plt.plt0_entry - = htab->lazy_plt->plt0_entry; - htab->plt.plt_entry - = htab->lazy_plt->plt_entry; + plt_layout->plt0_entry + = lazy_plt_layout->plt0_entry; + plt_layout->plt_entry + = lazy_plt_layout->plt_entry; } - htab->plt.plt_entry_size - = htab->lazy_plt->plt_entry_size; - htab->plt.plt_got_offset - = htab->lazy_plt->plt_got_offset; - htab->plt.eh_frame_plt_size - = htab->lazy_plt->eh_frame_plt_size; - htab->plt.eh_frame_plt - = htab->lazy_plt->eh_frame_plt; + plt_layout->plt_entry_size + = lazy_plt_layout->plt_entry_size; + plt_layout->plt_got_offset + = lazy_plt_layout->plt_got_offset; + plt_layout->eh_frame_plt_size + = lazy_plt_layout->eh_frame_plt_size; + plt_layout->eh_frame_plt + = lazy_plt_layout->eh_frame_plt; } /* Return if there are no normal input files. */ @@ -7022,7 +6421,7 @@ error_alignment: if (!_bfd_elf_create_ifunc_sections (dynobj, info)) info->callbacks->einfo (_("%F: failed to create ifunc sections\n")); - plt_alignment = bfd_log2 (htab->plt.plt_entry_size); + plt_alignment = bfd_log2 (plt_layout->plt_entry_size); if (pltsec != NULL) { @@ -7033,8 +6432,8 @@ error_alignment: asection *s = bfd_get_linker_section (dynobj, ".interp"); if (s == NULL) abort (); - s->size = sizeof ELF_DYNAMIC_INTERPRETER; - s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; + s->size = htab->dynamic_interpreter_size; + s->contents = (unsigned char *) htab->dynamic_interpreter; htab->interp = s; } @@ -7051,7 +6450,7 @@ error_alignment: | SEC_LOAD | SEC_READONLY); unsigned int non_lazy_plt_alignment - = bfd_log2 (htab->non_lazy_plt->plt_entry_size); + = bfd_log2 (non_lazy_plt_layout->plt_entry_size); sec = pltsec; if (!bfd_set_section_alignment (sec->owner, sec, @@ -7142,38 +6541,6 @@ error_alignment: return pbfd; } -static bfd_boolean -elf_i386_link_check_relocs (bfd *abfd, struct bfd_link_info *info) -{ - if (!bfd_link_relocatable (info)) - { - /* Check for ___tls_get_addr reference. */ - struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (elf_hash_table (info), "___tls_get_addr", - FALSE, FALSE, FALSE); - if (h != NULL) - ((struct elf_i386_link_hash_entry *) h)->tls_get_addr = 1; - } - - /* Invoke the regular ELF backend linker to do all the work. */ - return _bfd_elf_link_check_relocs (abfd, info); -} - -static void -elf_i386_merge_symbol_attribute (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - bfd_boolean definition, - bfd_boolean dynamic ATTRIBUTE_UNUSED) -{ - if (definition) - { - struct elf_i386_link_hash_entry *eh - = (struct elf_i386_link_hash_entry *) h; - eh->def_protected = (ELF_ST_VISIBILITY (isym->st_other) - == STV_PROTECTED); - } -} - #define TARGET_LITTLE_SYM i386_elf32_vec #define TARGET_LITTLE_NAME "elf32-i386" #define ELF_ARCH bfd_arch_i386 @@ -7204,12 +6571,10 @@ elf_i386_merge_symbol_attribute (struct elf_link_hash_entry *h, #define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup #define bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup #define bfd_elf32_get_synthetic_symtab elf_i386_get_synthetic_symtab -#define bfd_elf32_bfd_link_check_relocs elf_i386_link_check_relocs #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol #define elf_backend_relocs_compatible _bfd_elf_relocs_compatible #define elf_backend_check_relocs elf_i386_check_relocs -#define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol #define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections #define elf_backend_fake_sections elf_i386_fake_sections #define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections @@ -7221,15 +6586,7 @@ elf_i386_merge_symbol_attribute (struct elf_link_hash_entry *h, #define elf_backend_reloc_type_class elf_i386_reloc_type_class #define elf_backend_relocate_section elf_i386_relocate_section #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections -#define elf_backend_always_size_sections elf_i386_always_size_sections -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_hash_symbol elf_i386_hash_symbol -#define elf_backend_fixup_symbol elf_i386_fixup_symbol -#define elf_backend_parse_gnu_properties elf_i386_parse_gnu_properties -#define elf_backend_merge_gnu_properties elf_i386_merge_gnu_properties #define elf_backend_setup_gnu_properties elf_i386_link_setup_gnu_properties -#define elf_backend_merge_symbol_attribute elf_i386_merge_symbol_attribute #include "elf32-target.h" diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 847a182..442ee95 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -19,15 +19,8 @@ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "sysdep.h" -#include "bfd.h" -#include "bfdlink.h" -#include "libbfd.h" -#include "elf-bfd.h" +#include "elfxx-x86.h" #include "elf-nacl.h" -#include "bfd_stdint.h" -#include "objalloc.h" -#include "hashtab.h" #include "dwarf2.h" #include "libiberty.h" @@ -534,12 +527,6 @@ elf_x86_64_write_core_note (bfd *abfd, char *buf, int *bufsiz, #define ELF64_DYNAMIC_INTERPRETER "/lib/ld64.so.1" #define ELF32_DYNAMIC_INTERPRETER "/lib/ldx32.so.1" -/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid - copying dynamic variables from a shared lib into an app's dynbss - section, and instead use a dynamic relocation to point into the - shared lib. */ -#define ELIMINATE_COPY_RELOCS 1 - /* The size in bytes of an entry in the global offset table. */ #define GOT_ENTRY_SIZE 8 @@ -1045,45 +1032,7 @@ static const struct elf_x86_64_backend_data elf_x86_64_arch_bed = #define elf_backend_arch_data &elf_x86_64_arch_bed -/* Is a undefined weak symbol which is resolved to 0. Reference to an - undefined weak symbol is resolved to 0 when building executable if - it isn't dynamic and - 1. Has non-GOT/non-PLT relocations in text section. Or - 2. Has no GOT/PLT relocation. - Local undefined weak symbol is always resolved to 0. - */ -#define UNDEFINED_WEAK_RESOLVED_TO_ZERO(INFO, GOT_RELOC, EH) \ - ((EH)->elf.root.type == bfd_link_hash_undefweak \ - && ((EH)->elf.forced_local \ - || (bfd_link_executable (INFO) \ - && (elf_x86_64_hash_table (INFO)->interp == NULL \ - || !(GOT_RELOC) \ - || (EH)->has_non_got_reloc \ - || !(INFO)->dynamic_undefined_weak)))) - -/* Should copy relocation be generated for a symbol. Don't generate - copy relocation against a protected symbol defined in a shared - object with GNU_PROPERTY_NO_COPY_ON_PROTECTED. */ -#define SYMBOL_NO_COPYRELOC(INFO, EH) \ - ((EH)->def_protected \ - && ((EH)->elf.root.type == bfd_link_hash_defined \ - || (EH)->elf.root.type == bfd_link_hash_defweak) \ - && elf_has_no_copy_on_protected ((EH)->elf.root.u.def.section->owner) \ - && ((EH)->elf.root.u.def.section->owner->flags & DYNAMIC) != 0 \ - && ((EH)->elf.root.u.def.section->flags & SEC_CODE) == 0) - -/* x86-64 ELF linker hash entry. */ - -struct elf_x86_64_link_hash_entry -{ - struct elf_link_hash_entry elf; - - /* Track dynamic relocs copied for this symbol. */ - struct elf_dyn_relocs *dyn_relocs; - -#define GOT_UNKNOWN 0 -#define GOT_NORMAL 1 -#define GOT_TLS_GD 2 +/* Values in tls_type of x86 ELF linker hash entry. */ #define GOT_TLS_IE 3 #define GOT_TLS_GDESC 4 #define GOT_TLS_GD_BOTH_P(type) \ @@ -1094,68 +1043,6 @@ struct elf_x86_64_link_hash_entry ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type)) #define GOT_TLS_GD_ANY_P(type) \ (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) - unsigned char tls_type; - - /* TRUE if a weak symbol with a real definition needs a copy reloc. - When there is a weak symbol with a real definition, the processor - independent code will have arranged for us to see the real - definition first. We need to copy the needs_copy bit from the - real definition and check it when allowing copy reloc in PIE. */ - unsigned int needs_copy : 1; - - /* TRUE if symbol has GOT or PLT relocations. */ - unsigned int has_got_reloc : 1; - - /* TRUE if symbol has non-GOT/non-PLT relocations in text sections. */ - unsigned int has_non_got_reloc : 1; - - /* Don't call finish_dynamic_symbol on this symbol. */ - unsigned int no_finish_dynamic_symbol : 1; - - /* TRUE if symbol is __tls_get_addr. */ - unsigned int tls_get_addr : 1; - - /* TRUE if symbol is defined as a protected symbol. */ - unsigned int def_protected : 1; - - /* Reference count of C/C++ function pointer relocations in read-write - section which can be resolved at run-time. */ - bfd_signed_vma func_pointer_refcount; - - /* Information about the GOT PLT entry. Filled when there are both - GOT and PLT relocations against the same function. */ - union gotplt_union plt_got; - - /* Information about the second PLT entry. */ - union gotplt_union plt_second; - - /* Offset of the GOTPLT entry reserved for the TLS descriptor, - starting at the end of the jump table. */ - bfd_vma tlsdesc_got; -}; - -#define elf_x86_64_hash_entry(ent) \ - ((struct elf_x86_64_link_hash_entry *)(ent)) - -struct elf_x86_64_obj_tdata -{ - struct elf_obj_tdata root; - - /* tls_type for each local got entry. */ - char *local_got_tls_type; - - /* GOTPLT entries for TLS descriptors. */ - bfd_vma *local_tlsdesc_gotent; -}; - -#define elf_x86_64_tdata(abfd) \ - ((struct elf_x86_64_obj_tdata *) (abfd)->tdata.any) - -#define elf_x86_64_local_got_tls_type(abfd) \ - (elf_x86_64_tdata (abfd)->local_got_tls_type) - -#define elf_x86_64_local_tlsdesc_gotent(abfd) \ - (elf_x86_64_tdata (abfd)->local_tlsdesc_gotent) #define is_x86_64_elf(bfd) \ (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ @@ -1165,7 +1052,7 @@ struct elf_x86_64_obj_tdata static bfd_boolean elf_x86_64_mkobject (bfd *abfd) { - return bfd_elf_allocate_object (abfd, sizeof (struct elf_x86_64_obj_tdata), + return bfd_elf_allocate_object (abfd, sizeof (struct elf_x86_obj_tdata), X86_64_ELF_DATA); } @@ -1173,15 +1060,7 @@ elf_x86_64_mkobject (bfd *abfd) struct elf_x86_64_link_hash_table { - struct elf_link_hash_table elf; - - /* Short-cuts to get to dynamic linker sections. */ - asection *interp; - asection *plt_eh_frame; - asection *plt_second; - asection *plt_second_eh_frame; - asection *plt_got; - asection *plt_got_eh_frame; + struct elf_x86_link_hash_table x86; /* Parameters describing PLT generation, lazy or non-lazy. */ struct elf_x86_64_plt_layout plt; @@ -1191,201 +1070,41 @@ struct elf_x86_64_link_hash_table /* Parameters describing non-lazy PLT generation. */ const struct elf_x86_64_non_lazy_plt_layout *non_lazy_plt; - - union - { - bfd_signed_vma refcount; - bfd_vma offset; - } tls_ld_got; - - /* The amount of space used by the jump slots in the GOT. */ - bfd_vma sgotplt_jump_table_size; - - /* Small local sym cache. */ - struct sym_cache sym_cache; - - bfd_vma (*r_info) (bfd_vma, bfd_vma); - bfd_vma (*r_sym) (bfd_vma); - unsigned int pointer_r_type; - const char *dynamic_interpreter; - int dynamic_interpreter_size; - - /* _TLS_MODULE_BASE_ symbol. */ - struct bfd_link_hash_entry *tls_module_base; - - /* Used by local STT_GNU_IFUNC symbols. */ - htab_t loc_hash_table; - void * loc_hash_memory; - - /* The offset into splt of the PLT entry for the TLS descriptor - resolver. Special values are 0, if not necessary (or not found - to be necessary yet), and -1 if needed but not determined - yet. */ - bfd_vma tlsdesc_plt; - /* The offset into sgot of the GOT entry used by the PLT entry - above. */ - bfd_vma tlsdesc_got; - - /* The index of the next R_X86_64_JUMP_SLOT entry in .rela.plt. */ - bfd_vma next_jump_slot_index; - /* The index of the next R_X86_64_IRELATIVE entry in .rela.plt. */ - bfd_vma next_irelative_index; - - /* TRUE if there are dynamic relocs against IFUNC symbols that apply - to read-only sections. */ - bfd_boolean readonly_dynrelocs_against_ifunc; }; -/* Get the x86-64 ELF linker hash table from a link_info structure. */ - -#define elf_x86_64_hash_table(p) \ - (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) \ - == X86_64_ELF_DATA ? ((struct elf_x86_64_link_hash_table *) ((p)->hash)) : NULL) - -#define elf_x86_64_compute_jump_table_size(htab) \ - ((htab)->elf.srelplt->reloc_count * GOT_ENTRY_SIZE) - -/* Create an entry in an x86-64 ELF linker hash table. */ - -static struct bfd_hash_entry * -elf_x86_64_link_hash_newfunc (struct bfd_hash_entry *entry, - struct bfd_hash_table *table, - const char *string) -{ - /* Allocate the structure if it has not already been allocated by a - subclass. */ - if (entry == NULL) - { - entry = (struct bfd_hash_entry *) - bfd_hash_allocate (table, - sizeof (struct elf_x86_64_link_hash_entry)); - if (entry == NULL) - return entry; - } +#define elf_x86_64_next_tls_desc_index(htab) \ + ((struct elf_x86_64_link_hash_table *) (htab))->next_tls_desc_index - /* Call the allocation method of the superclass. */ - entry = _bfd_elf_link_hash_newfunc (entry, table, string); - if (entry != NULL) - { - struct elf_x86_64_link_hash_entry *eh; +#define elf_x86_64_srelplt2(htab) \ + ((struct elf_x86_64_link_hash_table *) (htab))->srelplt2 - eh = (struct elf_x86_64_link_hash_entry *) entry; - eh->dyn_relocs = NULL; - eh->tls_type = GOT_UNKNOWN; - eh->needs_copy = 0; - eh->has_got_reloc = 0; - eh->has_non_got_reloc = 0; - eh->no_finish_dynamic_symbol = 0; - eh->tls_get_addr = 0; - eh->def_protected = 0; - eh->func_pointer_refcount = 0; - eh->plt_second.offset = (bfd_vma) -1; - eh->plt_got.offset = (bfd_vma) -1; - eh->tlsdesc_got = (bfd_vma) -1; - } +#define elf_x86_64_plt(htab) \ + ((struct elf_x86_64_link_hash_table *) (htab))->plt - return entry; -} +#define elf_x86_64_lazy_plt(htab) \ + ((struct elf_x86_64_link_hash_table *) (htab))->lazy_plt -/* Compute a hash of a local hash entry. We use elf_link_hash_entry - for local symbol so that we can handle local STT_GNU_IFUNC symbols - as global symbol. We reuse indx and dynstr_index for local symbol - hash since they aren't used by global symbols in this backend. */ - -static hashval_t -elf_x86_64_local_htab_hash (const void *ptr) -{ - struct elf_link_hash_entry *h - = (struct elf_link_hash_entry *) ptr; - return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index); -} - -/* Compare local hash entries. */ - -static int -elf_x86_64_local_htab_eq (const void *ptr1, const void *ptr2) -{ - struct elf_link_hash_entry *h1 - = (struct elf_link_hash_entry *) ptr1; - struct elf_link_hash_entry *h2 - = (struct elf_link_hash_entry *) ptr2; +#define elf_x86_64_non_lazy_plt(htab) \ + ((struct elf_x86_64_link_hash_table *) (htab))->non_lazy_plt - return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index; -} - -/* Find and/or create a hash entry for local symbol. */ - -static struct elf_link_hash_entry * -elf_x86_64_get_local_sym_hash (struct elf_x86_64_link_hash_table *htab, - bfd *abfd, const Elf_Internal_Rela *rel, - bfd_boolean create) -{ - struct elf_x86_64_link_hash_entry e, *ret; - asection *sec = abfd->sections; - hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id, - htab->r_sym (rel->r_info)); - void **slot; - - e.elf.indx = sec->id; - e.elf.dynstr_index = htab->r_sym (rel->r_info); - slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h, - create ? INSERT : NO_INSERT); - - if (!slot) - return NULL; - - if (*slot) - { - ret = (struct elf_x86_64_link_hash_entry *) *slot; - return &ret->elf; - } - - ret = (struct elf_x86_64_link_hash_entry *) - objalloc_alloc ((struct objalloc *) htab->loc_hash_memory, - sizeof (struct elf_x86_64_link_hash_entry)); - if (ret) - { - memset (ret, 0, sizeof (*ret)); - ret->elf.indx = sec->id; - ret->elf.dynstr_index = htab->r_sym (rel->r_info); - ret->elf.dynindx = -1; - ret->func_pointer_refcount = 0; - ret->plt_got.offset = (bfd_vma) -1; - *slot = ret; - } - return &ret->elf; -} - -/* Destroy an X86-64 ELF linker hash table. */ - -static void -elf_x86_64_link_hash_table_free (bfd *obfd) -{ - struct elf_x86_64_link_hash_table *htab - = (struct elf_x86_64_link_hash_table *) obfd->link.hash; - - if (htab->loc_hash_table) - htab_delete (htab->loc_hash_table); - if (htab->loc_hash_memory) - objalloc_free ((struct objalloc *) htab->loc_hash_memory); - _bfd_elf_link_hash_table_free (obfd); -} +#define elf_x86_64_compute_jump_table_size(htab) \ + ((htab)->elf.srelplt->reloc_count * GOT_ENTRY_SIZE) /* Create an X86-64 ELF linker hash table. */ static struct bfd_link_hash_table * elf_x86_64_link_hash_table_create (bfd *abfd) { - struct elf_x86_64_link_hash_table *ret; + struct elf_x86_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf_x86_64_link_hash_table); - ret = (struct elf_x86_64_link_hash_table *) bfd_zmalloc (amt); + ret = (struct elf_x86_link_hash_table *) bfd_zmalloc (amt); if (ret == NULL) return NULL; if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, - elf_x86_64_link_hash_newfunc, - sizeof (struct elf_x86_64_link_hash_entry), + _bfd_x86_elf_link_hash_newfunc, + sizeof (struct elf_x86_link_hash_entry), X86_64_ELF_DATA)) { free (ret); @@ -1409,100 +1128,22 @@ elf_x86_64_link_hash_table_create (bfd *abfd) ret->dynamic_interpreter_size = sizeof ELF32_DYNAMIC_INTERPRETER; } + ret->tls_get_addr = "__tls_get_addr"; ret->loc_hash_table = htab_try_create (1024, - elf_x86_64_local_htab_hash, - elf_x86_64_local_htab_eq, + _bfd_x86_elf_local_htab_hash, + _bfd_x86_elf_local_htab_eq, NULL); ret->loc_hash_memory = objalloc_create (); if (!ret->loc_hash_table || !ret->loc_hash_memory) { - elf_x86_64_link_hash_table_free (abfd); + _bfd_x86_elf_link_hash_table_free (abfd); return NULL; } - ret->elf.root.hash_table_free = elf_x86_64_link_hash_table_free; + ret->elf.root.hash_table_free = _bfd_x86_elf_link_hash_table_free; return &ret->elf.root; } -/* Copy the extra info we tack onto an elf_link_hash_entry. */ - -static void -elf_x86_64_copy_indirect_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *dir, - struct elf_link_hash_entry *ind) -{ - struct elf_x86_64_link_hash_entry *edir, *eind; - - edir = (struct elf_x86_64_link_hash_entry *) dir; - eind = (struct elf_x86_64_link_hash_entry *) ind; - - edir->has_got_reloc |= eind->has_got_reloc; - edir->has_non_got_reloc |= eind->has_non_got_reloc; - - if (eind->dyn_relocs != NULL) - { - if (edir->dyn_relocs != NULL) - { - struct elf_dyn_relocs **pp; - struct elf_dyn_relocs *p; - - /* Add reloc counts against the indirect sym to the direct sym - list. Merge any entries against the same section. */ - for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) - { - struct elf_dyn_relocs *q; - - for (q = edir->dyn_relocs; q != NULL; q = q->next) - if (q->sec == p->sec) - { - q->pc_count += p->pc_count; - q->count += p->count; - *pp = p->next; - break; - } - if (q == NULL) - pp = &p->next; - } - *pp = edir->dyn_relocs; - } - - edir->dyn_relocs = eind->dyn_relocs; - eind->dyn_relocs = NULL; - } - - if (ind->root.type == bfd_link_hash_indirect - && dir->got.refcount <= 0) - { - edir->tls_type = eind->tls_type; - eind->tls_type = GOT_UNKNOWN; - } - - if (ELIMINATE_COPY_RELOCS - && ind->root.type != bfd_link_hash_indirect - && dir->dynamic_adjusted) - { - /* If called to transfer flags for a weakdef during processing - of elf_adjust_dynamic_symbol, don't copy non_got_ref. - We clear it ourselves for ELIMINATE_COPY_RELOCS. */ - if (dir->versioned != versioned_hidden) - dir->ref_dynamic |= ind->ref_dynamic; - dir->ref_regular |= ind->ref_regular; - dir->ref_regular_nonweak |= ind->ref_regular_nonweak; - dir->needs_plt |= ind->needs_plt; - dir->pointer_equality_needed |= ind->pointer_equality_needed; - } - else - { - if (eind->func_pointer_refcount > 0) - { - edir->func_pointer_refcount += eind->func_pointer_refcount; - eind->func_pointer_refcount = 0; - } - - _bfd_elf_link_hash_copy_indirect (info, dir, ind); - } -} - static bfd_boolean elf64_x86_64_elf_object_p (bfd *abfd) { @@ -1538,11 +1179,11 @@ elf_x86_64_check_tls_transition (bfd *abfd, bfd_boolean largepic = FALSE; struct elf_link_hash_entry *h; bfd_vma offset; - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd_byte *call; bfd_boolean indirect_call; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); offset = rel->r_offset; switch (r_type) { @@ -1682,7 +1323,7 @@ elf_x86_64_check_tls_transition (bfd *abfd, h = sym_hashes[r_symndx - symtab_hdr->sh_info]; if (h == NULL - || !((struct elf_x86_64_link_hash_entry *) h)->tls_get_addr) + || !((struct elf_x86_link_hash_entry *) h)->tls_get_addr) return FALSE; else if (largepic) return ELF32_R_TYPE (rel[1].r_info) == R_X86_64_PLTOFF64; @@ -1861,9 +1502,9 @@ elf_x86_64_tls_transition (struct bfd_link_info *info, bfd *abfd, name = h->root.root.string; else { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) name = "*unknown*"; else @@ -1923,7 +1564,7 @@ elf_x86_64_need_pic (struct bfd_link_info *info, v = _("protected symbol "); break; default: - if (((struct elf_x86_64_link_hash_entry *) h)->def_protected) + if (((struct elf_x86_link_hash_entry *) h)->def_protected) v = _("protected symbol "); else v = _("symbol "); @@ -1984,7 +1625,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd, asection *sec, bfd_boolean *converted, struct bfd_link_info *link_info) { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd_boolean is_pic; bfd_boolean require_reloc_pc32; bfd_boolean relocx; @@ -2007,7 +1648,7 @@ elf_x86_64_convert_load_reloc (bfd *abfd, asection *sec, if (raddend != -4) return TRUE; - htab = elf_x86_64_hash_table (link_info); + htab = elf_x86_hash_table (link_info, X86_64_ELF_DATA); is_pic = bfd_link_pic (link_info); relocx = (r_type == R_X86_64_GOTPCRELX @@ -2076,8 +1717,9 @@ elf_x86_64_convert_load_reloc (bfd *abfd, asection *sec, R_X86_64_PC32. */ if ((relocx || opcode == 0x8b) && UNDEFINED_WEAK_RESOLVED_TO_ZERO (link_info, + X86_64_ELF_DATA, TRUE, - elf_x86_64_hash_entry (h))) + elf_x86_hash_entry (h))) { if (opcode == 0xff) { @@ -2251,8 +1893,8 @@ convert: } else { - struct elf_x86_64_link_hash_entry *eh - = (struct elf_x86_64_link_hash_entry *) h; + struct elf_x86_link_hash_entry *eh + = (struct elf_x86_link_hash_entry *) h; /* Convert to "nop call foo". ADDR_PREFIX_OPCODE is a nop prefix. */ @@ -2386,7 +2028,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, const Elf_Internal_Rela *relocs) { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; const Elf_Internal_Rela *rel; @@ -2408,7 +2050,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, BFD_ASSERT (is_x86_64_elf (abfd)); - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) { sec->check_relocs_failed = 1; @@ -2435,7 +2077,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, unsigned int r_type; unsigned int r_symndx; struct elf_link_hash_entry *h; - struct elf_x86_64_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; Elf_Internal_Sym *isym; const char *name; bfd_boolean size_reloc; @@ -2462,8 +2104,8 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, /* Check relocation against local STT_GNU_IFUNC symbol. */ if (ELF_ST_TYPE (isym->st_info) == STT_GNU_IFUNC) { - h = elf_x86_64_get_local_sym_hash (htab, abfd, rel, - TRUE); + h = _bfd_elf_x86_get_local_sym_hash (htab, abfd, rel, + TRUE); if (h == NULL) goto error_return; @@ -2538,11 +2180,11 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, rel, rel_end, h, r_symndx, FALSE)) goto error_return; - eh = (struct elf_x86_64_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; switch (r_type) { case R_X86_64_TLSLD: - htab->tls_ld_got.refcount += 1; + htab->tls_ld_or_ldm_got.refcount += 1; goto create_got; case R_X86_64_TPOFF32: @@ -2605,14 +2247,14 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (local_got_refcounts == NULL) goto error_return; elf_local_got_refcounts (abfd) = local_got_refcounts; - elf_x86_64_local_tlsdesc_gotent (abfd) + elf_x86_local_tlsdesc_gotent (abfd) = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); - elf_x86_64_local_got_tls_type (abfd) + elf_x86_local_got_tls_type (abfd) = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); } local_got_refcounts[r_symndx] += 1; old_tls_type - = elf_x86_64_local_got_tls_type (abfd) [r_symndx]; + = elf_x86_local_got_tls_type (abfd) [r_symndx]; } /* If a TLS symbol is accessed using IE at least once, @@ -2648,7 +2290,7 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, if (eh != NULL) eh->tls_type = tls_type; else - elf_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type; + elf_x86_local_got_tls_type (abfd) [r_symndx] = tls_type; } } /* Fall through */ @@ -2949,25 +2591,6 @@ elf_x86_64_gc_mark_hook (asection *sec, return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } -/* Remove undefined weak symbol from the dynamic symbol table if it - is resolved to 0. */ - -static bfd_boolean -elf_x86_64_fixup_symbol (struct bfd_link_info *info, - struct elf_link_hash_entry *h) -{ - if (h->dynindx != -1 - && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, - elf_x86_64_hash_entry (h)->has_got_reloc, - elf_x86_64_hash_entry (h))) - { - h->dynindx = -1; - _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, - h->dynstr_index); - } - return TRUE; -} - /* Adjust a symbol defined by a dynamic object and referenced by a regular object. The current definition is in some section of the dynamic object, but we're not including those sections. We have to @@ -2978,9 +2601,9 @@ static bfd_boolean elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, struct elf_link_hash_entry *h) { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; asection *s, *srel; - struct elf_x86_64_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; struct elf_dyn_relocs *p; /* STT_GNU_IFUNC symbol must go through PLT. */ @@ -2994,7 +2617,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, bfd_size_type pc_count = 0, count = 0; struct elf_dyn_relocs **pp; - eh = (struct elf_x86_64_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) { pc_count += p->pc_count; @@ -3061,7 +2684,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, the link may change h->type. So fix it now. */ h->plt.offset = (bfd_vma) -1; - eh = (struct elf_x86_64_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the @@ -3106,7 +2729,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, if (ELIMINATE_COPY_RELOCS) { - eh = (struct elf_x86_64_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; for (p = eh->dyn_relocs; p != NULL; p = p->next) { s = p->sec->output_section; @@ -3133,7 +2756,7 @@ elf_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, both the dynamic object and the regular object will refer to the same memory location for the variable. */ - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return FALSE; @@ -3168,26 +2791,32 @@ static bfd_boolean elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) { struct bfd_link_info *info; - struct elf_x86_64_link_hash_table *htab; - struct elf_x86_64_link_hash_entry *eh; + struct elf_x86_link_hash_table *htab; + struct elf_x86_link_hash_entry *eh; struct elf_dyn_relocs *p; const struct elf_backend_data *bed; unsigned int plt_entry_size; bfd_boolean resolved_to_zero; + const struct elf_x86_64_plt_layout *plt_layout; + const struct elf_x86_64_non_lazy_plt_layout *non_lazy_plt_layout; if (h->root.type == bfd_link_hash_indirect) return TRUE; - eh = (struct elf_x86_64_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; info = (struct bfd_link_info *) inf; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return FALSE; bed = get_elf_backend_data (info->output_bfd); - plt_entry_size = htab->plt.plt_entry_size; + + plt_layout = &elf_x86_64_plt (htab); + non_lazy_plt_layout = elf_x86_64_non_lazy_plt (htab); + plt_entry_size = plt_layout->plt_entry_size; resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + X86_64_ELF_DATA, eh->has_got_reloc, eh); @@ -3223,7 +2852,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) &eh->dyn_relocs, &htab->readonly_dynrelocs_against_ifunc, plt_entry_size, - (htab->plt.has_plt0 + (plt_layout->has_plt0 * plt_entry_size), GOT_ENTRY_SIZE, TRUE)) { @@ -3234,7 +2863,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) eh->plt_second.offset = s->size; /* Make room for this entry in the second PLT section. */ - s->size += htab->non_lazy_plt->plt_entry_size; + s->size += non_lazy_plt_layout->plt_entry_size; } return TRUE; @@ -3276,7 +2905,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) first entry. The .plt section is used by prelink to undo prelinking for dynamic relocations. */ if (s->size == 0) - s->size = htab->plt.has_plt0 * plt_entry_size; + s->size = plt_layout->has_plt0 * plt_entry_size; if (use_plt_got) eh->plt_got.offset = got_s->size; @@ -3321,12 +2950,12 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) /* Make room for this entry. */ if (use_plt_got) - got_s->size += htab->non_lazy_plt->plt_entry_size; + got_s->size += non_lazy_plt_layout->plt_entry_size; else { s->size += plt_entry_size; if (second_s) - second_s->size += htab->non_lazy_plt->plt_entry_size; + second_s->size += non_lazy_plt_layout->plt_entry_size; /* We also need to make an entry in the .got.plt section, which will be placed in the .got section by the linker @@ -3365,7 +2994,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) if (h->got.refcount > 0 && bfd_link_executable (info) && h->dynindx == -1 - && elf_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE) + && elf_x86_hash_entry (h)->tls_type == GOT_TLS_IE) { h->got.offset = (bfd_vma) -1; } @@ -3373,7 +3002,7 @@ elf_x86_64_allocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) { asection *s; bfd_boolean dyn; - int tls_type = elf_x86_64_hash_entry (h)->tls_type; + int tls_type = elf_x86_hash_entry (h)->tls_type; /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -3567,44 +3196,6 @@ elf_x86_64_allocate_local_dynrelocs (void **slot, void *inf) return elf_x86_64_allocate_dynrelocs (h, inf); } -/* Find any dynamic relocs that apply to read-only sections. */ - -static bfd_boolean -elf_x86_64_readonly_dynrelocs (struct elf_link_hash_entry *h, - void * inf) -{ - struct elf_x86_64_link_hash_entry *eh; - struct elf_dyn_relocs *p; - - /* Skip local IFUNC symbols. */ - if (h->forced_local && h->type == STT_GNU_IFUNC) - return TRUE; - - eh = (struct elf_x86_64_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) - { - asection *s = p->sec->output_section; - - if (s != NULL && (s->flags & SEC_READONLY) != 0) - { - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - info->flags |= DF_TEXTREL; - - if ((info->warn_shared_textrel && bfd_link_pic (info)) - || info->error_textrel) - /* xgettext:c-format */ - info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"), - p->sec->owner, h->root.root.string, - p->sec); - - /* Not an error, just cut short the traversal. */ - return FALSE; - } - } - return TRUE; -} - /* Convert load via the GOT slot to load immediate. */ static bfd_boolean @@ -3615,7 +3206,7 @@ elf_x86_64_convert_load (bfd *abfd, asection *sec, Elf_Internal_Rela *internal_relocs; Elf_Internal_Rela *irel, *irelend; bfd_byte *contents; - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd_boolean changed; bfd_signed_vma *local_got_refcounts; @@ -3639,7 +3230,7 @@ elf_x86_64_convert_load (bfd *abfd, asection *sec, return FALSE; changed = FALSE; - htab = elf_x86_64_hash_table (link_info); + htab = elf_x86_hash_table (link_info, X86_64_ELF_DATA); local_got_refcounts = elf_local_got_refcounts (abfd); /* Get the section contents. */ @@ -3666,9 +3257,9 @@ elf_x86_64_convert_load (bfd *abfd, asection *sec, r_symndx = htab->r_sym (irel->r_info); if (r_symndx < symtab_hdr->sh_info) - h = elf_x86_64_get_local_sym_hash (htab, sec->owner, - (const Elf_Internal_Rela *) irel, - FALSE); + h = _bfd_elf_x86_get_local_sym_hash (htab, sec->owner, + (const Elf_Internal_Rela *) irel, + FALSE); else { h = elf_sym_hashes (abfd)[r_symndx - symtab_hdr->sh_info]; @@ -3741,14 +3332,16 @@ static bfd_boolean elf_x86_64_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd *dynobj; asection *s; bfd_boolean relocs; bfd *ibfd; const struct elf_backend_data *bed; + const struct elf_x86_64_plt_layout *plt_layout; + const struct elf_x86_64_non_lazy_plt_layout *non_lazy_plt_layout; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return FALSE; bed = get_elf_backend_data (output_bfd); @@ -3757,6 +3350,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, if (dynobj == NULL) abort (); + plt_layout = &elf_x86_64_plt (htab); + non_lazy_plt_layout = elf_x86_64_non_lazy_plt (htab); + /* Set up .got offsets for local syms, and space for local dynamic relocs. */ for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link.next) @@ -3817,8 +3413,8 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, symtab_hdr = &elf_symtab_hdr (ibfd); locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; - local_tls_type = elf_x86_64_local_got_tls_type (ibfd); - local_tlsdesc_gotent = elf_x86_64_local_tlsdesc_gotent (ibfd); + local_tls_type = elf_x86_local_got_tls_type (ibfd); + local_tlsdesc_gotent = elf_x86_local_tlsdesc_gotent (ibfd); s = htab->elf.sgot; srel = htab->elf.srelgot; for (; local_got < end_local_got; @@ -3862,16 +3458,16 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, } } - if (htab->tls_ld_got.refcount > 0) + if (htab->tls_ld_or_ldm_got.refcount > 0) { /* Allocate 2 got entries and 1 dynamic reloc for R_X86_64_TLSLD relocs. */ - htab->tls_ld_got.offset = htab->elf.sgot->size; + htab->tls_ld_or_ldm_got.offset = htab->elf.sgot->size; htab->elf.sgot->size += 2 * GOT_ENTRY_SIZE; htab->elf.srelgot->size += bed->s->sizeof_rela; } else - htab->tls_ld_got.offset = -1; + htab->tls_ld_or_ldm_got.offset = -1; /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ @@ -3913,9 +3509,9 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, /* Reserve room for the initial entry. FIXME: we could probably do away with it in this case. */ if (htab->elf.splt->size == 0) - htab->elf.splt->size = htab->plt.plt_entry_size; + htab->elf.splt->size = plt_layout->plt_entry_size; htab->tlsdesc_plt = htab->elf.splt->size; - htab->elf.splt->size += htab->plt.plt_entry_size; + htab->elf.splt->size += plt_layout->plt_entry_size; } } @@ -3944,14 +3540,14 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && htab->elf.splt != NULL && htab->elf.splt->size != 0 && !bfd_is_abs_section (htab->elf.splt->output_section)) - htab->plt_eh_frame->size = htab->plt.eh_frame_plt_size; + htab->plt_eh_frame->size = plt_layout->eh_frame_plt_size; if (htab->plt_got_eh_frame != NULL && htab->plt_got != NULL && htab->plt_got->size != 0 && !bfd_is_abs_section (htab->plt_got->output_section)) htab->plt_got_eh_frame->size - = htab->non_lazy_plt->eh_frame_plt_size; + = non_lazy_plt_layout->eh_frame_plt_size; /* Unwind info for the second PLT and .plt.got sections are identical. */ @@ -3960,7 +3556,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && htab->plt_second->size != 0 && !bfd_is_abs_section (htab->plt_second->output_section)) htab->plt_second_eh_frame->size - = htab->non_lazy_plt->eh_frame_plt_size; + = non_lazy_plt_layout->eh_frame_plt_size; } /* We now have determined the sizes of the various dynamic sections. @@ -4036,7 +3632,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && htab->plt_eh_frame->contents != NULL) { memcpy (htab->plt_eh_frame->contents, - htab->plt.eh_frame_plt, htab->plt_eh_frame->size); + plt_layout->eh_frame_plt, htab->plt_eh_frame->size); bfd_put_32 (dynobj, htab->elf.splt->size, htab->plt_eh_frame->contents + PLT_FDE_LEN_OFFSET); } @@ -4045,7 +3641,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && htab->plt_got_eh_frame->contents != NULL) { memcpy (htab->plt_got_eh_frame->contents, - htab->non_lazy_plt->eh_frame_plt, + non_lazy_plt_layout->eh_frame_plt, htab->plt_got_eh_frame->size); bfd_put_32 (dynobj, htab->plt_got->size, (htab->plt_got_eh_frame->contents @@ -4056,7 +3652,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, && htab->plt_second_eh_frame->contents != NULL) { memcpy (htab->plt_second_eh_frame->contents, - htab->non_lazy_plt->eh_frame_plt, + non_lazy_plt_layout->eh_frame_plt, htab->plt_second_eh_frame->size); bfd_put_32 (dynobj, htab->plt_second->size, (htab->plt_second_eh_frame->contents @@ -4111,7 +3707,7 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) elf_link_hash_traverse (&htab->elf, - elf_x86_64_readonly_dynrelocs, + _bfd_x86_elf_readonly_dynrelocs, info); if ((info->flags & DF_TEXTREL) != 0) @@ -4134,88 +3730,6 @@ elf_x86_64_size_dynamic_sections (bfd *output_bfd, return TRUE; } -static bfd_boolean -elf_x86_64_always_size_sections (bfd *output_bfd, - struct bfd_link_info *info) -{ - asection *tls_sec = elf_hash_table (info)->tls_sec; - - if (tls_sec) - { - struct elf_link_hash_entry *tlsbase; - - tlsbase = elf_link_hash_lookup (elf_hash_table (info), - "_TLS_MODULE_BASE_", - FALSE, FALSE, FALSE); - - if (tlsbase && tlsbase->type == STT_TLS) - { - struct elf_x86_64_link_hash_table *htab; - struct bfd_link_hash_entry *bh = NULL; - const struct elf_backend_data *bed - = get_elf_backend_data (output_bfd); - - htab = elf_x86_64_hash_table (info); - if (htab == NULL) - return FALSE; - - if (!(_bfd_generic_link_add_one_symbol - (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, - tls_sec, 0, NULL, FALSE, - bed->collect, &bh))) - return FALSE; - - htab->tls_module_base = bh; - - tlsbase = (struct elf_link_hash_entry *)bh; - tlsbase->def_regular = 1; - tlsbase->other = STV_HIDDEN; - tlsbase->root.linker_def = 1; - (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); - } - } - - return TRUE; -} - -/* _TLS_MODULE_BASE_ needs to be treated especially when linking - executables. Rather than setting it to the beginning of the TLS - section, we have to set it to the end. This function may be called - multiple times, it is idempotent. */ - -static void -elf_x86_64_set_tls_module_base (struct bfd_link_info *info) -{ - struct elf_x86_64_link_hash_table *htab; - struct bfd_link_hash_entry *base; - - if (!bfd_link_executable (info)) - return; - - htab = elf_x86_64_hash_table (info); - if (htab == NULL) - return; - - base = htab->tls_module_base; - if (base == NULL) - return; - - base->u.def.value = htab->elf.tls_size; -} - -/* Return the base VMA address which should be subtracted from real addresses - when resolving @dtpoff relocation. - This is PT_TLS segment p_vaddr. */ - -static bfd_vma -elf_x86_64_dtpoff_base (struct bfd_link_info *info) -{ - /* If tls_sec is NULL, we should have signalled an error already. */ - if (elf_hash_table (info)->tls_sec == NULL) - return 0; - return elf_hash_table (info)->tls_sec->vma; -} - /* Return the relocation value for @tpoff relocation if STT_TLS virtual address is ADDRESS. */ @@ -4265,7 +3779,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, Elf_Internal_Sym *local_syms, asection **local_sections) { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_vma *local_got_offsets; @@ -4281,16 +3795,16 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (input_section->check_relocs_failed) return FALSE; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return FALSE; - plt_entry_size = htab->plt.plt_entry_size; + plt_entry_size = elf_x86_64_plt (htab).plt_entry_size; symtab_hdr = &elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); - local_tlsdesc_gotents = elf_x86_64_local_tlsdesc_gotent (input_bfd); + local_tlsdesc_gotents = elf_x86_local_tlsdesc_gotent (input_bfd); - elf_x86_64_set_tls_module_base (info); + _bfd_x86_elf_set_tls_module_base (info); rel = wrel = relocs; relend = relocs + input_section->reloc_count; @@ -4300,7 +3814,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, reloc_howto_type *howto; unsigned long r_symndx; struct elf_link_hash_entry *h; - struct elf_x86_64_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; Elf_Internal_Sym *sym; asection *sec; bfd_vma off, offplt, plt_offset; @@ -4349,8 +3863,8 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (!bfd_link_relocatable (info) && ELF_ST_TYPE (sym->st_info) == STT_GNU_IFUNC) { - h = elf_x86_64_get_local_sym_hash (htab, input_bfd, - rel, FALSE); + h = _bfd_elf_x86_get_local_sym_hash (htab, input_bfd, + rel, FALSE); if (h == NULL) abort (); @@ -4414,7 +3928,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, } } - eh = (struct elf_x86_64_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; /* Since STT_GNU_IFUNC symbol must go through PLT, we handle it here if it is defined in a non-shared object. */ @@ -4462,7 +3976,7 @@ elf_x86_64_relocate_section (bfd *output_bfd, if (htab->elf.splt != NULL) { plt_index = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0); + - elf_x86_64_plt (htab).has_plt0); off = (plt_index + 3) * GOT_ENTRY_SIZE; base_got = htab->elf.sgotplt; } @@ -4654,6 +4168,7 @@ do_ifunc_pointer: resolved_to_zero = (eh != NULL && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + X86_64_ELF_DATA, eh->has_got_reloc, eh)); @@ -4692,7 +4207,7 @@ do_ifunc_pointer: finish_dynamic_symbol would use that as offset into .got. */ bfd_vma plt_index = (h->plt.offset / plt_entry_size - - htab->plt.has_plt0); + - elf_x86_64_plt (htab).has_plt0); off = (plt_index + 3) * GOT_ENTRY_SIZE; base_got = htab->elf.sgotplt; } @@ -5193,9 +4708,9 @@ direct: case R_X86_64_GOTTPOFF: tls_type = GOT_UNKNOWN; if (h == NULL && local_got_offsets) - tls_type = elf_x86_64_local_got_tls_type (input_bfd) [r_symndx]; + tls_type = elf_x86_local_got_tls_type (input_bfd) [r_symndx]; else if (h != NULL) - tls_type = elf_x86_64_hash_entry (h)->tls_type; + tls_type = elf_x86_hash_entry (h)->tls_type; if (! elf_x86_64_tls_transition (info, input_bfd, input_section, contents, @@ -5392,7 +4907,7 @@ direct: if (h != NULL) { off = h->got.offset; - offplt = elf_x86_64_hash_entry (h)->tlsdesc_got; + offplt = elf_x86_hash_entry (h)->tlsdesc_got; } else { @@ -5427,7 +4942,7 @@ direct: + htab->sgotplt_jump_table_size); sreloc = htab->elf.srelplt; if (indx == 0) - outrel.r_addend = relocation - elf_x86_64_dtpoff_base (info); + outrel.r_addend = relocation - _bfd_x86_elf_dtpoff_base (info); else outrel.r_addend = 0; elf_append_rela (output_bfd, sreloc, &outrel); @@ -5449,7 +4964,7 @@ direct: outrel.r_addend = 0; if ((dr_type == R_X86_64_TPOFF64 || dr_type == R_X86_64_TLSDESC) && indx == 0) - outrel.r_addend = relocation - elf_x86_64_dtpoff_base (info); + outrel.r_addend = relocation - _bfd_x86_elf_dtpoff_base (info); outrel.r_info = htab->r_info (indx, dr_type); elf_append_rela (output_bfd, sreloc, &outrel); @@ -5460,7 +4975,7 @@ direct: { BFD_ASSERT (! unresolved_reloc); bfd_put_64 (output_bfd, - relocation - elf_x86_64_dtpoff_base (info), + relocation - _bfd_x86_elf_dtpoff_base (info), htab->elf.sgot->contents + off + GOT_ENTRY_SIZE); } else @@ -5684,7 +5199,7 @@ direct: if (htab->elf.sgot == NULL) abort (); - off = htab->tls_ld_got.offset; + off = htab->tls_ld_or_ldm_got.offset; if (off & 1) off &= ~1; else @@ -5705,7 +5220,7 @@ direct: outrel.r_addend = 0; elf_append_rela (output_bfd, htab->elf.srelgot, &outrel); - htab->tls_ld_got.offset |= 1; + htab->tls_ld_or_ldm_got.offset |= 1; } relocation = htab->elf.sgot->output_section->vma + htab->elf.sgot->output_offset + off; @@ -5715,7 +5230,7 @@ direct: case R_X86_64_DTPOFF32: if (!bfd_link_executable (info) || (input_section->flags & SEC_CODE) == 0) - relocation -= elf_x86_64_dtpoff_base (info); + relocation -= _bfd_x86_elf_dtpoff_base (info); else relocation = elf_x86_64_tpoff (info, relocation); break; @@ -5728,7 +5243,7 @@ direct: case R_X86_64_DTPOFF64: BFD_ASSERT ((input_section->flags & SEC_CODE) == 0); - relocation -= elf_x86_64_dtpoff_base (info); + relocation -= _bfd_x86_elf_dtpoff_base (info); break; default: @@ -5843,26 +5358,34 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd_boolean use_plt_second; - struct elf_x86_64_link_hash_entry *eh; + struct elf_x86_link_hash_entry *eh; bfd_boolean local_undefweak; + const struct elf_x86_64_plt_layout *plt_layout; + const struct elf_x86_64_lazy_plt_layout *lazy_plt_layout; + const struct elf_x86_64_non_lazy_plt_layout *non_lazy_plt_layout; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return FALSE; /* Use the second PLT section only if there is .plt section. */ use_plt_second = htab->elf.splt != NULL && htab->plt_second != NULL; - eh = (struct elf_x86_64_link_hash_entry *) h; + eh = (struct elf_x86_link_hash_entry *) h; if (eh->no_finish_dynamic_symbol) abort (); + plt_layout = &elf_x86_64_plt (htab); + lazy_plt_layout = elf_x86_64_lazy_plt (htab); + non_lazy_plt_layout = elf_x86_64_non_lazy_plt (htab); + /* We keep PLT/GOT entries without dynamic PLT/GOT relocations for resolved undefined weak symbols in executable so that their references have value 0 at run-time. */ local_undefweak = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + X86_64_ELF_DATA, eh->has_got_reloc, eh); @@ -5916,24 +5439,24 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, if (plt == htab->elf.splt) { - got_offset = (h->plt.offset / htab->plt.plt_entry_size - - htab->plt.has_plt0); + got_offset = (h->plt.offset / plt_layout->plt_entry_size + - plt_layout->has_plt0); got_offset = (got_offset + 3) * GOT_ENTRY_SIZE; } else { - got_offset = h->plt.offset / htab->plt.plt_entry_size; + got_offset = h->plt.offset / plt_layout->plt_entry_size; got_offset = got_offset * GOT_ENTRY_SIZE; } /* Fill in the entry in the procedure linkage table. */ - memcpy (plt->contents + h->plt.offset, htab->plt.plt_entry, - htab->plt.plt_entry_size); + memcpy (plt->contents + h->plt.offset, plt_layout->plt_entry, + plt_layout->plt_entry_size); if (use_plt_second) { memcpy (htab->plt_second->contents + eh->plt_second.offset, - htab->non_lazy_plt->plt_entry, - htab->non_lazy_plt->plt_entry_size); + non_lazy_plt_layout->plt_entry, + non_lazy_plt_layout->plt_entry_size); resolved_plt = htab->plt_second; plt_offset = eh->plt_second.offset; @@ -5954,7 +5477,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, - resolved_plt->output_section->vma - resolved_plt->output_offset - plt_offset - - htab->plt.plt_got_insn_size); + - plt_layout->plt_got_insn_size); /* Check PC-relative offset overflow in PLT entry. */ if ((plt_got_pcrel_offset + 0x80000000) > 0xffffffff) @@ -5964,7 +5487,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, bfd_put_32 (output_bfd, plt_got_pcrel_offset, (resolved_plt->contents + plt_offset - + htab->plt.plt_got_offset)); + + plt_layout->plt_got_offset)); /* Fill in the entry in the global offset table, initially this points to the second part of the PLT entry. Leave the entry @@ -5972,11 +5495,11 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, against undefined weak symbol in PIE. */ if (!local_undefweak) { - if (htab->plt.has_plt0) + if (plt_layout->has_plt0) bfd_put_64 (output_bfd, (plt->output_section->vma + plt->output_offset + h->plt.offset - + htab->lazy_plt->plt_lazy_offset), + + lazy_plt_layout->plt_lazy_offset), gotplt->contents + got_offset); /* Fill in the entry in the .rela.plt section. */ @@ -6011,15 +5534,15 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, /* Don't fill the second and third slots in PLT entry for static executables nor without PLT0. */ - if (plt == htab->elf.splt && htab->plt.has_plt0) + if (plt == htab->elf.splt && plt_layout->has_plt0) { bfd_vma plt0_offset - = h->plt.offset + htab->lazy_plt->plt_plt_insn_end; + = h->plt.offset + lazy_plt_layout->plt_plt_insn_end; /* Put relocation index. */ bfd_put_32 (output_bfd, plt_index, (plt->contents + h->plt.offset - + htab->lazy_plt->plt_reloc_offset)); + + lazy_plt_layout->plt_reloc_offset)); /* Put offset for jmp .PLT0 and check for overflow. We don't check relocation index for overflow since branch displacement @@ -6030,7 +5553,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, output_bfd, h->root.root.string); bfd_put_32 (output_bfd, - plt0_offset, (plt->contents + h->plt.offset - + htab->lazy_plt->plt_plt_offset)); + + lazy_plt_layout->plt_plt_offset)); } bed = get_elf_backend_data (output_bfd); @@ -6061,8 +5584,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, /* Fill in the entry in the GOT procedure linkage table. */ plt_offset = eh->plt_got.offset; memcpy (plt->contents + plt_offset, - htab->non_lazy_plt->plt_entry, - htab->non_lazy_plt->plt_entry_size); + non_lazy_plt_layout->plt_entry, + non_lazy_plt_layout->plt_entry_size); /* Put offset the PC-relative instruction referring to the GOT entry, subtracting the size of that instruction. */ @@ -6072,7 +5595,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, - plt->output_section->vma - plt->output_offset - plt_offset - - htab->non_lazy_plt->plt_got_insn_size); + - non_lazy_plt_layout->plt_got_insn_size); /* Check PC-relative offset overflow in GOT PLT entry. */ got_after_plt = got->output_section->vma > plt->output_section->vma; @@ -6084,7 +5607,7 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, bfd_put_32 (output_bfd, got_pcrel_offset, (plt->contents + plt_offset - + htab->non_lazy_plt->plt_got_offset)); + + non_lazy_plt_layout->plt_got_offset)); } if (!local_undefweak @@ -6108,8 +5631,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, /* Don't generate dynamic GOT relocation against undefined weak symbol in executable. */ if (h->got.offset != (bfd_vma) -1 - && ! GOT_TLS_GD_ANY_P (elf_x86_64_hash_entry (h)->tls_type) - && elf_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE + && ! GOT_TLS_GD_ANY_P (elf_x86_hash_entry (h)->tls_type) + && elf_x86_hash_entry (h)->tls_type != GOT_TLS_IE && !local_undefweak) { Elf_Internal_Rela rela; @@ -6287,7 +5810,8 @@ elf_x86_64_reloc_type_class (const struct bfd_link_info *info, { bfd *abfd = info->output_bfd; const struct elf_backend_data *bed = get_elf_backend_data (abfd); - struct elf_x86_64_link_hash_table *htab = elf_x86_64_hash_table (info); + struct elf_x86_link_hash_table *htab + = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab->elf.dynsym != NULL && htab->elf.dynsym->contents != NULL) @@ -6331,11 +5855,11 @@ static bfd_boolean elf_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) { - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd *dynobj; asection *sdyn; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return FALSE; @@ -6347,6 +5871,9 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, bfd_byte *dyncon, *dynconend; const struct elf_backend_data *bed; bfd_size_type sizeof_dyn; + const struct elf_x86_64_plt_layout *plt_layout; + const struct elf_x86_64_lazy_plt_layout *lazy_plt_layout; + const struct elf_x86_64_non_lazy_plt_layout *non_lazy_plt_layout; if (sdyn == NULL || htab->elf.sgot == NULL) abort (); @@ -6397,18 +5924,22 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, (*bed->s->swap_dyn_out) (output_bfd, &dyn, dyncon); } + plt_layout = &elf_x86_64_plt (htab); + lazy_plt_layout = elf_x86_64_lazy_plt (htab); + non_lazy_plt_layout = elf_x86_64_non_lazy_plt (htab); + if (htab->elf.splt && htab->elf.splt->size > 0) { elf_section_data (htab->elf.splt->output_section) - ->this_hdr.sh_entsize = htab->plt.plt_entry_size; + ->this_hdr.sh_entsize = plt_layout->plt_entry_size; - if (htab->plt.has_plt0) + if (plt_layout->has_plt0) { /* Fill in the special first entry in the procedure linkage table. */ memcpy (htab->elf.splt->contents, - htab->lazy_plt->plt0_entry, - htab->lazy_plt->plt_entry_size); + lazy_plt_layout->plt0_entry, + lazy_plt_layout->plt_entry_size); /* Add offset for pushq GOT+8(%rip), since the instruction uses 6 bytes subtract this value. */ bfd_put_32 (output_bfd, @@ -6419,7 +5950,7 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - htab->elf.splt->output_offset - 6), (htab->elf.splt->contents - + htab->lazy_plt->plt0_got1_offset)); + + lazy_plt_layout->plt0_got1_offset)); /* Add offset for the PC-relative instruction accessing GOT+16, subtracting the offset to the end of that instruction. */ @@ -6429,9 +5960,9 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, + 16 - htab->elf.splt->output_section->vma - htab->elf.splt->output_offset - - htab->lazy_plt->plt0_got2_insn_end), + - lazy_plt_layout->plt0_got2_insn_end), (htab->elf.splt->contents - + htab->lazy_plt->plt0_got2_offset)); + + lazy_plt_layout->plt0_got2_offset)); if (htab->tlsdesc_plt) { @@ -6439,8 +5970,8 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, htab->elf.sgot->contents + htab->tlsdesc_got); memcpy (htab->elf.splt->contents + htab->tlsdesc_plt, - htab->lazy_plt->plt0_entry, - htab->lazy_plt->plt_entry_size); + lazy_plt_layout->plt0_entry, + lazy_plt_layout->plt_entry_size); /* Add offset for pushq GOT+8(%rip), since the instruction uses 6 bytes subtract this value. */ @@ -6454,7 +5985,7 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - 6), (htab->elf.splt->contents + htab->tlsdesc_plt - + htab->lazy_plt->plt0_got1_offset)); + + lazy_plt_layout->plt0_got1_offset)); /* Add offset for the PC-relative instruction accessing GOT+TDG, where TDG stands for htab->tlsdesc_got, subtracting the offset to the end of that @@ -6466,22 +5997,22 @@ elf_x86_64_finish_dynamic_sections (bfd *output_bfd, - htab->elf.splt->output_section->vma - htab->elf.splt->output_offset - htab->tlsdesc_plt - - htab->lazy_plt->plt0_got2_insn_end), + - lazy_plt_layout->plt0_got2_insn_end), (htab->elf.splt->contents + htab->tlsdesc_plt - + htab->lazy_plt->plt0_got2_offset)); + + lazy_plt_layout->plt0_got2_offset)); } } } - } - if (htab->plt_got != NULL && htab->plt_got->size > 0) - elf_section_data (htab->plt_got->output_section) - ->this_hdr.sh_entsize = htab->non_lazy_plt->plt_entry_size; + if (htab->plt_got != NULL && htab->plt_got->size > 0) + elf_section_data (htab->plt_got->output_section) + ->this_hdr.sh_entsize = non_lazy_plt_layout->plt_entry_size; - if (htab->plt_second != NULL && htab->plt_second->size > 0) - elf_section_data (htab->plt_second->output_section) - ->this_hdr.sh_entsize = htab->non_lazy_plt->plt_entry_size; + if (htab->plt_second != NULL && htab->plt_second->size > 0) + elf_section_data (htab->plt_second->output_section) + ->this_hdr.sh_entsize = non_lazy_plt_layout->plt_entry_size; + } /* GOT is always created in setup_gnu_properties. But it may not be needed. */ @@ -6623,7 +6154,8 @@ elf_x86_64_output_arch_local_syms asection *, struct elf_link_hash_entry *) ATTRIBUTE_UNUSED) { - struct elf_x86_64_link_hash_table *htab = elf_x86_64_hash_table (info); + struct elf_x86_link_hash_table *htab + = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return FALSE; @@ -6635,22 +6167,6 @@ elf_x86_64_output_arch_local_syms return TRUE; } -/* Sort relocs into address order. */ - -static int -compare_relocs (const void *ap, const void *bp) -{ - const arelent *a = * (const arelent **) ap; - const arelent *b = * (const arelent **) bp; - - if (a->address > b->address) - return 1; - else if (a->address < b->address) - return -1; - else - return 0; -} - enum elf_x86_64_plt_type { plt_non_lazy = 0, @@ -6880,7 +6396,8 @@ elf_x86_64_get_synthetic_symtab (bfd *abfd, dynsyms); /* Sort the relocs by address. */ - qsort (dynrelbuf, dynrelcount, sizeof (arelent *), compare_relocs); + qsort (dynrelbuf, dynrelcount, sizeof (arelent *), + _bfd_x86_elf_compare_relocs); size = count * sizeof (asymbol); @@ -7170,21 +6687,6 @@ elf_x86_64_merge_symbol (struct elf_link_hash_entry *h, return TRUE; } -static void -elf_x86_64_merge_symbol_attribute (struct elf_link_hash_entry *h, - const Elf_Internal_Sym *isym, - bfd_boolean definition, - bfd_boolean dynamic ATTRIBUTE_UNUSED) -{ - if (definition) - { - struct elf_x86_64_link_hash_entry *eh - = (struct elf_x86_64_link_hash_entry *) h; - eh->def_protected = (ELF_ST_VISIBILITY (isym->st_other) - == STV_PROTECTED); - } -} - static int elf_x86_64_additional_program_headers (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED) @@ -7207,19 +6709,6 @@ elf_x86_64_additional_program_headers (bfd *abfd, return count; } -/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ - -static bfd_boolean -elf_x86_64_hash_symbol (struct elf_link_hash_entry *h) -{ - if (h->plt.offset != (bfd_vma) -1 - && !h->def_regular - && !h->pointer_equality_needed) - return FALSE; - - return _bfd_elf_hash_symbol (h); -} - /* Return TRUE iff relocations for INPUT are compatible with OUTPUT. */ static bfd_boolean @@ -7231,136 +6720,6 @@ elf_x86_64_relocs_compatible (const bfd_target *input, && _bfd_elf_relocs_compatible (input, output)); } -/* Parse x86-64 GNU properties. */ - -static enum elf_property_kind -elf_x86_64_parse_gnu_properties (bfd *abfd, unsigned int type, - bfd_byte *ptr, unsigned int datasz) -{ - elf_property *prop; - - switch (type) - { - case GNU_PROPERTY_X86_ISA_1_USED: - case GNU_PROPERTY_X86_ISA_1_NEEDED: - case GNU_PROPERTY_X86_FEATURE_1_AND: - if (datasz != 4) - { - _bfd_error_handler - ((type == GNU_PROPERTY_X86_ISA_1_USED - ? _("error: %B: <corrupt x86 ISA used size: 0x%x>") - : (type == GNU_PROPERTY_X86_ISA_1_NEEDED - ? _("error: %B: <corrupt x86 ISA needed size: 0x%x>") - : _("error: %B: <corrupt x86 feature size: 0x%x>"))), - abfd, datasz); - return property_corrupt; - } - prop = _bfd_elf_get_property (abfd, type, datasz); - /* Combine properties of the same type. */ - prop->u.number |= bfd_h_get_32 (abfd, ptr); - prop->pr_kind = property_number; - break; - - default: - return property_ignored; - } - - return property_number; -} - -/* Merge x86-64 GNU property BPROP with APROP. If APROP isn't NULL, - return TRUE if APROP is updated. Otherwise, return TRUE if BPROP - should be merged with ABFD. */ - -static bfd_boolean -elf_x86_64_merge_gnu_properties (struct bfd_link_info *info, - bfd *abfd ATTRIBUTE_UNUSED, - elf_property *aprop, - elf_property *bprop) -{ - unsigned int number, features; - bfd_boolean updated = FALSE; - unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; - - switch (pr_type) - { - case GNU_PROPERTY_X86_ISA_1_USED: - case GNU_PROPERTY_X86_ISA_1_NEEDED: - if (aprop != NULL && bprop != NULL) - { - number = aprop->u.number; - aprop->u.number = number | bprop->u.number; - updated = number != (unsigned int) aprop->u.number; - } - else - { - /* Return TRUE if APROP is NULL to indicate that BPROP should - be added to ABFD. */ - updated = aprop == NULL; - } - break; - - case GNU_PROPERTY_X86_FEATURE_1_AND: - /* Only one of APROP and BPROP can be NULL: - 1. APROP & BPROP when both APROP and BPROP aren't NULL. - 2. If APROP is NULL, remove x86 feature. - 3. Otherwise, do nothing. - */ - if (aprop != NULL && bprop != NULL) - { - features = 0; - if (info->ibt) - features = GNU_PROPERTY_X86_FEATURE_1_IBT; - if (info->shstk) - features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; - number = aprop->u.number; - /* Add GNU_PROPERTY_X86_FEATURE_1_IBT and - GNU_PROPERTY_X86_FEATURE_1_SHSTK. */ - aprop->u.number = (number & bprop->u.number) | features; - updated = number != (unsigned int) aprop->u.number; - /* Remove the property if all feature bits are cleared. */ - if (aprop->u.number == 0) - aprop->pr_kind = property_remove; - } - else - { - features = 0; - if (info->ibt) - features = GNU_PROPERTY_X86_FEATURE_1_IBT; - if (info->shstk) - features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; - if (features) - { - /* Add GNU_PROPERTY_X86_FEATURE_1_IBT and - GNU_PROPERTY_X86_FEATURE_1_SHSTK. */ - if (aprop != NULL) - { - number = aprop->u.number; - aprop->u.number = number | features; - updated = number != (unsigned int) aprop->u.number; - } - else - { - bprop->u.number |= features; - updated = TRUE; - } - } - else if (aprop != NULL) - { - aprop->pr_kind = property_remove; - updated = TRUE; - } - } - break; - - default: - /* Never should happen. */ - abort (); - } - - return updated; -} - /* Set up x86-64 GNU properties. Return the first relocatable ELF input with GNU properties if found. Otherwise, return NULL. */ @@ -7373,10 +6732,13 @@ elf_x86_64_link_setup_gnu_properties (struct bfd_link_info *info) bfd *dynobj; bfd_boolean use_ibt_plt; unsigned int plt_alignment, features; - struct elf_x86_64_link_hash_table *htab; + struct elf_x86_link_hash_table *htab; bfd *pbfd; bfd *ebfd = NULL; elf_property *prop; + struct elf_x86_64_plt_layout *plt_layout; + const struct elf_x86_64_lazy_plt_layout *lazy_plt_layout; + const struct elf_x86_64_non_lazy_plt_layout *non_lazy_plt_layout; features = 0; if (info->ibt) @@ -7438,7 +6800,7 @@ error_alignment: if (bfd_link_relocatable (info)) return pbfd; - htab = elf_x86_64_hash_table (info); + htab = elf_x86_hash_table (info, X86_64_ELF_DATA); if (htab == NULL) return pbfd; @@ -7493,10 +6855,12 @@ error_alignment: } } + plt_layout = &elf_x86_64_plt (htab); + /* Even when lazy binding is disabled by "-z now", the PLT0 entry may still be used with LD_AUDIT or LD_PROFILE if PLT entry is used for canonical function address. */ - htab->plt.has_plt0 = 1; + plt_layout->has_plt0 = 1; if (get_elf_x86_64_backend_data (info->output_bfd)->os == is_normal) @@ -7505,70 +6869,77 @@ error_alignment: { if (ABI_64_P (dynobj)) { - htab->lazy_plt = &elf_x86_64_lazy_ibt_plt; - htab->non_lazy_plt = &elf_x86_64_non_lazy_ibt_plt; + elf_x86_64_lazy_plt (htab) + = &elf_x86_64_lazy_ibt_plt; + elf_x86_64_non_lazy_plt (htab) + = &elf_x86_64_non_lazy_ibt_plt; } else { - htab->lazy_plt = &elf_x32_lazy_ibt_plt; - htab->non_lazy_plt = &elf_x32_non_lazy_ibt_plt; + elf_x86_64_lazy_plt (htab) + = &elf_x32_lazy_ibt_plt; + elf_x86_64_non_lazy_plt (htab) + = &elf_x32_non_lazy_ibt_plt; } } else if (info->bndplt) { - htab->lazy_plt = &elf_x86_64_lazy_bnd_plt; - htab->non_lazy_plt = &elf_x86_64_non_lazy_bnd_plt; + elf_x86_64_lazy_plt (htab) = &elf_x86_64_lazy_bnd_plt; + elf_x86_64_non_lazy_plt (htab) = &elf_x86_64_non_lazy_bnd_plt; } else { - htab->lazy_plt = &elf_x86_64_lazy_plt; - htab->non_lazy_plt = &elf_x86_64_non_lazy_plt; + elf_x86_64_lazy_plt (htab) = &elf_x86_64_lazy_plt; + elf_x86_64_non_lazy_plt (htab) = &elf_x86_64_non_lazy_plt; } normal_target = TRUE; } else { - htab->lazy_plt = &elf_x86_64_nacl_plt; - htab->non_lazy_plt = NULL; + elf_x86_64_lazy_plt (htab) = &elf_x86_64_nacl_plt; + elf_x86_64_non_lazy_plt (htab) = NULL; normal_target = FALSE; } + lazy_plt_layout = elf_x86_64_lazy_plt (htab); + non_lazy_plt_layout = elf_x86_64_non_lazy_plt (htab); + pltsec = htab->elf.splt; /* If the non-lazy PLT is available, use it for all PLT entries if there are no PLT0 or no .plt section. */ - if (htab->non_lazy_plt != NULL - && (!htab->plt.has_plt0 || pltsec == NULL)) + if (non_lazy_plt_layout != NULL + && (!plt_layout->has_plt0 || pltsec == NULL)) { lazy_plt = FALSE; - htab->plt.plt_entry - = htab->non_lazy_plt->plt_entry; - htab->plt.plt_entry_size - = htab->non_lazy_plt->plt_entry_size; - htab->plt.plt_got_offset - = htab->non_lazy_plt->plt_got_offset; - htab->plt.plt_got_insn_size - = htab->non_lazy_plt->plt_got_insn_size; - htab->plt.eh_frame_plt_size - = htab->non_lazy_plt->eh_frame_plt_size; - htab->plt.eh_frame_plt - = htab->non_lazy_plt->eh_frame_plt; + plt_layout->plt_entry + = non_lazy_plt_layout->plt_entry; + plt_layout->plt_entry_size + = non_lazy_plt_layout->plt_entry_size; + plt_layout->plt_got_offset + = non_lazy_plt_layout->plt_got_offset; + plt_layout->plt_got_insn_size + = non_lazy_plt_layout->plt_got_insn_size; + plt_layout->eh_frame_plt_size + = non_lazy_plt_layout->eh_frame_plt_size; + plt_layout->eh_frame_plt + = non_lazy_plt_layout->eh_frame_plt; } else { lazy_plt = TRUE; - htab->plt.plt_entry - = htab->lazy_plt->plt_entry; - htab->plt.plt_entry_size - = htab->lazy_plt->plt_entry_size; - htab->plt.plt_got_offset - = htab->lazy_plt->plt_got_offset; - htab->plt.plt_got_insn_size - = htab->lazy_plt->plt_got_insn_size; - htab->plt.eh_frame_plt_size - = htab->lazy_plt->eh_frame_plt_size; - htab->plt.eh_frame_plt - = htab->lazy_plt->eh_frame_plt; + plt_layout->plt_entry + = lazy_plt_layout->plt_entry; + plt_layout->plt_entry_size + = lazy_plt_layout->plt_entry_size; + plt_layout->plt_got_offset + = lazy_plt_layout->plt_got_offset; + plt_layout->plt_got_insn_size + = lazy_plt_layout->plt_got_insn_size; + plt_layout->eh_frame_plt_size + = lazy_plt_layout->eh_frame_plt_size; + plt_layout->eh_frame_plt + = lazy_plt_layout->eh_frame_plt; } /* Return if there are no normal input files. */ @@ -7598,7 +6969,7 @@ error_alignment: if (!_bfd_elf_create_ifunc_sections (dynobj, info)) info->callbacks->einfo (_("%F: failed to create ifunc sections\n")); - plt_alignment = bfd_log2 (htab->plt.plt_entry_size); + plt_alignment = bfd_log2 (plt_layout->plt_entry_size); if (pltsec != NULL) { @@ -7627,7 +6998,7 @@ error_alignment: | SEC_LOAD | SEC_READONLY); unsigned int non_lazy_plt_alignment - = bfd_log2 (htab->non_lazy_plt->plt_entry_size); + = bfd_log2 (non_lazy_plt_layout->plt_entry_size); sec = pltsec; if (!bfd_set_section_alignment (sec->owner, sec, @@ -7749,23 +7120,6 @@ error_alignment: return pbfd; } -static bfd_boolean -elf_x86_64_link_check_relocs (bfd *abfd, struct bfd_link_info *info) -{ - if (!bfd_link_relocatable (info)) - { - /* Check for __tls_get_addr reference. */ - struct elf_link_hash_entry *h; - h = elf_link_hash_lookup (elf_hash_table (info), "__tls_get_addr", - FALSE, FALSE, FALSE); - if (h != NULL) - ((struct elf_x86_64_link_hash_entry *) h)->tls_get_addr = 1; - } - - /* Invoke the regular ELF backend linker to do all the work. */ - return _bfd_elf_link_check_relocs (abfd, info); -} - static const struct bfd_elf_special_section elf_x86_64_special_sections[]= { @@ -7811,7 +7165,6 @@ elf_x86_64_special_sections[]= #define elf_backend_adjust_dynamic_symbol elf_x86_64_adjust_dynamic_symbol #define elf_backend_relocs_compatible elf_x86_64_relocs_compatible #define elf_backend_check_relocs elf_x86_64_check_relocs -#define elf_backend_copy_indirect_symbol elf_x86_64_copy_indirect_symbol #define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections #define elf_backend_finish_dynamic_sections elf_x86_64_finish_dynamic_sections #define elf_backend_finish_dynamic_symbol elf_x86_64_finish_dynamic_symbol @@ -7825,12 +7178,10 @@ elf_x86_64_special_sections[]= #define elf_backend_reloc_type_class elf_x86_64_reloc_type_class #define elf_backend_relocate_section elf_x86_64_relocate_section #define elf_backend_size_dynamic_sections elf_x86_64_size_dynamic_sections -#define elf_backend_always_size_sections elf_x86_64_always_size_sections #define elf_backend_init_index_section _bfd_elf_init_1_index_section #define elf_backend_object_p elf64_x86_64_elf_object_p #define bfd_elf64_mkobject elf_x86_64_mkobject #define bfd_elf64_get_synthetic_symtab elf_x86_64_get_synthetic_symtab -#define bfd_elf64_bfd_link_check_relocs elf_x86_64_link_check_relocs #define elf_backend_section_from_shdr \ elf_x86_64_section_from_shdr @@ -7849,22 +7200,10 @@ elf_x86_64_special_sections[]= elf_x86_64_common_definition #define elf_backend_merge_symbol \ elf_x86_64_merge_symbol -#define elf_backend_merge_symbol_attribute \ - elf_x86_64_merge_symbol_attribute #define elf_backend_special_sections \ elf_x86_64_special_sections #define elf_backend_additional_program_headers \ elf_x86_64_additional_program_headers -#define elf_backend_hash_symbol \ - elf_x86_64_hash_symbol -#define elf_backend_omit_section_dynsym \ - ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) -#define elf_backend_fixup_symbol \ - elf_x86_64_fixup_symbol -#define elf_backend_parse_gnu_properties \ - elf_x86_64_parse_gnu_properties -#define elf_backend_merge_gnu_properties \ - elf_x86_64_merge_gnu_properties #define elf_backend_setup_gnu_properties \ elf_x86_64_link_setup_gnu_properties @@ -8132,8 +7471,6 @@ elf32_x86_64_nacl_elf_object_p (bfd *abfd) elf_x86_64_mkobject #define bfd_elf32_get_synthetic_symtab \ elf_x86_64_get_synthetic_symtab -#define bfd_elf32_bfd_link_check_relocs \ - elf_x86_64_link_check_relocs #undef elf_backend_object_p #define elf_backend_object_p \ diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c new file mode 100644 index 0000000..1c8380d --- /dev/null +++ b/bfd/elfxx-x86.c @@ -0,0 +1,580 @@ +/* x86 specific support for ELF + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "elfxx-x86.h" + +/* _TLS_MODULE_BASE_ needs to be treated especially when linking + executables. Rather than setting it to the beginning of the TLS + section, we have to set it to the end. This function may be called + multiple times, it is idempotent. */ + +void +_bfd_x86_elf_set_tls_module_base (struct bfd_link_info *info) +{ + struct elf_x86_link_hash_table *htab; + struct bfd_link_hash_entry *base; + const struct elf_backend_data *bed; + + if (!bfd_link_executable (info)) + return; + + bed = get_elf_backend_data (info->output_bfd); + htab = elf_x86_hash_table (info, bed->target_id); + if (htab == NULL) + return; + + base = htab->tls_module_base; + if (base == NULL) + return; + + base->u.def.value = htab->elf.tls_size; +} + +/* Return the base VMA address which should be subtracted from real addresses + when resolving @dtpoff relocation. + This is PT_TLS segment p_vaddr. */ + +bfd_vma +_bfd_x86_elf_dtpoff_base (struct bfd_link_info *info) +{ + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; +} + +/* Find any dynamic relocs that apply to read-only sections. */ + +bfd_boolean +_bfd_x86_elf_readonly_dynrelocs (struct elf_link_hash_entry *h, + void *inf) +{ + struct elf_x86_link_hash_entry *eh; + struct elf_dyn_relocs *p; + + /* Skip local IFUNC symbols. */ + if (h->forced_local && h->type == STT_GNU_IFUNC) + return TRUE; + + eh = (struct elf_x86_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + asection *s = p->sec->output_section; + + if (s != NULL && (s->flags & SEC_READONLY) != 0) + { + struct bfd_link_info *info = (struct bfd_link_info *) inf; + + info->flags |= DF_TEXTREL; + + if ((info->warn_shared_textrel && bfd_link_pic (info)) + || info->error_textrel) + /* xgettext:c-format */ + info->callbacks->einfo (_("%P: %B: warning: relocation against `%s' in readonly section `%A'\n"), + p->sec->owner, h->root.root.string, + p->sec); + + /* Not an error, just cut short the traversal. */ + return FALSE; + } + } + return TRUE; +} + +/* Find and/or create a hash entry for local symbol. */ + +struct elf_link_hash_entry * +_bfd_elf_x86_get_local_sym_hash (struct elf_x86_link_hash_table *htab, + bfd *abfd, const Elf_Internal_Rela *rel, + bfd_boolean create) +{ + struct elf_x86_link_hash_entry e, *ret; + asection *sec = abfd->sections; + hashval_t h = ELF_LOCAL_SYMBOL_HASH (sec->id, + htab->r_sym (rel->r_info)); + void **slot; + + e.elf.indx = sec->id; + e.elf.dynstr_index = htab->r_sym (rel->r_info); + slot = htab_find_slot_with_hash (htab->loc_hash_table, &e, h, + create ? INSERT : NO_INSERT); + + if (!slot) + return NULL; + + if (*slot) + { + ret = (struct elf_x86_link_hash_entry *) *slot; + return &ret->elf; + } + + ret = (struct elf_x86_link_hash_entry *) + objalloc_alloc ((struct objalloc *) htab->loc_hash_memory, + sizeof (struct elf_x86_link_hash_entry)); + if (ret) + { + memset (ret, 0, sizeof (*ret)); + ret->elf.indx = sec->id; + ret->elf.dynstr_index = htab->r_sym (rel->r_info); + ret->elf.dynindx = -1; + ret->plt_got.offset = (bfd_vma) -1; + *slot = ret; + } + return &ret->elf; +} + +/* Create an entry in a x86 ELF linker hash table. NB: THIS MUST BE IN + SYNC WITH _bfd_elf_link_hash_newfunc. */ + +struct bfd_hash_entry * +_bfd_x86_elf_link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) +{ + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (entry == NULL) + { + entry = (struct bfd_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct elf_x86_link_hash_entry)); + if (entry == NULL) + return entry; + } + + /* Call the allocation method of the superclass. */ + entry = _bfd_link_hash_newfunc (entry, table, string); + if (entry != NULL) + { + struct elf_x86_link_hash_entry *eh + = (struct elf_x86_link_hash_entry *) entry; + struct elf_link_hash_table *htab + = (struct elf_link_hash_table *) table; + + memset (&eh->elf.size, 0, + (sizeof (struct elf_x86_link_hash_entry) + - offsetof (struct elf_link_hash_entry, size))); + /* Set local fields. */ + eh->elf.indx = -1; + eh->elf.dynindx = -1; + eh->elf.got = htab->init_got_refcount; + eh->elf.plt = htab->init_plt_refcount; + /* Assume that we have been called by a non-ELF symbol reader. + This flag is then reset by the code which reads an ELF input + file. This ensures that a symbol created by a non-ELF symbol + reader will have the flag set correctly. */ + eh->elf.non_elf = 1; + eh->plt_second.offset = (bfd_vma) -1; + eh->plt_got.offset = (bfd_vma) -1; + eh->tlsdesc_got = (bfd_vma) -1; + } + + return entry; +} + +/* Compute a hash of a local hash entry. We use elf_link_hash_entry + for local symbol so that we can handle local STT_GNU_IFUNC symbols + as global symbol. We reuse indx and dynstr_index for local symbol + hash since they aren't used by global symbols in this backend. */ + +hashval_t +_bfd_x86_elf_local_htab_hash (const void *ptr) +{ + struct elf_link_hash_entry *h + = (struct elf_link_hash_entry *) ptr; + return ELF_LOCAL_SYMBOL_HASH (h->indx, h->dynstr_index); +} + +/* Compare local hash entries. */ + +int +_bfd_x86_elf_local_htab_eq (const void *ptr1, const void *ptr2) +{ + struct elf_link_hash_entry *h1 + = (struct elf_link_hash_entry *) ptr1; + struct elf_link_hash_entry *h2 + = (struct elf_link_hash_entry *) ptr2; + + return h1->indx == h2->indx && h1->dynstr_index == h2->dynstr_index; +} + +/* Destroy an x86 ELF linker hash table. */ + +void +_bfd_x86_elf_link_hash_table_free (bfd *obfd) +{ + struct elf_x86_link_hash_table *htab + = (struct elf_x86_link_hash_table *) obfd->link.hash; + + if (htab->loc_hash_table) + htab_delete (htab->loc_hash_table); + if (htab->loc_hash_memory) + objalloc_free ((struct objalloc *) htab->loc_hash_memory); + _bfd_elf_link_hash_table_free (obfd); +} + +/* Sort relocs into address order. */ + +int +_bfd_x86_elf_compare_relocs (const void *ap, const void *bp) +{ + const arelent *a = * (const arelent **) ap; + const arelent *b = * (const arelent **) bp; + + if (a->address > b->address) + return 1; + else if (a->address < b->address) + return -1; + else + return 0; +} + +bfd_boolean +_bfd_x86_elf_link_check_relocs (bfd *abfd, struct bfd_link_info *info) +{ + if (!bfd_link_relocatable (info)) + { + /* Check for __tls_get_addr reference. */ + struct elf_x86_link_hash_table *htab; + const struct elf_backend_data *bed = get_elf_backend_data (abfd); + htab = elf_x86_hash_table (info, bed->target_id); + if (htab) + { + struct elf_link_hash_entry *h + = elf_link_hash_lookup (elf_hash_table (info), + htab->tls_get_addr, + FALSE, FALSE, FALSE); + if (h != NULL) + ((struct elf_x86_link_hash_entry *) h)->tls_get_addr = 1; + } + } + + /* Invoke the regular ELF backend linker to do all the work. */ + return _bfd_elf_link_check_relocs (abfd, info); +} + +bfd_boolean +_bfd_x86_elf_always_size_sections (bfd *output_bfd, + struct bfd_link_info *info) +{ + asection *tls_sec = elf_hash_table (info)->tls_sec; + + if (tls_sec) + { + struct elf_link_hash_entry *tlsbase; + + tlsbase = elf_link_hash_lookup (elf_hash_table (info), + "_TLS_MODULE_BASE_", + FALSE, FALSE, FALSE); + + if (tlsbase && tlsbase->type == STT_TLS) + { + struct elf_x86_link_hash_table *htab; + struct bfd_link_hash_entry *bh = NULL; + const struct elf_backend_data *bed + = get_elf_backend_data (output_bfd); + + htab = elf_x86_hash_table (info, bed->target_id); + if (htab == NULL) + return FALSE; + + if (!(_bfd_generic_link_add_one_symbol + (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, + tls_sec, 0, NULL, FALSE, + bed->collect, &bh))) + return FALSE; + + htab->tls_module_base = bh; + + tlsbase = (struct elf_link_hash_entry *)bh; + tlsbase->def_regular = 1; + tlsbase->other = STV_HIDDEN; + tlsbase->root.linker_def = 1; + (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); + } + } + + return TRUE; +} + +void +_bfd_x86_elf_merge_symbol_attribute (struct elf_link_hash_entry *h, + const Elf_Internal_Sym *isym, + bfd_boolean definition, + bfd_boolean dynamic ATTRIBUTE_UNUSED) +{ + if (definition) + { + struct elf_x86_link_hash_entry *eh + = (struct elf_x86_link_hash_entry *) h; + eh->def_protected = (ELF_ST_VISIBILITY (isym->st_other) + == STV_PROTECTED); + } +} + +/* Copy the extra info we tack onto an elf_link_hash_entry. */ + +void +_bfd_x86_elf_copy_indirect_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) +{ + struct elf_x86_link_hash_entry *edir, *eind; + + edir = (struct elf_x86_link_hash_entry *) dir; + eind = (struct elf_x86_link_hash_entry *) ind; + + if (eind->dyn_relocs != NULL) + { + if (edir->dyn_relocs != NULL) + { + struct elf_dyn_relocs **pp; + struct elf_dyn_relocs *p; + + /* Add reloc counts against the indirect sym to the direct sym + list. Merge any entries against the same section. */ + for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) + { + struct elf_dyn_relocs *q; + + for (q = edir->dyn_relocs; q != NULL; q = q->next) + if (q->sec == p->sec) + { + q->pc_count += p->pc_count; + q->count += p->count; + *pp = p->next; + break; + } + if (q == NULL) + pp = &p->next; + } + *pp = edir->dyn_relocs; + } + + edir->dyn_relocs = eind->dyn_relocs; + eind->dyn_relocs = NULL; + } + + if (ind->root.type == bfd_link_hash_indirect + && dir->got.refcount <= 0) + { + edir->tls_type = eind->tls_type; + eind->tls_type = GOT_UNKNOWN; + } + + /* Copy gotoff_ref so that elf_i386_adjust_dynamic_symbol will + generate a R_386_COPY reloc. */ + edir->gotoff_ref |= eind->gotoff_ref; + + edir->has_got_reloc |= eind->has_got_reloc; + edir->has_non_got_reloc |= eind->has_non_got_reloc; + + if (ELIMINATE_COPY_RELOCS + && ind->root.type != bfd_link_hash_indirect + && dir->dynamic_adjusted) + { + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy non_got_ref. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + if (dir->versioned != versioned_hidden) + dir->ref_dynamic |= ind->ref_dynamic; + dir->ref_regular |= ind->ref_regular; + dir->ref_regular_nonweak |= ind->ref_regular_nonweak; + dir->needs_plt |= ind->needs_plt; + dir->pointer_equality_needed |= ind->pointer_equality_needed; + } + else + { + if (eind->func_pointer_refcount > 0) + { + edir->func_pointer_refcount += eind->func_pointer_refcount; + eind->func_pointer_refcount = 0; + } + + _bfd_elf_link_hash_copy_indirect (info, dir, ind); + } +} + +/* Remove undefined weak symbol from the dynamic symbol table if it + is resolved to 0. */ + +bfd_boolean +_bfd_x86_elf_fixup_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) +{ + if (h->dynindx != -1) + { + const struct elf_backend_data *bed + = get_elf_backend_data (info->output_bfd); + if (UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, + bed->target_id, + elf_x86_hash_entry (h)->has_got_reloc, + elf_x86_hash_entry (h))) + { + h->dynindx = -1; + _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, + h->dynstr_index); + } + } + return TRUE; +} + +/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ + +bfd_boolean +_bfd_x86_elf_hash_symbol (struct elf_link_hash_entry *h) +{ + if (h->plt.offset != (bfd_vma) -1 + && !h->def_regular + && !h->pointer_equality_needed) + return FALSE; + + return _bfd_elf_hash_symbol (h); +} + +/* Parse x86 GNU properties. */ + +enum elf_property_kind +_bfd_x86_elf_parse_gnu_properties (bfd *abfd, unsigned int type, + bfd_byte *ptr, unsigned int datasz) +{ + elf_property *prop; + + switch (type) + { + case GNU_PROPERTY_X86_ISA_1_USED: + case GNU_PROPERTY_X86_ISA_1_NEEDED: + case GNU_PROPERTY_X86_FEATURE_1_AND: + if (datasz != 4) + { + _bfd_error_handler + ((type == GNU_PROPERTY_X86_ISA_1_USED + ? _("error: %B: <corrupt x86 ISA used size: 0x%x>") + : (type == GNU_PROPERTY_X86_ISA_1_NEEDED + ? _("error: %B: <corrupt x86 ISA needed size: 0x%x>") + : _("error: %B: <corrupt x86 feature size: 0x%x>"))), + abfd, datasz); + return property_corrupt; + } + prop = _bfd_elf_get_property (abfd, type, datasz); + /* Combine properties of the same type. */ + prop->u.number |= bfd_h_get_32 (abfd, ptr); + prop->pr_kind = property_number; + break; + + default: + return property_ignored; + } + + return property_number; +} + +/* Merge x86 GNU property BPROP with APROP. If APROP isn't NULL, + return TRUE if APROP is updated. Otherwise, return TRUE if BPROP + should be merged with ABFD. */ + +bfd_boolean +_bfd_x86_elf_merge_gnu_properties (struct bfd_link_info *info, + bfd *abfd ATTRIBUTE_UNUSED, + elf_property *aprop, + elf_property *bprop) +{ + unsigned int number, features; + bfd_boolean updated = FALSE; + unsigned int pr_type = aprop != NULL ? aprop->pr_type : bprop->pr_type; + + switch (pr_type) + { + case GNU_PROPERTY_X86_ISA_1_USED: + case GNU_PROPERTY_X86_ISA_1_NEEDED: + if (aprop != NULL && bprop != NULL) + { + number = aprop->u.number; + aprop->u.number = number | bprop->u.number; + updated = number != (unsigned int) aprop->u.number; + } + else + { + /* Return TRUE if APROP is NULL to indicate that BPROP should + be added to ABFD. */ + updated = aprop == NULL; + } + break; + + case GNU_PROPERTY_X86_FEATURE_1_AND: + /* Only one of APROP and BPROP can be NULL: + 1. APROP & BPROP when both APROP and BPROP aren't NULL. + 2. If APROP is NULL, remove x86 feature. + 3. Otherwise, do nothing. + */ + if (aprop != NULL && bprop != NULL) + { + features = 0; + if (info->ibt) + features = GNU_PROPERTY_X86_FEATURE_1_IBT; + if (info->shstk) + features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + number = aprop->u.number; + /* Add GNU_PROPERTY_X86_FEATURE_1_IBT and + GNU_PROPERTY_X86_FEATURE_1_SHSTK. */ + aprop->u.number = (number & bprop->u.number) | features; + updated = number != (unsigned int) aprop->u.number; + /* Remove the property if all feature bits are cleared. */ + if (aprop->u.number == 0) + aprop->pr_kind = property_remove; + } + else + { + features = 0; + if (info->ibt) + features = GNU_PROPERTY_X86_FEATURE_1_IBT; + if (info->shstk) + features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + if (features) + { + /* Add GNU_PROPERTY_X86_FEATURE_1_IBT and + GNU_PROPERTY_X86_FEATURE_1_SHSTK. */ + if (aprop != NULL) + { + number = aprop->u.number; + aprop->u.number = number | features; + updated = number != (unsigned int) aprop->u.number; + } + else + { + bprop->u.number |= features; + updated = TRUE; + } + } + else if (aprop != NULL) + { + aprop->pr_kind = property_remove; + updated = TRUE; + } + } + break; + + default: + /* Never should happen. */ + abort (); + } + + return updated; +} diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h new file mode 100644 index 0000000..480189b --- /dev/null +++ b/bfd/elfxx-x86.h @@ -0,0 +1,283 @@ +/* x86 specific support for ELF + Copyright (C) 2017 Free Software Foundation, Inc. + + This file is part of BFD, the Binary File Descriptor library. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "sysdep.h" +#include "bfd.h" +#include "bfdlink.h" +#include "libbfd.h" +#include "elf-bfd.h" +#include "bfd_stdint.h" +#include "objalloc.h" +#include "hashtab.h" + +/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid + copying dynamic variables from a shared lib into an app's dynbss + section, and instead use a dynamic relocation to point into the + shared lib. */ +#define ELIMINATE_COPY_RELOCS 1 + +#define elf_x86_hash_table(p, id) \ + (elf_hash_table_id ((struct elf_link_hash_table *) ((p)->hash)) == (id) \ + ? ((struct elf_x86_link_hash_table *) ((p)->hash)) : NULL) + +/* Is a undefined weak symbol which is resolved to 0. Reference to an + undefined weak symbol is resolved to 0 when building executable if + it isn't dynamic and + 1. Has non-GOT/non-PLT relocations in text section. Or + 2. Has no GOT/PLT relocation. + Local undefined weak symbol is always resolved to 0. + */ +#define UNDEFINED_WEAK_RESOLVED_TO_ZERO(INFO, ID, GOT_RELOC, EH) \ + ((EH)->elf.root.type == bfd_link_hash_undefweak \ + && ((EH)->elf.forced_local \ + || (bfd_link_executable (INFO) \ + && (elf_x86_hash_table ((INFO), (ID))->interp == NULL \ + || !(GOT_RELOC) \ + || (EH)->has_non_got_reloc \ + || !(INFO)->dynamic_undefined_weak)))) + +/* Should copy relocation be generated for a symbol. Don't generate + copy relocation against a protected symbol defined in a shared + object with GNU_PROPERTY_NO_COPY_ON_PROTECTED. */ +#define SYMBOL_NO_COPYRELOC(INFO, EH) \ + ((EH)->def_protected \ + && ((EH)->elf.root.type == bfd_link_hash_defined \ + || (EH)->elf.root.type == bfd_link_hash_defweak) \ + && elf_has_no_copy_on_protected ((EH)->elf.root.u.def.section->owner) \ + && ((EH)->elf.root.u.def.section->owner->flags & DYNAMIC) != 0 \ + && ((EH)->elf.root.u.def.section->flags & SEC_CODE) == 0) + +/* x86 ELF linker hash entry. */ + +struct elf_x86_link_hash_entry +{ + struct elf_link_hash_entry elf; + + /* Track dynamic relocs copied for this symbol. */ + struct elf_dyn_relocs *dyn_relocs; + + unsigned char tls_type; + + /* TRUE if symbol has GOT or PLT relocations. */ + unsigned int has_got_reloc : 1; + + /* TRUE if symbol has non-GOT/non-PLT relocations in text sections. */ + unsigned int has_non_got_reloc : 1; + + /* Don't call finish_dynamic_symbol on this symbol. */ + unsigned int no_finish_dynamic_symbol : 1; + + /* TRUE if symbol is __tls_get_addr. */ + unsigned int tls_get_addr : 1; + + /* TRUE if symbol is defined as a protected symbol. */ + unsigned int def_protected : 1; + + /* Symbol is referenced by R_386_GOTOFF relocation. This is only used + by i386. */ + unsigned int gotoff_ref : 1; + + /* TRUE if a weak symbol with a real definition needs a copy reloc. + When there is a weak symbol with a real definition, the processor + independent code will have arranged for us to see the real + definition first. We need to copy the needs_copy bit from the + real definition and check it when allowing copy reloc in PIE. This + is only used by x86-64. */ + unsigned int needs_copy : 1; + + /* Reference count of C/C++ function pointer relocations in read-write + section which can be resolved at run-time. */ + bfd_signed_vma func_pointer_refcount; + + /* Information about the GOT PLT entry. Filled when there are both + GOT and PLT relocations against the same function. */ + union gotplt_union plt_got; + + /* Information about the second PLT entry. */ + union gotplt_union plt_second; + + /* Offset of the GOTPLT entry reserved for the TLS descriptor, + starting at the end of the jump table. */ + bfd_vma tlsdesc_got; +}; + +/* The first 3 values in tls_type of x86 ELF linker hash entry. */ +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_GD 2 + +#define elf_x86_hash_entry(ent) \ + ((struct elf_x86_link_hash_entry *)(ent)) + +/* x86 ELF linker hash table. */ + +struct elf_x86_link_hash_table +{ + struct elf_link_hash_table elf; + + /* Short-cuts to get to dynamic linker sections. */ + asection *interp; + asection *plt_eh_frame; + asection *plt_second; + asection *plt_second_eh_frame; + asection *plt_got; + asection *plt_got_eh_frame; + + union + { + bfd_signed_vma refcount; + bfd_vma offset; + } tls_ld_or_ldm_got; + + /* The amount of space used by the jump slots in the GOT. */ + bfd_vma sgotplt_jump_table_size; + + /* Small local sym cache. */ + struct sym_cache sym_cache; + + /* _TLS_MODULE_BASE_ symbol. */ + struct bfd_link_hash_entry *tls_module_base; + + /* Used by local STT_GNU_IFUNC symbols. */ + htab_t loc_hash_table; + void * loc_hash_memory; + + /* The offset into splt of the PLT entry for the TLS descriptor + resolver. Special values are 0, if not necessary (or not found + to be necessary yet), and -1 if needed but not determined + yet. */ + bfd_vma tlsdesc_plt; + + /* The offset into sgot of the GOT entry used by the PLT entry + above. */ + bfd_vma tlsdesc_got; + + /* The index of the next R_X86_64_JUMP_SLOT entry in .rela.plt. */ + bfd_vma next_jump_slot_index; + /* The index of the next R_X86_64_IRELATIVE entry in .rela.plt. */ + bfd_vma next_irelative_index; + + /* TRUE if there are dynamic relocs against IFUNC symbols that apply + to read-only sections. */ + bfd_boolean readonly_dynrelocs_against_ifunc; + + bfd_vma (*r_info) (bfd_vma, bfd_vma); + bfd_vma (*r_sym) (bfd_vma); + unsigned int pointer_r_type; + int dynamic_interpreter_size; + const char *dynamic_interpreter; + const char *tls_get_addr; +}; + +struct elf_x86_obj_tdata +{ + struct elf_obj_tdata root; + + /* tls_type for each local got entry. */ + char *local_got_tls_type; + + /* GOTPLT entries for TLS descriptors. */ + bfd_vma *local_tlsdesc_gotent; +}; + +#define elf_x86_tdata(abfd) \ + ((struct elf_x86_obj_tdata *) (abfd)->tdata.any) + +#define elf_x86_local_got_tls_type(abfd) \ + (elf_x86_tdata (abfd)->local_got_tls_type) + +#define elf_x86_local_tlsdesc_gotent(abfd) \ + (elf_x86_tdata (abfd)->local_tlsdesc_gotent) + +extern void _bfd_x86_elf_set_tls_module_base + (struct bfd_link_info *); + +extern bfd_vma _bfd_x86_elf_dtpoff_base + (struct bfd_link_info *); + +extern bfd_boolean _bfd_x86_elf_readonly_dynrelocs + (struct elf_link_hash_entry *, void *); + +extern struct elf_link_hash_entry * _bfd_elf_x86_get_local_sym_hash + (struct elf_x86_link_hash_table *, bfd *, const Elf_Internal_Rela *, + bfd_boolean); + +extern hashval_t _bfd_x86_elf_local_htab_hash + (const void *); + +extern int _bfd_x86_elf_local_htab_eq + (const void *, const void *); + +extern struct bfd_hash_entry * _bfd_x86_elf_link_hash_newfunc + (struct bfd_hash_entry *, struct bfd_hash_table *, const char *); + +extern void _bfd_x86_elf_link_hash_table_free + (bfd *); + +extern int _bfd_x86_elf_compare_relocs + (const void *, const void *); + +extern bfd_boolean _bfd_x86_elf_link_check_relocs + (bfd *, struct bfd_link_info *); + +extern bfd_boolean _bfd_x86_elf_always_size_sections + (bfd *, struct bfd_link_info *); + +extern void _bfd_x86_elf_merge_symbol_attribute + (struct elf_link_hash_entry *, const Elf_Internal_Sym *, + bfd_boolean, bfd_boolean); + +extern void _bfd_x86_elf_copy_indirect_symbol + (struct bfd_link_info *, struct elf_link_hash_entry *, + struct elf_link_hash_entry *); + +extern bfd_boolean _bfd_x86_elf_fixup_symbol + (struct bfd_link_info *, struct elf_link_hash_entry *); + +extern bfd_boolean _bfd_x86_elf_hash_symbol + (struct elf_link_hash_entry *); + +extern enum elf_property_kind _bfd_x86_elf_parse_gnu_properties + (bfd *, unsigned int, bfd_byte *, unsigned int); + +extern bfd_boolean _bfd_x86_elf_merge_gnu_properties + (struct bfd_link_info *, bfd *, elf_property *, elf_property *); + +#define bfd_elf64_bfd_link_check_relocs \ + _bfd_x86_elf_link_check_relocs +#define bfd_elf32_bfd_link_check_relocs \ + _bfd_x86_elf_link_check_relocs + +#define elf_backend_always_size_sections \ + _bfd_x86_elf_always_size_sections +#define elf_backend_merge_symbol_attribute \ + _bfd_x86_elf_merge_symbol_attribute +#define elf_backend_copy_indirect_symbol \ + _bfd_x86_elf_copy_indirect_symbol +#define elf_backend_fixup_symbol \ + _bfd_x86_elf_fixup_symbol +#define elf_backend_hash_symbol \ + _bfd_x86_elf_hash_symbol +#define elf_backend_omit_section_dynsym \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) +#define elf_backend_parse_gnu_properties \ + _bfd_x86_elf_parse_gnu_properties +#define elf_backend_merge_gnu_properties \ + _bfd_x86_elf_merge_gnu_properties |