X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-i386.c;h=31ef02a568e8292971d2c462b0f9602717cb24f2;hb=37c0b6ee65941d54fa8064c21b39f97fdc318156;hp=3bee4ca88db4d548b514dfc5c83606f5afb7fe1e;hpb=a5def14f1ca70e14d9433cb229c9369fa3051598;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 3bee4ca88d..31ef02a568 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -541,15 +541,20 @@ elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) shared lib. */ #define ELIMINATE_COPY_RELOCS 1 -/* The size in bytes of an entry in the procedure linkage table. */ +/* The size in bytes of an entry in the lazy procedure linkage table. */ -#define PLT_ENTRY_SIZE 16 +#define LAZY_PLT_ENTRY_SIZE 16 -/* The first entry in an absolute procedure linkage table looks like - this. See the SVR4 ABI i386 supplement to see how this works. - Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ +/* The size in bytes of an entry in the non-lazy procedure linkage + table. */ -static const bfd_byte elf_i386_plt0_entry[12] = +#define NON_LAZY_PLT_ENTRY_SIZE 8 + +/* The first entry in an absolute lazy procedure linkage table looks + like this. See the SVR4 ABI i386 supplement to see how this works. + Will be padded to LAZY_PLT_ENTRY_SIZE with lazy_plt->plt0_pad_byte. */ + +static const bfd_byte elf_i386_lazy_plt0_entry[12] = { 0xff, 0x35, /* pushl contents of address */ 0, 0, 0, 0, /* replaced with address of .got + 4. */ @@ -557,10 +562,10 @@ static const bfd_byte elf_i386_plt0_entry[12] = 0, 0, 0, 0 /* replaced with address of .got + 8. */ }; -/* Subsequent entries in an absolute procedure linkage table look like - this. */ +/* Subsequent entries in an absolute lazy procedure linkage table look + like this. */ -static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_lazy_plt_entry[LAZY_PLT_ENTRY_SIZE] = { 0xff, 0x25, /* jmp indirect */ 0, 0, 0, 0, /* replaced with address of this symbol in .got. */ @@ -570,18 +575,20 @@ static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; -/* The first entry in a PIC procedure linkage table look like this. - Will be padded to PLT_ENTRY_SIZE with htab->plt0_pad_byte. */ +/* The first entry in a PIC lazy procedure linkage table look like + this. Will be padded to LAZY_PLT_ENTRY_SIZE with + lazy_plt->plt0_pad_byte. */ -static const bfd_byte elf_i386_pic_plt0_entry[12] = +static const bfd_byte elf_i386_pic_lazy_plt0_entry[12] = { 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ 0xff, 0xa3, 8, 0, 0, 0 /* jmp *8(%ebx) */ }; -/* Subsequent entries in a PIC procedure linkage table look like this. */ +/* Subsequent entries in a PIC lazy procedure linkage table look like + this. */ -static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_pic_lazy_plt_entry[LAZY_PLT_ENTRY_SIZE] = { 0xff, 0xa3, /* jmp *offset(%ebx) */ 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ @@ -591,27 +598,82 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; -/* Entries in the GOT procedure linkage table look like this. */ +/* Entries in the non-lazy procedure linkage table look like this. */ -static const bfd_byte elf_i386_got_plt_entry[8] = +static const bfd_byte elf_i386_non_lazy_plt_entry[NON_LAZY_PLT_ENTRY_SIZE] = { 0xff, 0x25, /* jmp indirect */ 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ 0x66, 0x90 /* xchg %ax,%ax */ }; -/* Entries in the PIC GOT procedure linkage table look like this. */ +/* Entries in the PIC non-lazy procedure linkage table look like + this. */ -static const bfd_byte elf_i386_pic_got_plt_entry[8] = +static const bfd_byte elf_i386_pic_non_lazy_plt_entry[NON_LAZY_PLT_ENTRY_SIZE] = { 0xff, 0xa3, /* jmp *offset(%ebx) */ 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ 0x66, 0x90 /* xchg %ax,%ax */ }; -/* .eh_frame covering the .plt section. */ +/* The first entry in an absolute IBT-enabled lazy procedure linkage + table looks like this. */ + +static const bfd_byte elf_i386_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] = +{ + 0xff, 0x35, 0, 0, 0, 0, /* pushl GOT[1] */ + 0xff, 0x25, 0, 0, 0, 0, /* jmp *GOT[2] */ + 0x0f, 0x1f, 0x40, 0x00 /* nopl 0(%rax) */ +}; + +/* Subsequent entries for an absolute IBT-enabled lazy procedure linkage + table look like this. Subsequent entries for a PIC IBT-enabled lazy + procedure linkage table are the same. */ + +static const bfd_byte elf_i386_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = +{ + 0xf3, 0x0f, 0x1e, 0xfb, /* endbr32 */ + 0x68, 0, 0, 0, 0, /* pushl immediate */ + 0xe9, 0, 0, 0, 0, /* jmp relative */ + 0x66, 0x90 /* xchg %ax,%ax */ +}; + +/* The first entry in a PIC IBT-enabled lazy procedure linkage table + look like. */ + +static const bfd_byte elf_i386_pic_lazy_ibt_plt0_entry[LAZY_PLT_ENTRY_SIZE] = +{ + 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ + 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ + 0x0f, 0x1f, 0x40, 0x00 /* nopl 0(%rax) */ +}; + +/* Entries for branches with IBT-enabled in the absolute non-lazey + procedure linkage table look like this. They have the same size + as the lazy PLT entry. */ + +static const bfd_byte elf_i386_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = +{ + 0xf3, 0x0f, 0x1e, 0xfb, /* endbr32 */ + 0xff, 0x25, 0, 0, 0, 0, /* jmp *name@GOT */ + 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */ +}; + +/* Entries for branches with IBT-enabled in the PIC non-lazey procedure + linkage table look like this. They have the same size as the lazy + PLT entry. */ + +static const bfd_byte elf_i386_pic_non_lazy_ibt_plt_entry[LAZY_PLT_ENTRY_SIZE] = +{ + 0xf3, 0x0f, 0x1e, 0xfb, /* endbr32 */ + 0xff, 0xa3, 0, 0, 0, 0, /* jmp *name@GOT(%ebx) */ + 0x66, 0x0f, 0x1f, 0x44, 0x00, 0x00 /* nopw 0x0(%rax,%rax,1) */ +}; + +/* .eh_frame covering the lazy .plt section. */ -static const bfd_byte elf_i386_eh_frame_plt[] = +static const bfd_byte elf_i386_eh_frame_lazy_plt[] = { #define PLT_CIE_LENGTH 20 #define PLT_FDE_LENGTH 36 @@ -648,9 +710,44 @@ static const bfd_byte elf_i386_eh_frame_plt[] = DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop }; -/* .eh_frame covering the .plt.got section. */ +/* .eh_frame covering the lazy .plt section with IBT-enabled. */ + +static const bfd_byte elf_i386_eh_frame_lazy_ibt_plt[] = +{ + PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ + 0, 0, 0, 0, /* CIE ID */ + 1, /* CIE version */ + 'z', 'R', 0, /* Augmentation string */ + 1, /* Code alignment factor */ + 0x7c, /* Data alignment factor */ + 8, /* Return address column */ + 1, /* Augmentation size */ + DW_EH_PE_pcrel | DW_EH_PE_sdata4, /* FDE encoding */ + DW_CFA_def_cfa, 4, 4, /* DW_CFA_def_cfa: r4 (esp) ofs 4 */ + DW_CFA_offset + 8, 1, /* DW_CFA_offset: r8 (eip) at cfa-4 */ + DW_CFA_nop, DW_CFA_nop, + + PLT_FDE_LENGTH, 0, 0, 0, /* FDE length */ + PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ + 0, 0, 0, 0, /* R_386_PC32 .plt goes here */ + 0, 0, 0, 0, /* .plt size goes here */ + 0, /* Augmentation size */ + DW_CFA_def_cfa_offset, 8, /* DW_CFA_def_cfa_offset: 8 */ + DW_CFA_advance_loc + 6, /* DW_CFA_advance_loc: 6 to __PLT__+6 */ + DW_CFA_def_cfa_offset, 12, /* DW_CFA_def_cfa_offset: 12 */ + DW_CFA_advance_loc + 10, /* DW_CFA_advance_loc: 10 to __PLT__+16 */ + DW_CFA_def_cfa_expression, /* DW_CFA_def_cfa_expression */ + 11, /* Block length */ + DW_OP_breg4, 4, /* DW_OP_breg4 (esp): 4 */ + DW_OP_breg8, 0, /* DW_OP_breg8 (eip): 0 */ + DW_OP_lit15, DW_OP_and, DW_OP_lit9, DW_OP_ge, + DW_OP_lit2, DW_OP_shl, DW_OP_plus, + DW_CFA_nop, DW_CFA_nop, DW_CFA_nop, DW_CFA_nop +}; + +/* .eh_frame covering the non-lazy .plt section. */ -static const bfd_byte elf_i386_eh_frame_plt_got[] = +static const bfd_byte elf_i386_eh_frame_non_lazy_plt[] = { #define PLT_GOT_FDE_LENGTH 16 PLT_CIE_LENGTH, 0, 0, 0, /* CIE length */ @@ -668,23 +765,26 @@ static const bfd_byte elf_i386_eh_frame_plt_got[] = PLT_GOT_FDE_LENGTH, 0, 0, 0, /* FDE length */ PLT_CIE_LENGTH + 8, 0, 0, 0, /* CIE pointer */ - 0, 0, 0, 0, /* the start of .plt.got goes here */ - 0, 0, 0, 0, /* .plt.got size goes here */ + 0, 0, 0, 0, /* the start of non-lazy .plt goes here */ + 0, 0, 0, 0, /* non-lazy .plt size goes here */ 0, /* Augmentation size */ DW_CFA_nop, DW_CFA_nop, DW_CFA_nop }; -struct elf_i386_plt_layout +struct elf_i386_lazy_plt_layout { - /* The first entry in an absolute procedure linkage table looks like this. */ + /* The first entry in an absolute lazy procedure linkage table looks + like this. */ const bfd_byte *plt0_entry; unsigned int plt0_entry_size; - /* Offsets into plt0_entry that are to be replaced with GOT[1] and GOT[2]. */ + /* Offsets into plt0_entry that are to be replaced with GOT[1] and + GOT[2]. */ unsigned int plt0_got1_offset; unsigned int plt0_got2_offset; - /* Later entries in an absolute procedure linkage table look like this. */ + /* Later entries in an absolute lazy procedure linkage table look + like this. */ const bfd_byte *plt_entry; unsigned int plt_entry_size; @@ -693,46 +793,115 @@ struct elf_i386_plt_layout unsigned int plt_reloc_offset; /* ... offset into relocation table. */ unsigned int plt_plt_offset; /* ... offset to start of .plt. */ - /* Offset into plt_entry where the initial value of the GOT entry points. */ + /* Offset into plt_entry where the initial value of the GOT entry + points. */ unsigned int plt_lazy_offset; - /* The first entry in a PIC procedure linkage table looks like this. */ + /* The first entry in a PIC lazy procedure linkage table looks like + this. */ const bfd_byte *pic_plt0_entry; - /* Subsequent entries in a PIC procedure linkage table look like this. */ + /* Subsequent entries in a PIC lazy procedure linkage table look + like this. */ const bfd_byte *pic_plt_entry; - /* .eh_frame covering the .plt section. */ + /* .eh_frame covering the lazy .plt section. */ const bfd_byte *eh_frame_plt; unsigned int eh_frame_plt_size; +}; + +struct elf_i386_non_lazy_plt_layout +{ + /* Entries in an absolute 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. */ + const bfd_byte *pic_plt_entry; - /* .eh_frame covering the .plt.got section. */ - const bfd_byte *eh_frame_plt_got; - unsigned int eh_frame_plt_got_size; + unsigned int plt_entry_size; + + /* Offsets into plt_entry that are to be replaced with... */ + unsigned int plt_got_offset; /* ... address of this symbol in .got. */ + + /* .eh_frame covering the non-lazy .plt section. */ + const bfd_byte *eh_frame_plt; + unsigned int eh_frame_plt_size; }; -#define GET_PLT_ENTRY_SIZE(abfd) \ - get_elf_i386_backend_data (abfd)->plt->plt_entry_size +struct elf_i386_plt_layout +{ + /* 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; + unsigned int plt_entry_size; + + /* 1 has PLT0. */ + unsigned int has_plt0; + + /* Offsets into plt_entry that are to be replaced with... */ + unsigned int plt_got_offset; /* ... address of this symbol in .got. */ + + /* .eh_frame covering the .plt section. */ + const bfd_byte *eh_frame_plt; + unsigned int eh_frame_plt_size; +}; /* These are the standard parameters. */ -static const struct elf_i386_plt_layout elf_i386_plt = +static const struct elf_i386_lazy_plt_layout elf_i386_lazy_plt = { - elf_i386_plt0_entry, /* plt0_entry */ - sizeof (elf_i386_plt0_entry), /* plt0_entry_size */ + elf_i386_lazy_plt0_entry, /* plt0_entry */ + sizeof (elf_i386_lazy_plt0_entry), /* plt0_entry_size */ 2, /* plt0_got1_offset */ 8, /* plt0_got2_offset */ - elf_i386_plt_entry, /* plt_entry */ - PLT_ENTRY_SIZE, /* plt_entry_size */ + elf_i386_lazy_plt_entry, /* plt_entry */ + LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ 2, /* plt_got_offset */ 7, /* plt_reloc_offset */ 12, /* plt_plt_offset */ 6, /* plt_lazy_offset */ - elf_i386_pic_plt0_entry, /* pic_plt0_entry */ - elf_i386_pic_plt_entry, /* pic_plt_entry */ - elf_i386_eh_frame_plt, /* eh_frame_plt */ - sizeof (elf_i386_eh_frame_plt), /* eh_frame_plt_size */ - elf_i386_eh_frame_plt_got, /* eh_frame_plt_got */ - sizeof (elf_i386_eh_frame_plt_got), /* eh_frame_plt_got_size */ + elf_i386_pic_lazy_plt0_entry, /* pic_plt0_entry */ + elf_i386_pic_lazy_plt_entry, /* pic_plt_entry */ + elf_i386_eh_frame_lazy_plt, /* eh_frame_plt */ + sizeof (elf_i386_eh_frame_lazy_plt) /* eh_frame_plt_size */ + }; + +static const struct elf_i386_non_lazy_plt_layout elf_i386_non_lazy_plt = + { + elf_i386_non_lazy_plt_entry, /* plt_entry */ + elf_i386_pic_non_lazy_plt_entry, /* pic_plt_entry */ + NON_LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ + 2, /* plt_got_offset */ + elf_i386_eh_frame_non_lazy_plt, /* eh_frame_plt */ + sizeof (elf_i386_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ + }; + +static const struct elf_i386_lazy_plt_layout elf_i386_lazy_ibt_plt = + { + elf_i386_lazy_ibt_plt0_entry, /* plt0_entry */ + sizeof (elf_i386_lazy_ibt_plt0_entry), /* plt0_entry_size */ + 2, /* plt0_got1_offset */ + 8, /* plt0_got2_offset */ + elf_i386_lazy_ibt_plt_entry, /* plt_entry */ + LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ + 4+2, /* plt_got_offset */ + 4+1, /* plt_reloc_offset */ + 4+6, /* plt_plt_offset */ + 0, /* plt_lazy_offset */ + elf_i386_pic_lazy_ibt_plt0_entry, /* pic_plt0_entry */ + elf_i386_lazy_ibt_plt_entry, /* pic_plt_entry */ + elf_i386_eh_frame_lazy_ibt_plt, /* eh_frame_plt */ + sizeof (elf_i386_eh_frame_lazy_ibt_plt) /* eh_frame_plt_size */ + }; + +static const struct elf_i386_non_lazy_plt_layout elf_i386_non_lazy_ibt_plt = + { + elf_i386_non_lazy_ibt_plt_entry, /* plt_entry */ + elf_i386_pic_non_lazy_ibt_plt_entry,/* pic_plt_entry */ + LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ + 4+2, /* plt_got_offset */ + elf_i386_eh_frame_non_lazy_plt, /* eh_frame_plt */ + sizeof (elf_i386_eh_frame_non_lazy_plt) /* eh_frame_plt_size */ }; @@ -746,14 +915,16 @@ static const struct elf_i386_plt_layout elf_i386_plt = struct elf_i386_backend_data { - /* Parameters describing PLT generation. */ - const struct elf_i386_plt_layout *plt; - /* Value used to fill the unused bytes of the first PLT entry. */ bfd_byte plt0_pad_byte; - /* True if the target system is VxWorks. */ - int is_vxworks; + /* Target system. */ + enum + { + is_normal, + is_vxworks, + is_nacl + } os; }; #define get_elf_i386_backend_data(abfd) \ @@ -763,9 +934,8 @@ struct elf_i386_backend_data /* These are the standard parameters. */ static const struct elf_i386_backend_data elf_i386_arch_bed = { - &elf_i386_plt, /* plt */ 0, /* plt0_pad_byte */ - 0, /* is_vxworks */ + is_normal /* os */ }; #define elf_backend_arch_data &elf_i386_arch_bed @@ -775,14 +945,28 @@ static const struct elf_i386_backend_data elf_i386_arch_bed = 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 \ - && bfd_link_executable (INFO) \ - && (elf_i386_hash_table (INFO)->interp == NULL \ - || !(GOT_RELOC) \ - || (EH)->has_non_got_reloc \ - || !(INFO)->dynamic_undefined_weak)) + && ((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. */ @@ -820,10 +1004,14 @@ struct elf_i386_link_hash_entry /* Symbol has non-GOT/non-PLT relocations in text sections. */ unsigned int has_non_got_reloc : 1; - /* 0: symbol isn't ___tls_get_addr. - 1: symbol is ___tls_get_addr. - 2: symbol is unknown. */ - unsigned int tls_get_addr : 2; + /* 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. */ @@ -833,6 +1021,9 @@ struct elf_i386_link_hash_entry 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; @@ -881,9 +1072,20 @@ struct elf_i386_link_hash_table /* 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; + /* Parameters describing PLT generation. */ + struct elf_i386_plt_layout plt; + + /* Parameters describing lazy PLT generation. */ + const struct elf_i386_lazy_plt_layout *lazy_plt; + + /* Parameters describing non-lazy PLT generation. */ + const struct elf_i386_non_lazy_plt_layout *non_lazy_plt; + union { bfd_signed_vma refcount; @@ -959,7 +1161,9 @@ elf_i386_link_hash_newfunc (struct bfd_hash_entry *entry, eh->gotoff_ref = 0; eh->has_got_reloc = 0; eh->has_non_got_reloc = 0; - eh->tls_get_addr = 2; + 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; @@ -1088,55 +1292,6 @@ elf_i386_link_hash_table_create (bfd *abfd) return &ret->elf.root; } -/* Create .plt, .rel.plt, .got, .got.plt, .rel.got, .dynbss, and - .rel.bss sections in DYNOBJ, and set up shortcuts to them in our - hash table. */ - -static bfd_boolean -elf_i386_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) -{ - struct elf_i386_link_hash_table *htab; - - if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return FALSE; - - htab = elf_i386_hash_table (info); - if (htab == NULL) - return FALSE; - - /* Set the contents of the .interp section to the interpreter. */ - if (bfd_link_executable (info) && !info->nointerp) - { - 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; - htab->interp = s; - } - - if (get_elf_i386_backend_data (dynobj)->is_vxworks - && !elf_vxworks_create_dynamic_sections (dynobj, info, - &htab->srelplt2)) - return FALSE; - - if (!info->no_ld_generated_unwind_info - && htab->plt_eh_frame == NULL - && htab->elf.splt != NULL) - { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - htab->plt_eh_frame - = bfd_make_section_anyway_with_flags (dynobj, ".eh_frame", flags); - if (htab->plt_eh_frame == NULL - || !bfd_set_section_alignment (dynobj, htab->plt_eh_frame, 2)) - return FALSE; - } - - return TRUE; -} - /* Copy the extra info we tack onto an elf_link_hash_entry. */ static void @@ -1237,7 +1392,7 @@ elf_i386_check_tls_transition (asection *sec, struct elf_link_hash_entry *h; bfd_vma offset; bfd_byte *call; - bfd_boolean indirect_call, tls_get_addr; + bfd_boolean indirect_call; offset = rel->r_offset; switch (r_type) @@ -1342,29 +1497,9 @@ elf_i386_check_tls_transition (asection *sec, if (r_symndx < symtab_hdr->sh_info) return FALSE; - tls_get_addr = FALSE; h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (h != NULL && h->root.root.string != NULL) - { - struct elf_i386_link_hash_entry *eh - = (struct elf_i386_link_hash_entry *) h; - tls_get_addr = eh->tls_get_addr == 1; - if (eh->tls_get_addr > 1) - { - /* Use strncmp to check ___tls_get_addr since - ___tls_get_addr may be versioned. */ - if (strncmp (h->root.root.string, "___tls_get_addr", 15) - == 0) - { - eh->tls_get_addr = 1; - tls_get_addr = TRUE; - } - else - eh->tls_get_addr = 0; - } - } - - if (!tls_get_addr) + if (h == NULL + || !((struct elf_i386_link_hash_entry *) h)->tls_get_addr) return FALSE; else if (indirect_call) return (ELF32_R_TYPE (rel[1].r_info) == R_386_GOT32X); @@ -1567,10 +1702,10 @@ elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, _bfd_error_handler /* xgettext:c-format */ - (_("%B: TLS transition from %s to %s against `%s' at 0x%lx " + (_("%B: TLS transition from %s to %s against `%s' at %#Lx " "in section `%A' failed"), - abfd, sec, from->name, to->name, name, - (unsigned long) rel->r_offset); + abfd, from->name, to->name, name, + rel->r_offset, sec); bfd_set_error (bfd_error_bad_value); return FALSE; } @@ -1655,7 +1790,8 @@ elf_i386_convert_load_reloc (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, _bfd_error_handler /* xgettext:c-format */ - (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base register can not be used when making a shared object"), + (_("%B: direct GOT relocation R_386_GOT32X against `%s' without base" + " register can not be used when making a shared object"), abfd, name); return FALSE; } @@ -1721,7 +1857,7 @@ convert_branch: modrm = 0xe8; /* To support TLS optimization, always use addr32 prefix for "call *___tls_get_addr@GOT(%reg)". */ - if (eh && eh->tls_get_addr == 1) + if (eh && eh->tls_get_addr) { nop = 0x67; nop_offset = irel->r_offset - 2; @@ -1769,11 +1905,13 @@ convert_branch: return TRUE; /* def_regular is set by an assignment in a linker script in - bfd_elf_record_link_assignment. */ - if ((h->def_regular - || h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - && SYMBOL_REFERENCES_LOCAL (link_info, h)) + bfd_elf_record_link_assignment. start_stop is set on + __start_SECNAME/__stop_SECNAME which mark section SECNAME. */ + if (h->start_stop + || ((h->def_regular + || h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak) + && SYMBOL_REFERENCES_LOCAL (link_info, h))) { convert_load: if (opcode == 0x8b) @@ -1853,7 +1991,6 @@ elf_i386_check_relocs (bfd *abfd, const Elf_Internal_Rela *rel_end; asection *sreloc; bfd_byte *contents; - bfd_boolean use_plt_got; if (bfd_link_relocatable (info)) return TRUE; @@ -1885,10 +2022,6 @@ elf_i386_check_relocs (bfd *abfd, return FALSE; } - use_plt_got = (!get_elf_i386_backend_data (abfd)->is_vxworks - && (get_elf_i386_backend_data (abfd) - == &elf_i386_arch_bed)); - symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); @@ -1898,7 +2031,7 @@ elf_i386_check_relocs (bfd *abfd, for (rel = relocs; rel < rel_end; rel++) { unsigned int r_type; - unsigned long r_symndx; + unsigned int r_symndx; struct elf_link_hash_entry *h; struct elf_i386_link_hash_entry *eh; Elf_Internal_Sym *isym; @@ -1932,6 +2065,8 @@ elf_i386_check_relocs (bfd *abfd, goto error_return; /* Fake a STT_GNU_IFUNC symbol. */ + h->root.root.string = bfd_elf_sym_name (abfd, symtab_hdr, + isym, NULL); h->type = STT_GNU_IFUNC; h->def_regular = 1; h->ref_regular = 1; @@ -1953,32 +2088,12 @@ elf_i386_check_relocs (bfd *abfd, eh = (struct elf_i386_link_hash_entry *) h; if (h != NULL) { - switch (r_type) - { - default: - break; - - case R_386_GOTOFF: - eh->gotoff_ref = 1; - /* Fall through. */ - case R_386_32: - case R_386_PC32: - case R_386_PLT32: - case R_386_GOT32: - case R_386_GOT32X: - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - /* Create the ifunc sections for static executables. */ - if (h->type == STT_GNU_IFUNC - && !_bfd_elf_create_ifunc_sections (htab->elf.dynobj, - info)) - goto error_return; - break; - } + if (r_type == R_386_GOTOFF) + eh->gotoff_ref = 1; /* It is referenced by a non-shared object. */ h->ref_regular = 1; - h->root.non_ir_ref = 1; + h->root.non_ir_ref_regular = 1; if (h->type == STT_GNU_IFUNC) elf_tdata (info->output_bfd)->has_gnu_symbols @@ -2134,13 +2249,6 @@ elf_i386_check_relocs (bfd *abfd, case R_386_GOTOFF: case R_386_GOTPC: create_got: - if (htab->elf.sgot == NULL) - { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - if (!_bfd_elf_create_got_section (htab->elf.dynobj, info)) - goto error_return; - } if (r_type != R_386_TLS_IE) { if (eh != NULL) @@ -2195,15 +2303,10 @@ do_relocation: else if (h->type == STT_GNU_IFUNC && bfd_link_pic (info)) { - if (isym == NULL) - name = h->root.root.string; - else - name = bfd_elf_sym_name (abfd, symtab_hdr, isym, - NULL); - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unsupported non-PIC call to IFUNC `%s'"), - abfd, name); + _bfd_error_handler + /* xgettext:c-format */ + (_("%B: unsupported non-PIC call to IFUNC `%s'"), + abfd, h->root.root.string); bfd_set_error (bfd_error_bad_value); goto error_return; } @@ -2269,9 +2372,6 @@ do_size: this reloc. */ if (sreloc == NULL) { - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - sreloc = _bfd_elf_make_dynamic_reloc_section (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ FALSE); @@ -2348,58 +2448,6 @@ do_size: break; } - if (use_plt_got - && h != NULL - && h->plt.refcount > 0 - && (((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed) - || h->got.refcount > 0) - && htab->plt_got == NULL) - { - /* Create the GOT procedure linkage table. */ - unsigned int plt_got_align; - const struct elf_backend_data *bed; - - bed = get_elf_backend_data (info->output_bfd); - BFD_ASSERT (sizeof (elf_i386_got_plt_entry) == 8 - && (sizeof (elf_i386_got_plt_entry) - == sizeof (elf_i386_pic_got_plt_entry))); - plt_got_align = 3; - - if (htab->elf.dynobj == NULL) - htab->elf.dynobj = abfd; - htab->plt_got - = bfd_make_section_anyway_with_flags (htab->elf.dynobj, - ".plt.got", - (bed->dynamic_sec_flags - | SEC_ALLOC - | SEC_CODE - | SEC_LOAD - | SEC_READONLY)); - if (htab->plt_got == NULL - || !bfd_set_section_alignment (htab->elf.dynobj, - htab->plt_got, - plt_got_align)) - goto error_return; - - if (!info->no_ld_generated_unwind_info - && htab->plt_got_eh_frame == NULL - && get_elf_i386_backend_data (abfd)->plt->eh_frame_plt_got != NULL) - { - flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY - | SEC_HAS_CONTENTS | SEC_IN_MEMORY - | SEC_LINKER_CREATED); - htab->plt_got_eh_frame - = bfd_make_section_anyway_with_flags (htab->elf.dynobj, - ".eh_frame", - flags); - if (htab->plt_got_eh_frame == NULL - || !bfd_set_section_alignment (htab->elf.dynobj, - htab->plt_got_eh_frame, - 2)) - goto error_return; - } - } - if (r_type == R_386_GOT32X && (h == NULL || h->type != STT_GNU_IFUNC)) sec->need_convert_load = 1; @@ -2558,6 +2606,8 @@ 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; + /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the real definition first, and we can just use the same value. */ @@ -2567,7 +2617,9 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, || h->u.weakdef->root.type == bfd_link_hash_defweak); h->root.u.def.section = h->u.weakdef->root.u.def.section; h->root.u.def.value = h->u.weakdef->root.u.def.value; - if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) + if (ELIMINATE_COPY_RELOCS + || info->nocopyreloc + || SYMBOL_NO_COPYRELOC (info, eh)) h->non_got_ref = h->u.weakdef->non_got_ref; return TRUE; } @@ -2585,12 +2637,11 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, /* If there are no references to this symbol that do not use the GOT nor R_386_GOTOFF relocation, we don't need to generate a copy reloc. */ - eh = (struct elf_i386_link_hash_entry *) h; if (!h->non_got_ref && !eh->gotoff_ref) return TRUE; /* If -z nocopyreloc was given, we won't generate them either. */ - if (info->nocopyreloc) + if (info->nocopyreloc || SYMBOL_NO_COPYRELOC (info, eh)) { h->non_got_ref = 0; return TRUE; @@ -2607,7 +2658,7 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, relocations) in an executable. */ if (ELIMINATE_COPY_RELOCS && !eh->gotoff_ref - && !get_elf_i386_backend_data (info->output_bfd)->is_vxworks) + && get_elf_i386_backend_data (info->output_bfd)->os != is_vxworks) { for (p = eh->dyn_relocs; p != NULL; p = p->next) { @@ -2667,6 +2718,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) struct elf_dyn_relocs *p; unsigned plt_entry_size; bfd_boolean resolved_to_zero; + const struct elf_i386_backend_data *bed; if (h->root.type == bfd_link_hash_indirect) return TRUE; @@ -2678,7 +2730,9 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) if (htab == NULL) return FALSE; - plt_entry_size = GET_PLT_ENTRY_SIZE (info->output_bfd); + bed = get_elf_i386_backend_data (info->output_bfd); + + plt_entry_size = htab->plt.plt_entry_size; resolved_to_zero = UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh->has_got_reloc, @@ -2711,39 +2765,47 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) here if it is defined and referenced in a non-shared object. */ if (h->type == STT_GNU_IFUNC && h->def_regular) - return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, - &htab->readonly_dynrelocs_against_ifunc, - plt_entry_size, - plt_entry_size, 4, TRUE); + { + 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), + 4, TRUE)) + { + asection *s = htab->plt_second; + if (h->plt.offset != (bfd_vma) -1 && s != NULL) + { + /* Use the second PLT section if it is created. */ + 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; + } + + return TRUE; + } + else + return FALSE; + } /* Don't create the PLT entry if there are only function pointer relocations which can be resolved at run-time. */ else if (htab->elf.dynamic_sections_created && (h->plt.refcount > eh->func_pointer_refcount || eh->plt_got.refcount > 0)) { - bfd_boolean use_plt_got; + bfd_boolean use_plt_got = eh->plt_got.refcount > 0; /* Clear the reference count of function pointer relocations if PLT is used. */ eh->func_pointer_refcount = 0; - if ((info->flags & DF_BIND_NOW) && !h->pointer_equality_needed) - { - /* Don't use the regular PLT for DF_BIND_NOW. */ - h->plt.offset = (bfd_vma) -1; - - /* Use the GOT PLT. */ - h->got.refcount = 1; - eh->plt_got.refcount = 1; - } - - use_plt_got = eh->plt_got.refcount > 0; - /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 && !h->forced_local - && !resolved_to_zero) + && !resolved_to_zero + && h->root.type == bfd_link_hash_undefweak) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; @@ -2753,18 +2815,23 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { asection *s = htab->elf.splt; + asection *second_s = htab->plt_second; asection *got_s = htab->plt_got; /* If this is the first .plt entry, make room for the special first entry. The .plt section is used by prelink to undo prelinking for dynamic relocations. */ if (s->size == 0) - s->size = plt_entry_size; + s->size = htab->plt.has_plt0 * plt_entry_size; if (use_plt_got) eh->plt_got.offset = got_s->size; else - h->plt.offset = s->size; + { + h->plt.offset = s->size; + if (second_s) + eh->plt_second.offset = second_s->size; + } /* If this symbol is not defined in a regular file, and we are not generating a shared library, then set the symbol to this @@ -2783,17 +2850,29 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } else { - h->root.u.def.section = s; - h->root.u.def.value = h->plt.offset; + if (second_s) + { + /* We need to make a call to the entry of the + second PLT instead of regular PLT entry. */ + h->root.u.def.section = second_s; + h->root.u.def.value = eh->plt_second.offset; + } + else + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } } } /* Make room for this entry. */ if (use_plt_got) - got_s->size += sizeof (elf_i386_got_plt_entry); + got_s->size += htab->non_lazy_plt->plt_entry_size; else { s->size += plt_entry_size; + if (second_s) + second_s->size += htab->non_lazy_plt->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 @@ -2811,8 +2890,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } } - if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks - && !bfd_link_pic (info)) + if (bed->os == is_vxworks && !bfd_link_pic (info)) { /* VxWorks has a second set of relocations for each PLT entry in executables. They go in a separate relocation section, @@ -2865,7 +2943,8 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 && !h->forced_local - && !resolved_to_zero) + && !resolved_to_zero + && h->root.type == bfd_link_hash_undefweak) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; @@ -2947,7 +3026,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } } - if (get_elf_i386_backend_data (info->output_bfd)->is_vxworks) + if (bed->os == is_vxworks) { struct elf_dyn_relocs **pp; for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) @@ -3026,7 +3105,8 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) Undefined weak syms won't yet be marked as dynamic. */ if (h->dynindx == -1 && !h->forced_local - && !resolved_to_zero) + && !resolved_to_zero + && h->root.type == bfd_link_hash_undefweak) { if (! bfd_elf_link_record_dynamic_symbol (info, h)) return FALSE; @@ -3297,7 +3377,8 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) linker script /DISCARD/, so we'll be discarding the relocs too. */ } - else if (get_elf_i386_backend_data (output_bfd)->is_vxworks + else if ((get_elf_i386_backend_data (output_bfd)->os + == is_vxworks) && strcmp (p->sec->output_section->name, ".tls_vars") == 0) { @@ -3436,15 +3517,23 @@ 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 - = get_elf_i386_backend_data (output_bfd)->plt->eh_frame_plt_size; + htab->plt_eh_frame->size = htab->plt.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 - = get_elf_i386_backend_data (output_bfd)->plt->eh_frame_plt_got_size; + = htab->non_lazy_plt->eh_frame_plt_size; + + /* Unwind info for the second PLT and .plt.got sections are + identical. */ + if (htab->plt_second_eh_frame != NULL + && htab->plt_second != NULL + && 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; } /* We now have determined the sizes of the various dynamic sections. @@ -3472,9 +3561,11 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) else if (s == htab->elf.sgotplt || s == htab->elf.iplt || s == htab->elf.igotplt + || s == htab->plt_second || s == htab->plt_got || s == htab->plt_eh_frame || s == htab->plt_got_eh_frame + || s == htab->plt_second_eh_frame || s == htab->elf.sdynbss || s == htab->elf.sdynrelro) { @@ -3530,7 +3621,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, - get_elf_i386_backend_data (output_bfd)->plt->eh_frame_plt, + htab->plt.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); @@ -3540,13 +3631,24 @@ 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, - get_elf_i386_backend_data (output_bfd)->plt->eh_frame_plt_got, + htab->non_lazy_plt->eh_frame_plt, htab->plt_got_eh_frame->size); bfd_put_32 (dynobj, htab->plt_got->size, (htab->plt_got_eh_frame->contents + PLT_FDE_LEN_OFFSET)); } + if (htab->plt_second_eh_frame != NULL + && htab->plt_second_eh_frame->contents != NULL) + { + memcpy (htab->plt_second_eh_frame->contents, + htab->non_lazy_plt->eh_frame_plt, + htab->plt_second_eh_frame->size); + bfd_put_32 (dynobj, htab->plt_second->size, + (htab->plt_second_eh_frame->contents + + PLT_FDE_LEN_OFFSET)); + } + if (htab->elf.dynamic_sections_created) { /* Add some entries to the .dynamic section. We fill in the @@ -3569,14 +3671,14 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) relocation. */ if (!add_dynamic_entry (DT_PLTGOT, 0)) return FALSE; + } - if (htab->elf.srelplt->size != 0) - { - if (!add_dynamic_entry (DT_PLTRELSZ, 0) - || !add_dynamic_entry (DT_PLTREL, DT_REL) - || !add_dynamic_entry (DT_JMPREL, 0)) - return FALSE; - } + if (htab->elf.srelplt->size != 0) + { + if (!add_dynamic_entry (DT_PLTRELSZ, 0) + || !add_dynamic_entry (DT_PLTREL, DT_REL) + || !add_dynamic_entry (DT_JMPREL, 0)) + return FALSE; } if (relocs) @@ -3606,7 +3708,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) return FALSE; } } - if (get_elf_i386_backend_data (output_bfd)->is_vxworks + if (get_elf_i386_backend_data (output_bfd)->os == is_vxworks && !elf_vxworks_add_dynamic_entries (output_bfd, info)) return FALSE; } @@ -3788,14 +3890,15 @@ elf_i386_relocate_section (bfd *output_bfd, local_tlsdesc_gotents = elf_i386_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)->is_vxworks + is_vxworks_tls = ((get_elf_i386_backend_data (output_bfd)->os + == is_vxworks) && bfd_link_pic (info) && !strcmp (input_section->output_section->name, ".tls_vars")); elf_i386_set_tls_module_base (info); - plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); + plt_entry_size = htab->plt.plt_entry_size; rel = wrel = relocs; relend = relocs + input_section->reloc_count; @@ -3817,6 +3920,7 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_vma st_size; asection *resolved_plt; bfd_boolean resolved_to_zero; + bfd_boolean relative_reloc; r_type = ELF32_R_TYPE (rel->r_info); if (r_type == R_386_GNU_VTINHERIT @@ -3832,14 +3936,8 @@ elf_i386_relocate_section (bfd *output_bfd, >= R_386_ext - R_386_standard) && ((indx = r_type - R_386_tls_offset) - R_386_ext >= R_386_ext2 - R_386_ext)) - { - _bfd_error_handler - /* xgettext:c-format */ - (_("%B: unrecognized relocation (0x%x) in section `%A'"), - input_bfd, input_section, r_type); - bfd_set_error (bfd_error_bad_value); - return FALSE; - } + return _bfd_unrecognized_reloc (input_bfd, input_section, r_type); + howto = elf_howto_table + indx; r_symndx = ELF32_R_SYM (rel->r_info); @@ -3976,13 +4074,15 @@ elf_i386_relocate_section (bfd *output_bfd, continue; } + eh = (struct elf_i386_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. */ if (h != NULL && h->type == STT_GNU_IFUNC && h->def_regular) { - asection *plt, *gotplt, *base_got; + asection *gotplt, *base_got; bfd_vma plt_index; const char *name; @@ -3999,12 +4099,22 @@ elf_i386_relocate_section (bfd *output_bfd, /* STT_GNU_IFUNC symbol must go through PLT. */ if (htab->elf.splt != NULL) { - plt = htab->elf.splt; + if (htab->plt_second != NULL) + { + resolved_plt = htab->plt_second; + plt_offset = eh->plt_second.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } gotplt = htab->elf.sgotplt; } else { - plt = htab->elf.iplt; + resolved_plt = htab->elf.iplt; + plt_offset = h->plt.offset; gotplt = htab->elf.igotplt; } @@ -4032,7 +4142,8 @@ elf_i386_relocate_section (bfd *output_bfd, if (htab->elf.splt != NULL) { - plt_index = h->plt.offset / plt_entry_size - 1; + plt_index = (h->plt.offset / plt_entry_size + - htab->plt.has_plt0); off = (plt_index + 3) * 4; base_got = htab->elf.sgotplt; } @@ -4074,7 +4185,9 @@ elf_i386_relocate_section (bfd *output_bfd, - gotplt->output_section->vma - gotplt->output_offset); - if ((*(contents + rel->r_offset - 1) & 0xc7) == 0x5) + if (rel->r_offset > 1 + && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5 + && *(contents + rel->r_offset - 2) != 0x8d) { if (bfd_link_pic (info)) goto disallow_got32; @@ -4101,8 +4214,8 @@ elf_i386_relocate_section (bfd *output_bfd, goto bad_ifunc_reloc; } - relocation = (plt->output_section->vma - + plt->output_offset + h->plt.offset); + relocation = (resolved_plt->output_section->vma + + resolved_plt->output_offset + plt_offset); switch (r_type) { @@ -4150,6 +4263,10 @@ do_ifunc_pointer: || h->forced_local || bfd_link_executable (info)) { + info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), + h->root.root.string, + h->root.u.def.section->owner); + /* This symbol is resolved locally. */ outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); bfd_put_32 (output_bfd, @@ -4192,7 +4309,6 @@ do_ifunc_pointer: } } - eh = (struct elf_i386_link_hash_entry *) h; resolved_to_zero = (eh != NULL && UNDEFINED_WEAK_RESOLVED_TO_ZERO (info, eh->has_got_reloc, @@ -4243,7 +4359,8 @@ do_ifunc_pointer: + (h->got.offset & ~1) - offplt); else /* Use GOTPLT entry. */ - relocation = (h->plt.offset / plt_entry_size - 1 + 3) * 4; + relocation = (h->plt.offset / plt_entry_size + - htab->plt.has_plt0 + 3) * 4; if (!bfd_link_pic (info)) { @@ -4265,6 +4382,7 @@ r_386_got32: if (htab->elf.sgot == NULL) abort (); + relative_reloc = FALSE; if (h != NULL) { bfd_boolean dyn; @@ -4298,6 +4416,17 @@ r_386_got32: bfd_put_32 (output_bfd, relocation, htab->elf.sgot->contents + off); h->got.offset |= 1; + + if (h->dynindx == -1 + && !h->forced_local + && h->root.type != bfd_link_hash_undefweak + && bfd_link_pic (info)) + { + /* PR ld/21402: If this symbol isn't dynamic + in PIC, generate R_386_RELATIVE here. */ + eh->no_finish_dynamic_symbol = 1; + relative_reloc = TRUE; + } } } else @@ -4319,39 +4448,43 @@ r_386_got32: { bfd_put_32 (output_bfd, relocation, htab->elf.sgot->contents + off); + local_got_offsets[r_symndx] |= 1; if (bfd_link_pic (info)) - { - asection *s; - Elf_Internal_Rela outrel; - - s = htab->elf.srelgot; - if (s == NULL) - abort (); - - outrel.r_offset = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset - + off); - outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - elf_append_rel (output_bfd, s, &outrel); - } - - local_got_offsets[r_symndx] |= 1; + relative_reloc = TRUE; } } - if (off >= (bfd_vma) -2) - abort (); - - relocation = (htab->elf.sgot->output_section->vma - + htab->elf.sgot->output_offset + off); - if ((*(contents + rel->r_offset - 1) & 0xc7) == 0x5) + if (relative_reloc) { - if (bfd_link_pic (info)) - { - /* For PIC, disallow R_386_GOT32 without a base - register since we don't know what the GOT base - is. */ + asection *s; + Elf_Internal_Rela outrel; + + s = htab->elf.srelgot; + if (s == NULL) + abort (); + + outrel.r_offset = (htab->elf.sgot->output_section->vma + + htab->elf.sgot->output_offset + + off); + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + elf_append_rel (output_bfd, s, &outrel); + } + + if (off >= (bfd_vma) -2) + abort (); + + relocation = (htab->elf.sgot->output_section->vma + + htab->elf.sgot->output_offset + off); + if (rel->r_offset > 1 + && (*(contents + rel->r_offset - 1) & 0xc7) == 0x5 + && *(contents + rel->r_offset - 2) != 0x8d) + { + if (bfd_link_pic (info)) + { + /* For PIC, disallow R_386_GOT32 without a base + register, except for "lea foo@GOT, %reg", since + we don't know what the GOT base is. */ const char *name; disallow_got32: @@ -4363,7 +4496,9 @@ disallow_got32: _bfd_error_handler /* xgettext:c-format */ - (_("%B: direct GOT relocation %s against `%s' without base register can not be used when making a shared object"), + (_("%B: direct GOT relocation %s against `%s'" + " without base register can not be used" + " when making a shared object"), input_bfd, howto->name, name); bfd_set_error (bfd_error_bad_value); return FALSE; @@ -4411,7 +4546,8 @@ disallow_got32: _bfd_error_handler /* xgettext:c-format */ - (_("%B: relocation R_386_GOTOFF against undefined %s `%s' can not be used when making a shared object"), + (_("%B: relocation R_386_GOTOFF against undefined %s" + " `%s' can not be used when making a shared object"), input_bfd, v, h->root.root.string); bfd_set_error (bfd_error_bad_value); return FALSE; @@ -4423,7 +4559,8 @@ disallow_got32: { _bfd_error_handler /* xgettext:c-format */ - (_("%B: relocation R_386_GOTOFF against protected %s `%s' can not be used when making a shared object"), + (_("%B: relocation R_386_GOTOFF against protected %s" + " `%s' can not be used when making a shared object"), input_bfd, h->type == STT_FUNC ? "function" : "data", h->root.root.string); @@ -4469,8 +4606,16 @@ disallow_got32: if (h->plt.offset != (bfd_vma) -1) { - resolved_plt = htab->elf.splt; - plt_offset = h->plt.offset; + if (htab->plt_second != NULL) + { + resolved_plt = htab->plt_second; + plt_offset = eh->plt_second.offset; + } + else + { + resolved_plt = htab->elf.splt; + plt_offset = h->plt.offset; + } } else { @@ -5215,10 +5360,10 @@ disallow_got32: { _bfd_error_handler /* xgettext:c-format */ - (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), + (_("%B(%A+%#Lx): unresolvable %s relocation against symbol `%s'"), input_bfd, input_section, - (long) rel->r_offset, + rel->r_offset, howto->name, h->root.root.string); return FALSE; @@ -5255,9 +5400,9 @@ check_relocation_error: { _bfd_error_handler /* xgettext:c-format */ - (_("%B(%A+0x%lx): reloc against `%s': error %d"), + (_("%B(%A+%#Lx): reloc against `%s': error %d"), input_bfd, input_section, - (long) rel->r_offset, name, (int) r); + rel->r_offset, name, (int) r); return FALSE; } } @@ -5303,15 +5448,21 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, const struct elf_i386_backend_data *abed; struct elf_i386_link_hash_entry *eh; bfd_boolean local_undefweak; + bfd_boolean use_plt_second; htab = elf_i386_hash_table (info); if (htab == NULL) return FALSE; abed = get_elf_i386_backend_data (output_bfd); - plt_entry_size = GET_PLT_ENTRY_SIZE (output_bfd); + plt_entry_size = htab->plt.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; + 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 @@ -5322,11 +5473,11 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, if (h->plt.offset != (bfd_vma) -1) { - bfd_vma plt_index; + bfd_vma plt_index, plt_offset; bfd_vma got_offset; Elf_Internal_Rela rel; bfd_byte *loc; - asection *plt, *gotplt, *relplt; + asection *plt, *resolved_plt, *gotplt, *relplt; /* When building a static executable, use .iplt, .igot.plt and .rel.iplt sections for STT_GNU_IFUNC symbols. */ @@ -5369,7 +5520,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, if (plt == htab->elf.splt) { - got_offset = h->plt.offset / plt_entry_size - 1; + got_offset = (h->plt.offset / plt_entry_size + - htab->plt.has_plt0); got_offset = (got_offset + 3) * 4; } else @@ -5378,19 +5530,40 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, got_offset = got_offset * 4; } - /* Fill in the entry in the procedure linkage table. */ + /* Fill in the entry in the procedure linkage table and update + the first slot. */ + memcpy (plt->contents + h->plt.offset, htab->plt.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; + else + plt_entry = htab->non_lazy_plt->plt_entry; + memcpy (htab->plt_second->contents + eh->plt_second.offset, + plt_entry, htab->non_lazy_plt->plt_entry_size); + + resolved_plt = htab->plt_second; + plt_offset = eh->plt_second.offset; + } + else + { + resolved_plt = plt; + plt_offset = h->plt.offset; + } + if (! bfd_link_pic (info)) { - memcpy (plt->contents + h->plt.offset, abed->plt->plt_entry, - abed->plt->plt_entry_size); bfd_put_32 (output_bfd, (gotplt->output_section->vma + gotplt->output_offset + got_offset), - plt->contents + h->plt.offset - + abed->plt->plt_got_offset); + resolved_plt->contents + plt_offset + + htab->plt.plt_got_offset); - if (abed->is_vxworks) + if (abed->os == is_vxworks) { int s, k, reloc_index; @@ -5398,8 +5571,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, for this PLT entry. */ /* S: Current slot number (zero-based). */ - s = ((h->plt.offset - abed->plt->plt_entry_size) - / abed->plt->plt_entry_size); + s = ((h->plt.offset - htab->plt.plt_entry_size) + / htab->plt.plt_entry_size); /* K: Number of relocations for PLTResolve. */ if (bfd_link_pic (info)) k = PLTRESOLVE_RELOCS_SHLIB; @@ -5411,8 +5584,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, loc = (htab->srelplt2->contents + reloc_index * sizeof (Elf32_External_Rel)); - rel.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset + rel.r_offset = (plt->output_section->vma + + plt->output_offset + h->plt.offset + 2), rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); @@ -5429,11 +5602,9 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, } else { - memcpy (plt->contents + h->plt.offset, abed->plt->pic_plt_entry, - abed->plt->plt_entry_size); bfd_put_32 (output_bfd, got_offset, - plt->contents + h->plt.offset - + abed->plt->plt_got_offset); + resolved_plt->contents + plt_offset + + htab->plt.plt_got_offset); } /* Fill in the entry in the global offset table. Leave the entry @@ -5441,12 +5612,13 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, against undefined weak symbol in PIE. */ if (!local_undefweak) { - bfd_put_32 (output_bfd, - (plt->output_section->vma - + plt->output_offset - + h->plt.offset - + abed->plt->plt_lazy_offset), - gotplt->contents + got_offset); + if (htab->plt.has_plt0) + bfd_put_32 (output_bfd, + (plt->output_section->vma + + plt->output_offset + + h->plt.offset + + htab->lazy_plt->plt_lazy_offset), + gotplt->contents + got_offset); /* Fill in the entry in the .rel.plt section. */ rel.r_offset = (gotplt->output_section->vma @@ -5458,6 +5630,10 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, && h->def_regular && h->type == STT_GNU_IFUNC)) { + info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), + h->root.root.string, + h->root.u.def.section->owner); + /* If an STT_GNU_IFUNC symbol is locally defined, generate R_386_IRELATIVE instead of R_386_JUMP_SLOT. Store addend in the .got.plt section. */ @@ -5479,17 +5655,19 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, loc = relplt->contents + plt_index * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); - /* Don't fill PLT entry for static executables. */ - if (plt == htab->elf.splt) + /* 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) { bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), plt->contents + h->plt.offset - + abed->plt->plt_reloc_offset); - bfd_put_32 (output_bfd, - (h->plt.offset - + abed->plt->plt_plt_offset + 4), - plt->contents + h->plt.offset - + abed->plt->plt_plt_offset); + + htab->lazy_plt->plt_reloc_offset); + bfd_put_32 (output_bfd, + - (h->plt.offset + + htab->lazy_plt->plt_plt_offset + 4), + (plt->contents + h->plt.offset + + htab->lazy_plt->plt_plt_offset)); } } } @@ -5499,9 +5677,6 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, asection *plt, *got, *gotplt; const bfd_byte *got_plt_entry; - /* Offset of displacement of the indirect jump. */ - bfd_vma plt_got_offset = 2; - /* Set the entry in the GOT procedure linkage table. */ plt = htab->plt_got; got = htab->elf.sgot; @@ -5517,12 +5692,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 = elf_i386_got_plt_entry; + got_plt_entry = htab->non_lazy_plt->plt_entry; got_offset += got->output_section->vma + got->output_offset; } else { - got_plt_entry = elf_i386_pic_got_plt_entry; + got_plt_entry = htab->non_lazy_plt->pic_plt_entry; got_offset += (got->output_section->vma + got->output_offset - gotplt->output_section->vma @@ -5531,9 +5706,10 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, plt_offset = eh->plt_got.offset; memcpy (plt->contents + plt_offset, got_plt_entry, - sizeof (elf_i386_got_plt_entry)); + htab->non_lazy_plt->plt_entry_size); bfd_put_32 (output_bfd, got_offset, - plt->contents + plt_offset + plt_got_offset); + (plt->contents + plt_offset + + htab->non_lazy_plt->plt_got_offset)); } if (!local_undefweak @@ -5593,6 +5769,10 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, } if (SYMBOL_REFERENCES_LOCAL (info, h)) { + info->callbacks->minfo (_("Local IFUNC function `%s' in %B\n"), + h->root.root.string, + h->root.u.def.section->owner); + bfd_put_32 (output_bfd, (h->root.u.def.value + h->root.u.def.section->output_section->vma @@ -5611,6 +5791,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, else { asection *plt; + bfd_vma plt_offset; if (!h->pointer_equality_needed) abort (); @@ -5618,10 +5799,19 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, /* For non-shared object, we can't use .got.plt, which contains the real function addres if we need pointer equality. We load the GOT entry with the PLT entry. */ - plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; + if (htab->plt_second != NULL) + { + plt = htab->plt_second; + plt_offset = eh->plt_second.offset; + } + else + { + plt = htab->elf.splt ? htab->elf.splt : htab->elf.iplt; + plt_offset = h->plt.offset; + } bfd_put_32 (output_bfd, (plt->output_section->vma - + plt->output_offset + h->plt.offset), + + plt->output_offset + plt_offset), htab->elf.sgot->contents + h->got.offset); return TRUE; } @@ -5662,7 +5852,7 @@ do_glob_dat: + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY); - if ((h->root.u.def.section->flags & SEC_READONLY) != 0) + if (h->root.u.def.section == htab->elf.sdynrelro) s = htab->elf.sreldynrelro; else s = htab->elf.srelbss; @@ -5791,7 +5981,7 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, switch (dyn.d_tag) { default: - if (abed->is_vxworks + if (abed->os == is_vxworks && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) break; continue; @@ -5815,97 +6005,101 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); } - /* Fill in the first entry in the procedure linkage table. */ if (htab->elf.splt && htab->elf.splt->size > 0) { - if (bfd_link_pic (info)) - { - memcpy (htab->elf.splt->contents, abed->plt->pic_plt0_entry, - abed->plt->plt0_entry_size); - memset (htab->elf.splt->contents + abed->plt->plt0_entry_size, - abed->plt0_pad_byte, - abed->plt->plt_entry_size - abed->plt->plt0_entry_size); - } - else - { - memcpy (htab->elf.splt->contents, abed->plt->plt0_entry, - abed->plt->plt0_entry_size); - memset (htab->elf.splt->contents + abed->plt->plt0_entry_size, - abed->plt0_pad_byte, - abed->plt->plt_entry_size - abed->plt->plt0_entry_size); - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + 4), - htab->elf.splt->contents - + abed->plt->plt0_got1_offset); - bfd_put_32 (output_bfd, - (htab->elf.sgotplt->output_section->vma - + htab->elf.sgotplt->output_offset - + 8), - htab->elf.splt->contents - + abed->plt->plt0_got2_offset); - - if (abed->is_vxworks) - { - Elf_Internal_Rela rel; - - /* 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 - + abed->plt->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); - /* Generate a relocation for _GLOBAL_OFFSET_TABLE_ + 8. */ - rel.r_offset = (htab->elf.splt->output_section->vma - + htab->elf.splt->output_offset - + abed->plt->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 + - sizeof (Elf32_External_Rel)); - } - } - /* UnixWare sets the entsize of .plt to 4, although that doesn't really seem like the right value. */ elf_section_data (htab->elf.splt->output_section) ->this_hdr.sh_entsize = 4; - /* Correct the .rel.plt.unloaded relocations. */ - if (abed->is_vxworks && !bfd_link_pic (info)) + if (htab->plt.has_plt0) { - int num_plts = (htab->elf.splt->size - / abed->plt->plt_entry_size) - 1; - unsigned char *p; + /* 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, + abed->plt0_pad_byte, + htab->plt.plt_entry_size - htab->lazy_plt->plt0_entry_size); + if (!bfd_link_pic (info)) + { + bfd_put_32 (output_bfd, + (htab->elf.sgotplt->output_section->vma + + htab->elf.sgotplt->output_offset + + 4), + htab->elf.splt->contents + + htab->lazy_plt->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); - p = htab->srelplt2->contents; - if (bfd_link_pic (info)) - p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel); - else - p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel); + if (abed->os == is_vxworks) + { + Elf_Internal_Rela rel; + int num_plts = (htab->elf.splt->size + / htab->plt.plt_entry_size) - 1; + unsigned char *p; + + /* 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); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, + R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + htab->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); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, + R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, + htab->srelplt2->contents + + sizeof (Elf32_External_Rel)); + /* Correct the .rel.plt.unloaded relocations. */ + p = htab->srelplt2->contents; + if (bfd_link_pic (info)) + p += PLTRESOLVE_RELOCS_SHLIB * sizeof (Elf32_External_Rel); + else + p += PLTRESOLVE_RELOCS * sizeof (Elf32_External_Rel); - for (; num_plts; num_plts--) - { - Elf_Internal_Rela rel; - bfd_elf32_swap_reloc_in (output_bfd, p, &rel); - rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_386_32); - bfd_elf32_swap_reloc_out (output_bfd, &rel, p); - p += sizeof (Elf32_External_Rel); - - bfd_elf32_swap_reloc_in (output_bfd, p, &rel); - rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_386_32); - bfd_elf32_swap_reloc_out (output_bfd, &rel, p); - p += sizeof (Elf32_External_Rel); + for (; num_plts; num_plts--) + { + bfd_elf32_swap_reloc_in (output_bfd, p, &rel); + rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, + R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, p); + p += sizeof (Elf32_External_Rel); + + bfd_elf32_swap_reloc_in (output_bfd, p, &rel); + rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, + R_386_32); + bfd_elf32_swap_reloc_out (output_bfd, &rel, p); + p += sizeof (Elf32_External_Rel); + } + } } } } + + 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_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->elf.sgotplt) + /* Fill in the first three entries in the global offset table. */ + if (htab->elf.sgotplt && htab->elf.sgotplt->size > 0) { if (bfd_is_abs_section (htab->elf.sgotplt->output_section)) { @@ -5914,16 +6108,12 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, return FALSE; } - /* Fill in the first three entries in the global offset table. */ - if (htab->elf.sgotplt->size > 0) - { - bfd_put_32 (output_bfd, - (sdyn == NULL ? 0 - : sdyn->output_section->vma + sdyn->output_offset), - htab->elf.sgotplt->contents); - bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 4); - bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 8); - } + bfd_put_32 (output_bfd, + (sdyn == NULL ? 0 + : sdyn->output_section->vma + sdyn->output_offset), + htab->elf.sgotplt->contents); + bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 4); + bfd_put_32 (output_bfd, 0, htab->elf.sgotplt->contents + 8); elf_section_data (htab->elf.sgotplt->output_section)->this_hdr.sh_entsize = 4; } @@ -5983,6 +6173,35 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, } } + /* Adjust .eh_frame for the second PLT section. */ + if (htab->plt_second_eh_frame != NULL + && htab->plt_second_eh_frame->contents != NULL) + { + if (htab->plt_second != NULL + && htab->plt_second->size != 0 + && (htab->plt_second->flags & SEC_EXCLUDE) == 0 + && htab->plt_second->output_section != NULL + && htab->plt_second_eh_frame->output_section != NULL) + { + bfd_vma plt_start = htab->plt_second->output_section->vma; + bfd_vma eh_frame_start + = (htab->plt_second_eh_frame->output_section->vma + + htab->plt_second_eh_frame->output_offset + + PLT_FDE_START_OFFSET); + bfd_put_signed_32 (dynobj, plt_start - eh_frame_start, + htab->plt_second_eh_frame->contents + + PLT_FDE_START_OFFSET); + } + if (htab->plt_second_eh_frame->sec_info_type + == SEC_INFO_TYPE_EH_FRAME) + { + if (! _bfd_elf_write_section_eh_frame (output_bfd, info, + htab->plt_second_eh_frame, + htab->plt_second_eh_frame->contents)) + return FALSE; + } + } + if (htab->elf.sgot && htab->elf.sgot->size > 0) elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4; @@ -6022,96 +6241,415 @@ elf_i386_output_arch_local_syms return TRUE; } -/* Return an array of PLT entry symbol values. */ +/* Sort relocs into address order. */ -static bfd_vma * -elf_i386_get_plt_sym_val (bfd *abfd, asymbol **dynsyms, asection *plt, - asection *relplt) +static int +compare_relocs (const void *ap, const void *bp) { - bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); - arelent *p; - long count, i; - bfd_vma *plt_sym_val; - bfd_vma plt_offset; - bfd_byte *plt_contents; - const struct elf_i386_backend_data *bed - = get_elf_i386_backend_data (abfd); - Elf_Internal_Shdr *hdr; + const arelent *a = * (const arelent **) ap; + const arelent *b = * (const arelent **) bp; - /* Get the .plt section contents. */ - plt_contents = (bfd_byte *) bfd_malloc (plt->size); - if (plt_contents == NULL) - return NULL; - if (!bfd_get_section_contents (abfd, (asection *) plt, - plt_contents, 0, plt->size)) + 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, + plt_lazy = 1 << 0, + plt_pic = 1 << 1, + plt_second = 1 << 2, + plt_unknown = -1 +}; + +struct elf_i386_plt +{ + const char *name; + asection *sec; + bfd_byte *contents; + enum elf_i386_plt_type type; + unsigned int plt_got_offset; + unsigned int plt_entry_size; + long count; +}; + +/* Forward declaration. */ +static const struct elf_i386_lazy_plt_layout elf_i386_nacl_plt; + +/* Similar to _bfd_elf_get_synthetic_symtab. Support PLTs with all + dynamic relocations. */ + +static long +elf_i386_get_synthetic_symtab (bfd *abfd, + long symcount ATTRIBUTE_UNUSED, + asymbol **syms ATTRIBUTE_UNUSED, + long dynsymcount, + asymbol **dynsyms, + asymbol **ret) +{ + long size, count, i, n, len; + int j; + unsigned int plt_got_offset, plt_entry_size; + asymbol *s; + bfd_byte *plt_contents; + long dynrelcount, relsize; + arelent **dynrelbuf, *p; + const struct elf_i386_lazy_plt_layout *lazy_plt; + const struct elf_i386_non_lazy_plt_layout *non_lazy_plt; + const struct elf_i386_lazy_plt_layout *lazy_ibt_plt; + const struct elf_i386_non_lazy_plt_layout *non_lazy_ibt_plt; + asection *plt; + bfd_vma got_addr; + char *names; + enum elf_i386_plt_type plt_type; + struct elf_i386_plt plts[] = { -bad_return: - free (plt_contents); - return NULL; - } + { ".plt", NULL, NULL, plt_unknown, 0, 0, 0 }, + { ".plt.got", NULL, NULL, plt_non_lazy, 0, 0, 0 }, + { ".plt.sec", NULL, NULL, plt_second, 0, 0, 0 }, + { NULL, NULL, NULL, plt_non_lazy, 0, 0, 0 } + }; - slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; - if (! (*slurp_relocs) (abfd, relplt, dynsyms, TRUE)) - goto bad_return; + *ret = NULL; - hdr = &elf_section_data (relplt)->this_hdr; - count = relplt->size / hdr->sh_entsize; + if ((abfd->flags & (DYNAMIC | EXEC_P)) == 0) + return 0; - plt_sym_val = (bfd_vma *) bfd_malloc (sizeof (bfd_vma) * count); - if (plt_sym_val == NULL) - goto bad_return; + if (dynsymcount <= 0) + return 0; - for (i = 0; i < count; i++) - plt_sym_val[i] = -1; + relsize = bfd_get_dynamic_reloc_upper_bound (abfd); + if (relsize <= 0) + return -1; - plt_offset = bed->plt->plt_entry_size; - p = relplt->relocation; - for (i = 0; i < count; i++, p++) + non_lazy_plt = NULL; + /* Silence GCC 6. */ + lazy_plt = NULL; + non_lazy_ibt_plt = NULL; + lazy_ibt_plt = NULL; + switch (get_elf_i386_backend_data (abfd)->os) { - long reloc_index; + case is_normal: + non_lazy_plt = &elf_i386_non_lazy_plt; + lazy_ibt_plt = &elf_i386_lazy_ibt_plt; + non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt; + /* Fall through */ + case is_vxworks: + lazy_plt = &elf_i386_lazy_plt; + break; + case is_nacl: + lazy_plt = &elf_i386_nacl_plt; + break; + } - /* Skip unknown relocation. PR 17512: file: bc9d6cf5. */ - if (p->howto == NULL) - continue; + got_addr = 0; - if (p->howto->type != R_386_JUMP_SLOT - && p->howto->type != R_386_IRELATIVE) + count = 0; + for (j = 0; plts[j].name != NULL; j++) + { + plt = bfd_get_section_by_name (abfd, plts[j].name); + if (plt == NULL || plt->size == 0) continue; - reloc_index = H_GET_32 (abfd, (plt_contents + plt_offset - + bed->plt->plt_reloc_offset)); - reloc_index /= sizeof (Elf32_External_Rel); - if (reloc_index < count) - plt_sym_val[reloc_index] = plt->vma + plt_offset; + /* Get the PLT section contents. */ + plt_contents = (bfd_byte *) bfd_malloc (plt->size); + if (plt_contents == NULL) + break; + if (!bfd_get_section_contents (abfd, (asection *) plt, + plt_contents, 0, plt->size)) + { + free (plt_contents); + break; + } - plt_offset += bed->plt->plt_entry_size; + /* Check what kind of PLT it is. */ + plt_type = plt_unknown; + if (plts[j].type == plt_unknown + && (plt->size >= (lazy_plt->plt0_entry_size + + lazy_plt->plt_entry_size))) + { + /* Match lazy PLT first. */ + if (memcmp (plt_contents, lazy_plt->plt0_entry, + lazy_plt->plt0_got1_offset) == 0) + { + /* The fist entry in the lazy IBT PLT is the same as the + normal lazy PLT. */ + if (lazy_ibt_plt != NULL + && (memcmp (plt_contents + lazy_ibt_plt->plt0_entry_size, + lazy_ibt_plt->plt_entry, + lazy_ibt_plt->plt_got_offset) == 0)) + plt_type = plt_lazy | plt_second; + else + plt_type = plt_lazy; + } + else if (memcmp (plt_contents, lazy_plt->pic_plt0_entry, + lazy_plt->plt0_got1_offset) == 0) + { + /* The fist entry in the PIC lazy IBT PLT is the same as + the normal PIC lazy PLT. */ + if (lazy_ibt_plt != NULL + && (memcmp (plt_contents + lazy_ibt_plt->plt0_entry_size, + lazy_ibt_plt->pic_plt_entry, + lazy_ibt_plt->plt_got_offset) == 0)) + plt_type = plt_lazy | plt_pic | plt_second; + else + plt_type = plt_lazy | plt_pic; + } + } - /* PR binutils/18437: Skip extra relocations in the .rel.plt - section. */ - if (plt_offset >= plt->size) - break; + if (non_lazy_plt != NULL + && (plt_type == plt_unknown || plt_type == plt_non_lazy) + && plt->size >= non_lazy_plt->plt_entry_size) + { + /* Match non-lazy PLT. */ + if (memcmp (plt_contents, non_lazy_plt->plt_entry, + non_lazy_plt->plt_got_offset) == 0) + plt_type = plt_non_lazy; + else if (memcmp (plt_contents, non_lazy_plt->pic_plt_entry, + non_lazy_plt->plt_got_offset) == 0) + plt_type = plt_pic; + } + + if ((non_lazy_ibt_plt != NULL) + && (plt_type == plt_unknown || plt_type == plt_second) + && plt->size >= non_lazy_ibt_plt->plt_entry_size) + { + if (memcmp (plt_contents, + non_lazy_ibt_plt->plt_entry, + non_lazy_ibt_plt->plt_got_offset) == 0) + { + /* Match IBT PLT. */ + plt_type = plt_second; + non_lazy_plt = non_lazy_ibt_plt; + } + else if (memcmp (plt_contents, + non_lazy_ibt_plt->pic_plt_entry, + non_lazy_ibt_plt->plt_got_offset) == 0) + { + /* Match PIC IBT PLT. */ + plt_type = plt_second | plt_pic; + non_lazy_plt = non_lazy_ibt_plt; + } + } + + if (plt_type == plt_unknown) + { + free (plt_contents); + continue; + } + + plts[j].sec = plt; + plts[j].type = plt_type; + + if ((plt_type & plt_lazy)) + { + plts[j].plt_got_offset = lazy_plt->plt_got_offset; + plts[j].plt_entry_size = lazy_plt->plt_entry_size; + /* Skip PLT0 in lazy PLT. */ + i = 1; + } + else + { + plts[j].plt_got_offset = non_lazy_plt->plt_got_offset; + plts[j].plt_entry_size = non_lazy_plt->plt_entry_size; + i = 0; + } + + /* Skip lazy PLT when the second PLT is used. */ + if ((plt_type & (plt_lazy | plt_second)) + == (plt_lazy | plt_second)) + plts[j].count = 0; + else + { + n = plt->size / plts[j].plt_entry_size; + plts[j].count = n; + count += n - i; + } + + plts[j].contents = plt_contents; + + /* The _GLOBAL_OFFSET_TABLE_ address is needed. */ + if ((plt_type & plt_pic)) + got_addr = (bfd_vma) -1; } - free (plt_contents); + if (count == 0) + return -1; - return plt_sym_val; -} + dynrelbuf = (arelent **) bfd_malloc (relsize); + if (dynrelbuf == NULL) + return -1; -/* Similar to _bfd_elf_get_synthetic_symtab. */ + dynrelcount = bfd_canonicalize_dynamic_reloc (abfd, dynrelbuf, + dynsyms); -static long -elf_i386_get_synthetic_symtab (bfd *abfd, - long symcount, - asymbol **syms, - long dynsymcount, - asymbol **dynsyms, - asymbol **ret) -{ - asection *plt = bfd_get_section_by_name (abfd, ".plt"); - return _bfd_elf_ifunc_get_synthetic_symtab (abfd, symcount, syms, - dynsymcount, dynsyms, ret, - plt, - elf_i386_get_plt_sym_val); + /* Sort the relocs by address. */ + qsort (dynrelbuf, dynrelcount, sizeof (arelent *), compare_relocs); + + size = count * sizeof (asymbol); + + /* Allocate space for @plt suffixes. */ + n = 0; + for (i = 0; i < dynrelcount; i++) + { + p = dynrelbuf[i]; + size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt"); + if (p->addend != 0) + size += sizeof ("+0x") - 1 + 8; + } + + s = *ret = (asymbol *) bfd_zmalloc (size); + if (s == NULL) + { +bad_return: + for (j = 0; plts[j].name != NULL; j++) + if (plts[j].contents != NULL) + free (plts[j].contents); + free (dynrelbuf); + return -1; + } + + if (got_addr) + { + /* Check .got.plt and then .got to get the _GLOBAL_OFFSET_TABLE_ + address. */ + asection *sec = bfd_get_section_by_name (abfd, ".got.plt"); + if (sec != NULL) + got_addr = sec->vma; + else + { + sec = bfd_get_section_by_name (abfd, ".got"); + if (sec != NULL) + got_addr = sec->vma; + } + + if (got_addr == (bfd_vma) -1) + goto bad_return; + } + + /* Check for each PLT section. */ + names = (char *) (s + count); + size = 0; + n = 0; + for (j = 0; plts[j].name != NULL; j++) + if ((plt_contents = plts[j].contents) != NULL) + { + long k; + bfd_vma offset; + + plt_got_offset = plts[j].plt_got_offset; + plt_entry_size = plts[j].plt_entry_size; + + plt = plts[j].sec; + + if ((plts[j].type & plt_lazy)) + { + /* Skip PLT0 in lazy PLT. */ + k = 1; + offset = plt_entry_size; + } + else + { + k = 0; + offset = 0; + } + + /* Check each PLT entry against dynamic relocations. */ + for (; k < plts[j].count; k++) + { + int off; + bfd_vma got_vma; + long min, max, mid; + + /* Get the GOT offset, a signed 32-bit integer. */ + off = H_GET_32 (abfd, (plt_contents + offset + + plt_got_offset)); + got_vma = got_addr + off; + + /* Binary search. */ + p = dynrelbuf[0]; + min = 0; + max = dynrelcount; + while ((min + 1) < max) + { + arelent *r; + + mid = (min + max) / 2; + r = dynrelbuf[mid]; + if (got_vma > r->address) + min = mid; + else if (got_vma < r->address) + max = mid; + else + { + p = r; + break; + } + } + + /* Skip unknown relocation. PR 17512: file: bc9d6cf5. */ + if (got_vma == p->address + && p->howto != NULL + && (p->howto->type == R_386_JUMP_SLOT + || p->howto->type == R_386_GLOB_DAT + || p->howto->type == R_386_IRELATIVE)) + { + *s = **p->sym_ptr_ptr; + /* Undefined syms won't have BSF_LOCAL or BSF_GLOBAL + set. Since we are defining a symbol, ensure one + of them is set. */ + if ((s->flags & BSF_LOCAL) == 0) + s->flags |= BSF_GLOBAL; + s->flags |= BSF_SYNTHETIC; + /* This is no longer a section symbol. */ + s->flags &= ~BSF_SECTION_SYM; + s->section = plt; + s->the_bfd = plt->owner; + s->value = offset; + s->udata.p = NULL; + s->name = names; + len = strlen ((*p->sym_ptr_ptr)->name); + memcpy (names, (*p->sym_ptr_ptr)->name, len); + names += len; + if (p->addend != 0) + { + char buf[30], *a; + + memcpy (names, "+0x", sizeof ("+0x") - 1); + names += sizeof ("+0x") - 1; + bfd_sprintf_vma (abfd, buf, p->addend); + for (a = buf; *a == '0'; ++a) + ; + size = strlen (a); + memcpy (names, a, size); + names += size; + } + memcpy (names, "@plt", sizeof ("@plt")); + names += sizeof ("@plt"); + n++; + s++; + } + offset += plt_entry_size; + } + } + + /* PLT entries with R_386_TLS_DESC relocations are skipped. */ + if (n == 0) + goto bad_return; + + count = n; + + for (j = 0; plts[j].name != NULL; j++) + if (plts[j].contents != NULL) + free (plts[j].contents); + + free (dynrelbuf); + + return count; } /* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ @@ -6127,6 +6665,519 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h) 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: ") + : (type == GNU_PROPERTY_X86_ISA_1_NEEDED + ? _("error: %B: ") + : _("error: %B: "))), + 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. */ + +static bfd * +elf_i386_link_setup_gnu_properties (struct bfd_link_info *info) +{ + bfd_boolean normal_target; + bfd_boolean lazy_plt; + asection *sec, *pltsec; + bfd *dynobj; + bfd_boolean use_ibt_plt; + unsigned int plt_alignment, features; + struct elf_i386_link_hash_table *htab; + bfd *pbfd; + bfd *ebfd = NULL; + elf_property *prop; + + features = 0; + if (info->ibt) + features = GNU_PROPERTY_X86_FEATURE_1_IBT; + if (info->shstk) + features |= GNU_PROPERTY_X86_FEATURE_1_SHSTK; + + /* Find a normal input file with GNU property note. */ + for (pbfd = info->input_bfds; + pbfd != NULL; + pbfd = pbfd->link.next) + if (bfd_get_flavour (pbfd) == bfd_target_elf_flavour + && bfd_count_sections (pbfd) != 0) + { + ebfd = pbfd; + + if (elf_properties (pbfd) != NULL) + break; + } + + if (ebfd != NULL && features) + { + /* If features is set, add GNU_PROPERTY_X86_FEATURE_1_IBT and + GNU_PROPERTY_X86_FEATURE_1_SHSTK. */ + prop = _bfd_elf_get_property (ebfd, + GNU_PROPERTY_X86_FEATURE_1_AND, + 4); + prop->u.number |= features; + prop->pr_kind = property_number; + + /* Create the GNU property note section if needed. */ + if (pbfd == NULL) + { + sec = bfd_make_section_with_flags (ebfd, + NOTE_GNU_PROPERTY_SECTION_NAME, + (SEC_ALLOC + | SEC_LOAD + | SEC_IN_MEMORY + | SEC_READONLY + | SEC_HAS_CONTENTS + | SEC_DATA)); + if (sec == NULL) + info->callbacks->einfo (_("%F: failed to create GNU property section\n")); + + if (!bfd_set_section_alignment (ebfd, sec, 2)) + { +error_alignment: + info->callbacks->einfo (_("%F%A: failed to align section\n"), + sec); + } + + elf_section_type (sec) = SHT_NOTE; + } + } + + pbfd = _bfd_elf_link_setup_gnu_properties (info); + + if (bfd_link_relocatable (info)) + return pbfd; + + htab = elf_i386_hash_table (info); + if (htab == NULL) + return pbfd; + + use_ibt_plt = info->ibtplt || info->ibt; + if (!use_ibt_plt && pbfd != NULL) + { + /* Check if GNU_PROPERTY_X86_FEATURE_1_IBT is on. */ + elf_property_list *p; + + /* The property list is sorted in order of type. */ + for (p = elf_properties (pbfd); p; p = p->next) + { + if (GNU_PROPERTY_X86_FEATURE_1_AND == p->property.pr_type) + { + use_ibt_plt = !!(p->property.u.number + & GNU_PROPERTY_X86_FEATURE_1_IBT); + break; + } + else if (GNU_PROPERTY_X86_FEATURE_1_AND < p->property.pr_type) + break; + } + } + + dynobj = htab->elf.dynobj; + + /* Set htab->elf.dynobj here so that there is no need to check and + set it in check_relocs. */ + if (dynobj == NULL) + { + if (pbfd != NULL) + { + htab->elf.dynobj = pbfd; + dynobj = pbfd; + } + else + { + bfd *abfd; + + /* Find a normal input file to hold linker created + sections. */ + for (abfd = info->input_bfds; + abfd != NULL; + abfd = abfd->link.next) + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour + && (abfd->flags + & (DYNAMIC | BFD_LINKER_CREATED | BFD_PLUGIN)) == 0) + { + htab->elf.dynobj = abfd; + dynobj = abfd; + break; + } + } + } + + /* 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; + normal_target = FALSE; + + switch (get_elf_i386_backend_data (info->output_bfd)->os) + { + 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; + } + else + { + htab->lazy_plt = &elf_i386_lazy_plt; + htab->non_lazy_plt = &elf_i386_non_lazy_plt; + } + normal_target = TRUE; + break; + case is_vxworks: + htab->lazy_plt = &elf_i386_lazy_plt; + htab->non_lazy_plt = NULL; + if (!elf_vxworks_create_dynamic_sections (dynobj, info, + &htab->srelplt2)) + 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; + break; + } + + 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)) + { + lazy_plt = FALSE; + if (bfd_link_pic (info)) + htab->plt.plt_entry + = htab->non_lazy_plt->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; + } + 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; + } + else + { + htab->plt.plt0_entry + = htab->lazy_plt->plt0_entry; + 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.eh_frame_plt_size + = htab->lazy_plt->eh_frame_plt_size; + htab->plt.eh_frame_plt + = htab->lazy_plt->eh_frame_plt; + } + + /* Return if there are no normal input files. */ + if (dynobj == NULL) + return pbfd; + + /* Since create_dynamic_sections isn't always called, but GOT + relocations need GOT sections, create them here so that we + don't need to do it in check_relocs. */ + if (htab->elf.sgot == NULL + && !_bfd_elf_create_got_section (dynobj, info)) + info->callbacks->einfo (_("%F: failed to create GOT sections\n")); + + /* Create the ifunc sections here so that check_relocs can be + simplified. */ + 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); + + if (pltsec != NULL) + { + /* Whe creating executable, set the contents of the .interp + section to the interpreter. */ + if (bfd_link_executable (info) && !info->nointerp) + { + 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; + htab->interp = s; + } + + /* Don't change PLT section alignment for NaCl since it uses + 64-byte PLT entry and sets PLT section alignment to 32 + bytes. */ + if (normal_target) + { + const struct elf_backend_data *bed + = get_elf_backend_data (dynobj); + flagword pltflags = (bed->dynamic_sec_flags + | SEC_ALLOC + | SEC_CODE + | SEC_LOAD + | SEC_READONLY); + unsigned int non_lazy_plt_alignment + = bfd_log2 (htab->non_lazy_plt->plt_entry_size); + + sec = pltsec; + if (!bfd_set_section_alignment (sec->owner, sec, + plt_alignment)) + goto error_alignment; + + /* Create the GOT procedure linkage table. */ + sec = bfd_make_section_anyway_with_flags (dynobj, + ".plt.got", + pltflags); + if (sec == NULL) + info->callbacks->einfo (_("%F: failed to create GOT PLT section\n")); + + if (!bfd_set_section_alignment (dynobj, sec, + non_lazy_plt_alignment)) + goto error_alignment; + + htab->plt_got = sec; + + if (lazy_plt) + { + sec = NULL; + + if (use_ibt_plt) + { + /* Create the second PLT for Intel IBT support. IBT + PLT is supported only for non-NaCl target and is + is needed only for lazy binding. */ + sec = bfd_make_section_anyway_with_flags (dynobj, + ".plt.sec", + pltflags); + if (sec == NULL) + info->callbacks->einfo (_("%F: failed to create IBT-enabled PLT section\n")); + + if (!bfd_set_section_alignment (dynobj, sec, + plt_alignment)) + goto error_alignment; + } + + htab->plt_second = sec; + } + } + + if (!info->no_ld_generated_unwind_info) + { + flagword flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY + | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED); + + sec = bfd_make_section_anyway_with_flags (dynobj, + ".eh_frame", + flags); + if (sec == NULL) + info->callbacks->einfo (_("%F: failed to create PLT .eh_frame section\n")); + + if (!bfd_set_section_alignment (dynobj, sec, 2)) + goto error_alignment; + + htab->plt_eh_frame = sec; + + if (htab->plt_got != NULL) + { + sec = bfd_make_section_anyway_with_flags (dynobj, + ".eh_frame", + flags); + if (sec == NULL) + info->callbacks->einfo (_("%F: failed to create GOT PLT .eh_frame section\n")); + + if (!bfd_set_section_alignment (dynobj, sec, 2)) + goto error_alignment; + + htab->plt_got_eh_frame = sec; + } + } + } + + if (normal_target) + { + /* The .iplt section is used for IFUNC symbols in static + executables. */ + sec = htab->elf.iplt; + if (sec != NULL + && !bfd_set_section_alignment (sec->owner, sec, + plt_alignment)) + goto 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 @@ -6157,12 +7208,13 @@ elf_i386_hash_symbol (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 elf_i386_create_dynamic_sections +#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 #define elf_backend_finish_dynamic_symbol elf_i386_finish_dynamic_symbol @@ -6178,6 +7230,10 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h) ((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" @@ -6510,7 +7566,7 @@ static const bfd_byte elf_i386_nacl_eh_frame_plt[] = DW_CFA_nop, DW_CFA_nop }; -static const struct elf_i386_plt_layout elf_i386_nacl_plt = +static const struct elf_i386_lazy_plt_layout elf_i386_nacl_plt = { elf_i386_nacl_plt0_entry, /* plt0_entry */ sizeof (elf_i386_nacl_plt0_entry), /* plt0_entry_size */ @@ -6525,16 +7581,13 @@ static const struct elf_i386_plt_layout elf_i386_nacl_plt = elf_i386_nacl_pic_plt0_entry, /* pic_plt0_entry */ elf_i386_nacl_pic_plt_entry, /* pic_plt_entry */ elf_i386_nacl_eh_frame_plt, /* eh_frame_plt */ - sizeof (elf_i386_nacl_eh_frame_plt),/* eh_frame_plt_size */ - NULL, /* eh_frame_plt_got */ - 0, /* eh_frame_plt_got_size */ + sizeof (elf_i386_nacl_eh_frame_plt) /* eh_frame_plt_size */ }; static const struct elf_i386_backend_data elf_i386_nacl_arch_bed = { - &elf_i386_nacl_plt, /* plt */ - 0x90, /* plt0_pad_byte: nop insn */ - 0, /* is_vxworks */ + 0x90, /* plt0_pad_byte: nop insn */ + is_nacl /* os */ }; static bfd_boolean @@ -6572,14 +7625,15 @@ elf32_i386_nacl_elf_object_p (bfd *abfd) #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-vxworks" #undef ELF_OSABI +#undef ELF_MAXPAGESIZE +#define ELF_MAXPAGESIZE 0x1000 #undef elf_backend_plt_alignment #define elf_backend_plt_alignment 4 static const struct elf_i386_backend_data elf_i386_vxworks_arch_bed = { - &elf_i386_plt, /* plt */ 0x90, /* plt0_pad_byte */ - 1, /* is_vxworks */ + is_vxworks /* os */ }; #undef elf_backend_arch_data