/* x86 specific support for ELF
- Copyright (C) 2017 Free Software Foundation, Inc.
+ Copyright (C) 2017-2021 Free Software Foundation, Inc.
This file is part of BFD, the Binary File Descriptor library.
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
+/* Don't generate unused section symbols. */
+#define TARGET_KEEP_UNUSED_SECTION_SYMBOLS false
+
#include "sysdep.h"
#include "bfd.h"
#include "bfdlink.h"
#include "libbfd.h"
#include "elf-bfd.h"
-#include "bfd_stdint.h"
#include "hashtab.h"
+#include "elf-linker-x86.h"
#define PLT_CIE_LENGTH 20
#define PLT_FDE_LENGTH 36
into the shared library. However, if we are linking with -Bsymbolic,
we do not need to copy a reloc against a global symbol which is
defined in an object we are including in the link (i.e., DEF_REGULAR
- is set). At this point we have not seen all the input files, so it
- is possible that DEF_REGULAR is not set now but will be set later (it
- is never cleared). In case of a weak definition, DEF_REGULAR may be
- cleared later by a strong definition in a shared library. We account
- for that possibility below by storing information in the relocs_copied
- field of the hash table entry. A similar situation occurs when
- creating shared libraries and symbol visibility changes render the
- symbol local.
+ is set).
+
+ If PCREL_PLT is true, don't generate dynamic relocation in PIE for
+ PC-relative relocation against a dynamic function definition in data
+ section when PLT address can be used.
If on the other hand, we are creating an executable, we may need to
keep relocations for symbols satisfied by a dynamic library if we
We also need to generate dynamic pointer relocation against
STT_GNU_IFUNC symbol in the non-code section. */
-#define NEED_DYNAMIC_RELOCATION_P(INFO, H, SEC, R_TYPE, POINTER_TYPE) \
+#define NEED_DYNAMIC_RELOCATION_P(INFO, PCREL_PLT, H, SEC, R_TYPE, \
+ POINTER_TYPE) \
((bfd_link_pic (INFO) \
&& (! X86_PCREL_TYPE_P (R_TYPE) \
|| ((H) != NULL \
&& (! (bfd_link_pie (INFO) \
|| SYMBOLIC_BIND ((INFO), (H))) \
|| (H)->root.type == bfd_link_hash_defweak \
- || !(H)->def_regular)))) \
- || ((H) != NULL \
- && (H)->type == STT_GNU_IFUNC \
- && (R_TYPE) == POINTER_TYPE \
- && ((SEC)->flags & SEC_CODE) == 0) \
- || (ELIMINATE_COPY_RELOCS \
- && !bfd_link_pic (INFO) \
- && (H) != NULL \
- && ((H)->root.type == bfd_link_hash_defweak \
- || !(H)->def_regular)))
+ || (!(bfd_link_pie (INFO) \
+ && (PCREL_PLT) \
+ && (H)->plt.refcount > 0 \
+ && ((SEC)->flags & SEC_CODE) == 0 \
+ && (H)->type == STT_FUNC \
+ && (H)->def_dynamic) \
+ && !(H)->def_regular))))) \
+ || ((H) != NULL \
+ && (H)->type == STT_GNU_IFUNC \
+ && (R_TYPE) == POINTER_TYPE \
+ && ((SEC)->flags & SEC_CODE) == 0) \
+ || (ELIMINATE_COPY_RELOCS \
+ && !bfd_link_pic (INFO) \
+ && (H) != NULL \
+ && ((H)->root.type == bfd_link_hash_defweak \
+ || !(H)->def_regular)))
/* TRUE if dynamic relocation should be generated. Don't copy a
pc-relative relocation into the output file if the symbol needs
Copy dynamic function pointer relocations. Don't generate dynamic
relocations against resolved undefined weak symbols in PIE, except
when PC32_RELOC is TRUE. Undefined weak symbol is bound locally
- when PIC is false. */
-#define GENERATE_DYNAMIC_RELOCATION_P(INFO, EH, R_TYPE, \
+ when PIC is false. Don't generate dynamic relocations against
+ non-preemptible absolute symbol. */
+#define GENERATE_DYNAMIC_RELOCATION_P(INFO, EH, R_TYPE, SEC, \
NEED_COPY_RELOC_IN_PIE, \
RESOLVED_TO_ZERO, PC32_RELOC) \
((bfd_link_pic (INFO) \
+ && !(bfd_is_abs_section (SEC) \
+ && ((EH) == NULL \
+ || SYMBOL_REFERENCES_LOCAL (INFO, &(EH)->elf))) \
&& !(NEED_COPY_RELOC_IN_PIE) \
&& ((EH) == NULL \
|| ((ELF_ST_VISIBILITY ((EH)->elf.other) == STV_DEFAULT \
&& (!(RESOLVED_TO_ZERO) || PC32_RELOC)) \
|| (EH)->elf.root.type != bfd_link_hash_undefweak)) \
- && ((!X86_PCREL_TYPE_P (R_TYPE) \
- && !X86_SIZE_TYPE_P (R_TYPE)) \
- || ! SYMBOL_CALLS_LOCAL ((INFO), &(EH)->elf))) \
+ && ((!X86_PCREL_TYPE_P (R_TYPE) && !X86_SIZE_TYPE_P (R_TYPE)) \
+ || ! SYMBOL_CALLS_LOCAL ((INFO), \
+ (struct elf_link_hash_entry *) (EH)))) \
|| (ELIMINATE_COPY_RELOCS \
&& !bfd_link_pic (INFO) \
&& (EH) != NULL \
|| (ELF_ST_VISIBILITY ((H)->other) \
&& (H)->root.type == bfd_link_hash_undefweak))
+/* TRUE if this symbol isn't defined by a shared object. */
+#define SYMBOL_DEFINED_NON_SHARED_P(H) \
+ ((H)->def_regular \
+ || (H)->root.linker_def \
+ || (H)->root.ldscript_def \
+ || ((struct elf_x86_link_hash_entry *) (H))->linker_def \
+ || ELF_COMMON_DEF_P (H))
+
+/* Return TRUE if the symbol described by a linker hash entry H is
+ going to be absolute. Similar to bfd_is_abs_symbol, but excluding
+ all linker-script defined symbols. */
+#define ABS_SYMBOL_P(H) \
+ (bfd_is_abs_symbol (&(H)->root) && !(H)->root.ldscript_def)
+
/* TRUE if relative relocation should be generated. GOT reference to
global symbol in PIC will lead to dynamic symbol. It becomes a
problem when "time" or "times" is defined as a variable in an
executable, clashing with functions of the same name in libc. If a
symbol isn't undefined weak symbol, don't make it dynamic in PIC and
- generate relative relocation. */
+ generate relative relocation. Don't generate relative relocation
+ against non-preemptible absolute symbol. */
#define GENERATE_RELATIVE_RELOC_P(INFO, H) \
((H)->dynindx == -1 \
&& !(H)->forced_local \
&& (H)->root.type != bfd_link_hash_undefweak \
- && bfd_link_pic (INFO))
+ && bfd_link_pic (INFO) \
+ && !ABS_SYMBOL_P (H))
/* TRUE if this is a pointer reference to a local IFUNC. */
#define POINTER_LOCAL_IFUNC_P(INFO, H) \
{
struct elf_link_hash_entry elf;
- /* Track dynamic relocs copied for this symbol. */
- struct elf_dyn_relocs *dyn_relocs;
-
unsigned char tls_type;
/* Bit 0: Symbol has no GOT nor PLT relocations.
/* TRUE if symbol is defined by linker. */
unsigned int linker_def : 1;
+ /* TRUE if symbol is referenced by a non-GOT/non-PLT relocation in a
+ relocatable object file without indirect external access marker. */
+ unsigned int non_got_ref_without_indirect_extern_access : 1;
+
/* TRUE if symbol is referenced by R_386_GOTOFF relocation. This is
only used by i386. */
unsigned int gotoff_ref : 1;
struct elf_x86_lazy_plt_layout
{
- /* The first entry in an absolute lazy procedure linkage table looks
- like this. */
+ /* The first entry in a lazy procedure linkage table looks like this. */
const bfd_byte *plt0_entry;
unsigned int plt0_entry_size; /* Size of PLT0 entry. */
- /* Later entries in an absolute lazy procedure linkage table look
- like this. */
+ /* Later entries in a lazy procedure linkage table look like this. */
const bfd_byte *plt_entry;
unsigned int plt_entry_size; /* Size of each PLT entry. */
+ /* The TLSDESC entry in a lazy procedure linkage table looks like
+ this. This is for x86-64 only. */
+ const bfd_byte *plt_tlsdesc_entry;
+ unsigned int plt_tlsdesc_entry_size; /* Size of TLSDESC entry. */
+
+ /* Offsets into the TLSDESC entry that are to be replaced with
+ GOT+8 and GOT+TDG. These are for x86-64 only. */
+ unsigned int plt_tlsdesc_got1_offset;
+ unsigned int plt_tlsdesc_got2_offset;
+
+ /* Offset of the end of the PC-relative instructions containing
+ plt_tlsdesc_got1_offset and plt_tlsdesc_got2_offset. These
+ are for x86-64 only. */
+ unsigned int plt_tlsdesc_got1_insn_end;
+ unsigned int plt_tlsdesc_got2_insn_end;
+
/* Offsets into plt0_entry that are to be replaced with GOT[1] and
GOT[2]. */
unsigned int plt0_got1_offset;
struct elf_x86_non_lazy_plt_layout
{
- /* Entries in an absolute non-lazy procedure linkage table look like
- this. */
+ /* Entries in a non-lazy procedure linkage table look like this. */
const bfd_byte *plt_entry;
- /* Entries in a PIC non-lazy procedure linkage table look like this. */
+ /* Entries in a PIC non-lazy procedure linkage table look like this.
+ This is only used for i386 where absolute PLT and PIC PLT are
+ different. */
const bfd_byte *pic_plt_entry;
unsigned int plt_entry_size; /* Size of each PLT entry. */
struct elf_x86_plt_layout
{
- /* The first entry in a lazy procedure linkage table looks like this.
- This is only used for i386 where absolute PLT0 and PIC PLT0 are
- different. */
+ /* The first entry in a lazy procedure linkage table looks like this. */
const bfd_byte *plt0_entry;
/* Entries in a procedure linkage table look like this. */
const bfd_byte *plt_entry;
This is only used for x86-64. */
unsigned int plt_got_insn_size;
+ /* Alignment of the .iplt section. */
+ unsigned int iplt_alignment;
+
/* .eh_frame covering the .plt section. */
const bfd_byte *eh_frame_plt;
unsigned int eh_frame_plt_size;
#define GOT_TLS_IE_NEG 6
#define GOT_TLS_IE_BOTH 7
#define GOT_TLS_GDESC 8
+#define GOT_ABS 9
#define GOT_TLS_GD_BOTH_P(type) \
((type) == (GOT_TLS_GD | GOT_TLS_GDESC))
#define GOT_TLS_GD_P(type) \
#define elf_x86_hash_entry(ent) \
((struct elf_x86_link_hash_entry *)(ent))
-enum elf_x86_target_os
-{
- is_normal,
- is_vxworks,
- is_nacl
-};
-
/* x86 ELF linker hash table. */
struct elf_x86_link_hash_table
/* 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;
htab_t loc_hash_table;
void * loc_hash_memory;
- /* 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;
-
/* The (unloaded but important) .rel.plt.unloaded section on VxWorks.
This is used for i386 only. */
asection *srelplt2;
is only used for i386. */
bfd_vma next_tls_desc_index;
- /* 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. This is only used for x86-64. */
- bfd_vma tlsdesc_plt;
-
/* Value used to fill the unused bytes of the first PLT entry. This
is only used for i386. */
bfd_byte plt0_pad_byte;
+ /* TRUE if GOT is referenced. */
+ unsigned int got_referenced : 1;
+
+ /* TRUE if PLT is PC-relative. PLT in PDE and PC-relative PLT in PIE
+ can be used as function address.
+
+ NB: i386 has non-PIC PLT and PIC PLT. Only non-PIC PLT in PDE can
+ be used as function address. PIC PLT in PIE can't be used as
+ function address. */
+ unsigned int pcrel_plt : 1;
+
bfd_vma (*r_info) (bfd_vma, bfd_vma);
bfd_vma (*r_sym) (bfd_vma);
- bfd_boolean (*is_reloc_section) (const char *);
- enum elf_target_id target_id;
- enum elf_x86_target_os target_os;
+ bool (*is_reloc_section) (const char *);
unsigned int sizeof_reloc;
- unsigned int dt_reloc;
- unsigned int dt_reloc_sz;
- unsigned int dt_reloc_ent;
unsigned int got_entry_size;
unsigned int pointer_r_type;
int dynamic_interpreter_size;
const char *dynamic_interpreter;
const char *tls_get_addr;
-};
-
-/* Architecture-specific backend data for x86. */
-struct elf_x86_backend_data
-{
- /* Target system. */
- enum elf_x86_target_os target_os;
+ /* Options passed from the linker. */
+ struct elf_linker_x86_params *params;
};
-#define get_elf_x86_backend_data(abfd) \
- ((const struct elf_x86_backend_data *) \
- get_elf_backend_data (abfd)->arch_data)
-
struct elf_x86_init_table
{
/* The lazy PLT layout. */
long count;
};
+/* Set if a relocation is converted from a GOTPCREL relocation. */
+#define R_X86_64_converted_reloc_bit (1 << 7)
+
#define elf_x86_tdata(abfd) \
((struct elf_x86_obj_tdata *) (abfd)->tdata.any)
#define is_x86_elf(bfd, htab) \
(bfd_get_flavour (bfd) == bfd_target_elf_flavour \
&& elf_tdata (bfd) != NULL \
- && elf_object_id (bfd) == (htab)->target_id)
+ && elf_object_id (bfd) == (htab)->elf.hash_table_id)
-extern bfd_boolean _bfd_x86_elf_mkobject
+extern bool _bfd_x86_elf_mkobject
(bfd *);
extern void _bfd_x86_elf_set_tls_module_base
extern bfd_vma _bfd_x86_elf_dtpoff_base
(struct bfd_link_info *);
-extern bfd_boolean _bfd_x86_elf_readonly_dynrelocs
+extern bool _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);
+ bool);
extern hashval_t _bfd_x86_elf_local_htab_hash
(const void *);
extern int _bfd_x86_elf_compare_relocs
(const void *, const void *);
-extern bfd_boolean _bfd_x86_elf_link_check_relocs
+extern bool _bfd_x86_elf_link_check_relocs
(bfd *, struct bfd_link_info *);
-extern bfd_boolean _bfd_x86_elf_size_dynamic_sections
+extern bool _bfd_elf_x86_valid_reloc_p
+ (asection *, struct bfd_link_info *, struct elf_x86_link_hash_table *,
+ const Elf_Internal_Rela *, struct elf_link_hash_entry *,
+ Elf_Internal_Sym *, Elf_Internal_Shdr *, bool *);
+
+extern bool _bfd_x86_elf_size_dynamic_sections
(bfd *, struct bfd_link_info *);
extern struct elf_x86_link_hash_table *_bfd_x86_elf_finish_dynamic_sections
(bfd *, struct bfd_link_info *);
-extern bfd_boolean _bfd_x86_elf_always_size_sections
+extern bool _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);
+ (struct elf_link_hash_entry *, unsigned int, bool, bool);
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
+extern bool _bfd_x86_elf_fixup_symbol
(struct bfd_link_info *, struct elf_link_hash_entry *);
-extern bfd_boolean _bfd_x86_elf_hash_symbol
+extern bool _bfd_x86_elf_hash_symbol
(struct elf_link_hash_entry *);
-extern bfd_boolean _bfd_x86_elf_adjust_dynamic_symbol
+extern bool _bfd_x86_elf_adjust_dynamic_symbol
(struct bfd_link_info *, struct elf_link_hash_entry *);
extern void _bfd_x86_elf_hide_symbol
- (struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean);
+ (struct bfd_link_info *, struct elf_link_hash_entry *, bool);
-extern bfd_boolean _bfd_x86_elf_link_symbol_references_local
+extern bool _bfd_x86_elf_link_symbol_references_local
(struct bfd_link_info *, struct elf_link_hash_entry *);
extern asection * _bfd_x86_elf_gc_mark_hook
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 *);
+extern bool _bfd_x86_elf_merge_gnu_properties
+ (struct bfd_link_info *, bfd *, bfd *, elf_property *, elf_property *);
+
+extern void _bfd_x86_elf_link_fixup_gnu_properties
+ (struct bfd_link_info *, elf_property_list **);
extern bfd * _bfd_x86_elf_link_setup_gnu_properties
(struct bfd_link_info *, struct elf_x86_init_table *);
+extern void _bfd_x86_elf_link_fixup_ifunc_symbol
+ (struct bfd_link_info *, struct elf_x86_link_hash_table *,
+ struct elf_link_hash_entry *, Elf_Internal_Sym *sym);
+
+extern void _bfd_x86_elf_link_report_relative_reloc
+ (struct bfd_link_info *, asection *, struct elf_link_hash_entry *,
+ Elf_Internal_Sym *, const char *, const void *);
+
#define bfd_elf64_mkobject \
_bfd_x86_elf_mkobject
#define bfd_elf32_mkobject \
#define elf_backend_gc_mark_hook \
_bfd_x86_elf_gc_mark_hook
#define elf_backend_omit_section_dynsym \
- ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
+ _bfd_elf_omit_section_dynsym_all
#define elf_backend_parse_gnu_properties \
_bfd_x86_elf_parse_gnu_properties
#define elf_backend_merge_gnu_properties \
_bfd_x86_elf_merge_gnu_properties
+#define elf_backend_fixup_gnu_properties \
+ _bfd_x86_elf_link_fixup_gnu_properties