diff options
-rw-r--r-- | bfd/ChangeLog | 25 | ||||
-rw-r--r-- | bfd/elf32-i386.c | 355 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 410 | ||||
-rw-r--r-- | bfd/elfxx-x86.c | 390 | ||||
-rw-r--r-- | bfd/elfxx-x86.h | 31 |
5 files changed, 494 insertions, 717 deletions
diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 20bdf16..cf2c530 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,30 @@ 2017-09-01 H.J. Lu <hongjiu.lu@intel.com> + * elf32-i386.c (elf_i386_link_setup_gnu_properties): Updated. + Call _bfd_x86_elf_link_setup_gnu_properties. + * elf64-x86-64.c (elf_x86_lazy_plt_layout): Initialize + pic_plt0_entry and pic_plt_entry fields with the non-PIC PLT + entries. + (elf_x86_64_non_lazy_plt): Likewise. + (elf_x86_64_lazy_bnd_plt): Likewise. + (elf_x86_64_non_lazy_bnd_plt): Likewise. + (elf_x86_64_lazy_ibt_plt): Likewise. + (elf_x32_lazy_ibt_plt): Likewise. + (elf_x86_64_non_lazy_ibt_plt): Likewise. + (elf_x32_non_lazy_ibt_plt): Likewise. + (elf_x86_64_nacl_plt): Likewise. + (elf_x86_64_link_setup_gnu_properties): Updated. Call + _bfd_x86_elf_link_setup_gnu_properties. + * elfxx-x86.c: Include elf-vxworks.h". + (_bfd_x86_elf_link_setup_gnu_properties): New function. + * elfxx-x86.h (elf_x86_lazy_plt_layout): Remove "for i386 only" + comments for pic_plt0_entry and pic_plt_entry. + (elf_x86_non_lazy_plt_layout): Likewise. + (elf_x86_plt_layout_table): New. + (_bfd_x86_elf_link_setup_gnu_properties): Likewise. + +2017-09-01 H.J. Lu <hongjiu.lu@intel.com> + PR ld/22061 * elf32-i386.c (elf_i386_link_setup_gnu_properties): Create .eh_frame section for the second PLT. diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index a983301..a0d4285 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -5825,354 +5825,35 @@ elf_i386_get_synthetic_symtab (bfd *abfd, 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_x86_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_x86_hash_table (info, I386_ELF_DATA); - 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; + struct elf_x86_plt_layout_table plt_layout; + plt_layout.normal_target = FALSE; + plt_layout.is_vxworks = 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; + plt_layout.lazy_plt = &elf_i386_lazy_plt; + plt_layout.non_lazy_plt = &elf_i386_non_lazy_plt; + plt_layout.lazy_ibt_plt = &elf_i386_lazy_ibt_plt; + plt_layout.non_lazy_ibt_plt = &elf_i386_non_lazy_ibt_plt; + plt_layout.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")); + plt_layout.lazy_plt = &elf_i386_lazy_plt; + plt_layout.non_lazy_plt = NULL; + plt_layout.lazy_ibt_plt = NULL; + plt_layout.non_lazy_ibt_plt = NULL; + plt_layout.is_vxworks = TRUE; break; case is_nacl: - htab->lazy_plt = &elf_i386_nacl_plt; - htab->non_lazy_plt = NULL; + plt_layout.lazy_plt = &elf_i386_nacl_plt; + plt_layout.non_lazy_plt = NULL; + plt_layout.lazy_ibt_plt = NULL; + plt_layout.non_lazy_ibt_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; - } - - /* This is unused for i386. */ - htab->plt.plt_got_insn_size = 0; - - /* 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 = htab->dynamic_interpreter_size; - s->contents = (unsigned char *) htab->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 (htab->plt_second != NULL) - { - sec = bfd_make_section_anyway_with_flags (dynobj, - ".eh_frame", - flags); - if (sec == NULL) - info->callbacks->einfo (_("%F: failed to create the second PLT .eh_frame section\n")); - - if (!bfd_set_section_alignment (dynobj, sec, 2)) - goto error_alignment; - - htab->plt_second_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; + return _bfd_x86_elf_link_setup_gnu_properties (info, &plt_layout); } #define TARGET_LITTLE_SYM i386_elf32_vec diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index 969a053..547173b 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -848,8 +848,8 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_plt = 6, /* plt_got_insn_size */ LAZY_PLT_ENTRY_SIZE, /* plt_plt_insn_end */ 6, /* plt_lazy_offset */ - NULL, /* pic_plt0_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_lazy_plt0_entry, /* pic_plt0_entry */ + elf_x86_64_lazy_plt_entry, /* pic_plt_entry */ elf_x86_64_eh_frame_lazy_plt, /* eh_frame_plt */ sizeof (elf_x86_64_eh_frame_lazy_plt) /* eh_frame_plt_size */ }; @@ -857,7 +857,7 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_plt = static const struct elf_x86_non_lazy_plt_layout elf_x86_64_non_lazy_plt = { elf_x86_64_non_lazy_plt_entry, /* plt_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_non_lazy_plt_entry, /* pic_plt_entry */ NON_LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ 2, /* plt_got_offset */ 6, /* plt_got_insn_size */ @@ -880,8 +880,8 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_bnd_plt = 1+6, /* plt_got_insn_size */ 11, /* plt_plt_insn_end */ 0, /* plt_lazy_offset */ - NULL, /* pic_plt0_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_lazy_bnd_plt0_entry, /* pic_plt0_entry */ + elf_x86_64_lazy_bnd_plt_entry, /* pic_plt_entry */ elf_x86_64_eh_frame_lazy_bnd_plt, /* eh_frame_plt */ sizeof (elf_x86_64_eh_frame_lazy_bnd_plt) /* eh_frame_plt_size */ }; @@ -889,7 +889,7 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_bnd_plt = static const struct elf_x86_non_lazy_plt_layout elf_x86_64_non_lazy_bnd_plt = { elf_x86_64_non_lazy_bnd_plt_entry, /* plt_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_non_lazy_bnd_plt_entry, /* pic_plt_entry */ NON_LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ 1+2, /* plt_got_offset */ 1+6, /* plt_got_insn_size */ @@ -912,8 +912,8 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_lazy_ibt_plt = 4+1+6, /* plt_got_insn_size */ 4+1+5+5, /* plt_plt_insn_end */ 0, /* plt_lazy_offset */ - NULL, /* pic_plt0_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_lazy_bnd_plt0_entry, /* pic_plt0_entry */ + elf_x86_64_lazy_ibt_plt_entry, /* pic_plt_entry */ elf_x86_64_eh_frame_lazy_ibt_plt, /* eh_frame_plt */ sizeof (elf_x86_64_eh_frame_lazy_ibt_plt) /* eh_frame_plt_size */ }; @@ -933,8 +933,8 @@ static const struct elf_x86_lazy_plt_layout elf_x32_lazy_ibt_plt = 4+6, /* plt_got_insn_size */ 4+5+5, /* plt_plt_insn_end */ 0, /* plt_lazy_offset */ - NULL, /* pic_plt0_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_lazy_plt0_entry, /* pic_plt0_entry */ + elf_x32_lazy_ibt_plt_entry, /* pic_plt_entry */ elf_x32_eh_frame_lazy_ibt_plt, /* eh_frame_plt */ sizeof (elf_x32_eh_frame_lazy_ibt_plt) /* eh_frame_plt_size */ }; @@ -942,7 +942,7 @@ static const struct elf_x86_lazy_plt_layout elf_x32_lazy_ibt_plt = static const struct elf_x86_non_lazy_plt_layout elf_x86_64_non_lazy_ibt_plt = { elf_x86_64_non_lazy_ibt_plt_entry, /* plt_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_non_lazy_ibt_plt_entry, /* pic_plt_entry */ LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ 4+1+2, /* plt_got_offset */ 4+1+6, /* plt_got_insn_size */ @@ -953,7 +953,7 @@ static const struct elf_x86_non_lazy_plt_layout elf_x86_64_non_lazy_ibt_plt = static const struct elf_x86_non_lazy_plt_layout elf_x32_non_lazy_ibt_plt = { elf_x32_non_lazy_ibt_plt_entry, /* plt_entry */ - NULL, /* pic_plt_entry */ + elf_x32_non_lazy_ibt_plt_entry, /* pic_plt_entry */ LAZY_PLT_ENTRY_SIZE, /* plt_entry_size */ 4+2, /* plt_got_offset */ 4+6, /* plt_got_insn_size */ @@ -6380,386 +6380,44 @@ elf_x86_64_relocs_compatible (const bfd_target *input, static bfd * elf_x86_64_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_x86_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; - } + struct elf_x86_plt_layout_table plt_layout; - if (ebfd != NULL && features) + plt_layout.is_vxworks = FALSE; + if (get_elf_x86_64_backend_data (info->output_bfd)->os == is_normal) { - /* 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) + if (info->bndplt) { - 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, - ABI_64_P (ebfd) ? 3 : 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_x86_hash_table (info, X86_64_ELF_DATA); - 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; + plt_layout.lazy_plt = &elf_x86_64_lazy_bnd_plt; + plt_layout.non_lazy_plt = &elf_x86_64_non_lazy_bnd_plt; } 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; - } + plt_layout.lazy_plt = &elf_x86_64_lazy_plt; + plt_layout.non_lazy_plt = &elf_x86_64_non_lazy_plt; } - } - - /* 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; - if (get_elf_x86_64_backend_data (info->output_bfd)->os - == is_normal) - { - if (use_ibt_plt) - { - if (ABI_64_P (dynobj)) - { - htab->lazy_plt - = &elf_x86_64_lazy_ibt_plt; - htab->non_lazy_plt - = &elf_x86_64_non_lazy_ibt_plt; - } - else - { - htab->lazy_plt - = &elf_x32_lazy_ibt_plt; - htab->non_lazy_plt - = &elf_x32_non_lazy_ibt_plt; - } - } - else if (info->bndplt) + if (ABI_64_P (info->output_bfd)) { - htab->lazy_plt = &elf_x86_64_lazy_bnd_plt; - htab->non_lazy_plt = &elf_x86_64_non_lazy_bnd_plt; + plt_layout.lazy_ibt_plt = &elf_x86_64_lazy_ibt_plt; + plt_layout.non_lazy_ibt_plt = &elf_x86_64_non_lazy_ibt_plt; } else { - htab->lazy_plt = &elf_x86_64_lazy_plt; - htab->non_lazy_plt = &elf_x86_64_non_lazy_plt; + plt_layout.lazy_ibt_plt = &elf_x32_lazy_ibt_plt; + plt_layout.non_lazy_ibt_plt = &elf_x32_non_lazy_ibt_plt; } - normal_target = TRUE; + plt_layout.normal_target = TRUE; } else { - htab->lazy_plt = &elf_x86_64_nacl_plt; - htab->non_lazy_plt = NULL; - normal_target = FALSE; - } - - 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; - htab->plt.plt_entry = htab->non_lazy_plt->plt_entry; - htab->plt.plt_entry_size = htab->non_lazy_plt->plt_entry_size; - htab->plt.plt_got_offset = htab->non_lazy_plt->plt_got_offset; - htab->plt.plt_got_insn_size - = htab->non_lazy_plt->plt_got_insn_size; - htab->plt.eh_frame_plt_size - = htab->non_lazy_plt->eh_frame_plt_size; - htab->plt.eh_frame_plt = htab->non_lazy_plt->eh_frame_plt; - } - else - { - lazy_plt = TRUE; - htab->plt.plt_entry = htab->lazy_plt->plt_entry; - htab->plt.plt_entry_size = htab->lazy_plt->plt_entry_size; - htab->plt.plt_got_offset = htab->lazy_plt->plt_got_offset; - htab->plt.plt_got_insn_size - = htab->lazy_plt->plt_got_insn_size; - htab->plt.eh_frame_plt_size - = htab->lazy_plt->eh_frame_plt_size; - htab->plt.eh_frame_plt = htab->lazy_plt->eh_frame_plt; - } - - /* This is unused for x86-64. */ - htab->plt.plt0_entry = NULL; - - /* 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 relocations, 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")); - - /* Align .got and .got.plt sections to their entry size. Do it here - instead of in create_dynamic_sections so that they are always - properly aligned even if create_dynamic_sections isn't called. */ - sec = htab->elf.sgot; - if (!bfd_set_section_alignment (dynobj, sec, 3)) - goto error_alignment; - - sec = htab->elf.sgotplt; - if (!bfd_set_section_alignment (dynobj, sec, 3)) - goto error_alignment; - - /* 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 = htab->dynamic_interpreter_size; - s->contents = (unsigned char *) htab->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. Don't create additional PLT sections for NaCl. */ - 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; - } - else if (info->bndplt && ABI_64_P (dynobj)) - { - /* Create the second PLT for Intel MPX support. MPX - PLT is supported only for non-NaCl target in 64-bit - mode and 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 BND PLT section\n")); - - if (!bfd_set_section_alignment (dynobj, sec, - non_lazy_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, - ABI_64_P (dynobj) ? 3 : 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, - ABI_64_P (dynobj) ? 3 : 2)) - goto error_alignment; - - htab->plt_got_eh_frame = sec; - } - - if (htab->plt_second != NULL) - { - sec = bfd_make_section_anyway_with_flags (dynobj, - ".eh_frame", - flags); - if (sec == NULL) - info->callbacks->einfo (_("%F: failed to create the second PLT .eh_frame section\n")); - - if (!bfd_set_section_alignment (dynobj, sec, - ABI_64_P (dynobj) ? 3 : 2)) - goto error_alignment; - - htab->plt_second_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; + plt_layout.lazy_plt = &elf_x86_64_nacl_plt; + plt_layout.non_lazy_plt = NULL; + plt_layout.lazy_ibt_plt = NULL; + plt_layout.non_lazy_ibt_plt = NULL; + plt_layout.normal_target = FALSE; } - return pbfd; + return _bfd_x86_elf_link_setup_gnu_properties (info, &plt_layout); } static const struct bfd_elf_special_section @@ -7062,8 +6720,8 @@ static const struct elf_x86_lazy_plt_layout elf_x86_64_nacl_plt = 7, /* plt_got_insn_size */ 42, /* plt_plt_insn_end */ 32, /* plt_lazy_offset */ - NULL, /* pic_plt0_entry */ - NULL, /* pic_plt_entry */ + elf_x86_64_nacl_plt0_entry, /* pic_plt0_entry */ + elf_x86_64_nacl_plt_entry, /* pic_plt_entry */ elf_x86_64_nacl_eh_frame_plt, /* eh_frame_plt */ sizeof (elf_x86_64_nacl_eh_frame_plt) /* eh_frame_plt_size */ }; diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index eb02ed2..d43fe31 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -19,6 +19,7 @@ MA 02110-1301, USA. */ #include "elfxx-x86.h" +#include "elf-vxworks.h" #include "objalloc.h" #include "elf/i386.h" #include "elf/x86-64.h" @@ -900,3 +901,392 @@ _bfd_x86_elf_merge_gnu_properties (struct bfd_link_info *info, return updated; } + +/* Set up x86 GNU properties. Return the first relocatable ELF input + with GNU properties if found. Otherwise, return NULL. */ + +bfd * +_bfd_x86_elf_link_setup_gnu_properties + (struct bfd_link_info *info, + struct elf_x86_plt_layout_table *plt_layout) +{ + 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_x86_link_hash_table *htab; + bfd *pbfd; + bfd *ebfd = NULL; + elf_property *prop; + const struct elf_backend_data *bed; + unsigned int class_align = ABI_64_P (info->output_bfd) ? 3 : 2; + unsigned int got_align; + + 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, class_align)) + { +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; + + bed = get_elf_backend_data (info->output_bfd); + + htab = elf_x86_hash_table (info, bed->target_id); + 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 = plt_layout->normal_target; + + if (normal_target) + { + if (use_ibt_plt) + { + htab->lazy_plt = plt_layout->lazy_ibt_plt; + htab->non_lazy_plt = plt_layout->non_lazy_ibt_plt; + } + else + { + htab->lazy_plt = plt_layout->lazy_plt; + htab->non_lazy_plt = plt_layout->non_lazy_plt; + } + } + else + { + htab->lazy_plt = plt_layout->lazy_plt; + htab->non_lazy_plt = NULL; + } + + 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.plt_got_insn_size + = htab->non_lazy_plt->plt_got_insn_size; + htab->plt.eh_frame_plt_size + = htab->non_lazy_plt->eh_frame_plt_size; + htab->plt.eh_frame_plt = htab->non_lazy_plt->eh_frame_plt; + } + 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.plt_got_insn_size + = htab->lazy_plt->plt_got_insn_size; + htab->plt.eh_frame_plt_size + = htab->lazy_plt->eh_frame_plt_size; + htab->plt.eh_frame_plt = htab->lazy_plt->eh_frame_plt; + } + + /* Return if there are no normal input files. */ + if (dynobj == NULL) + return pbfd; + + if (plt_layout->is_vxworks + && !elf_vxworks_create_dynamic_sections (dynobj, info, + &htab->srelplt2)) + { + info->callbacks->einfo (_("%F: failed to create VxWorks dynamic sections\n")); + return pbfd; + } + + /* Since create_dynamic_sections isn't always called, but GOT + relocations need GOT relocations, 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")); + + got_align = (bed->target_id == X86_64_ELF_DATA) ? 3 : 2; + + /* Align .got and .got.plt sections to their entry size. Do it here + instead of in create_dynamic_sections so that they are always + properly aligned even if create_dynamic_sections isn't called. */ + sec = htab->elf.sgot; + if (!bfd_set_section_alignment (dynobj, sec, got_align)) + goto error_alignment; + + sec = htab->elf.sgotplt; + if (!bfd_set_section_alignment (dynobj, sec, got_align)) + goto error_alignment; + + /* 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 = htab->dynamic_interpreter_size; + s->contents = (unsigned char *) htab->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. Don't create additional PLT sections for NaCl. */ + if (normal_target) + { + 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; + } + else if (info->bndplt && ABI_64_P (dynobj)) + { + /* Create the second PLT for Intel MPX support. MPX + PLT is supported only for non-NaCl target in 64-bit + mode and 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 BND PLT section\n")); + + if (!bfd_set_section_alignment (dynobj, sec, + non_lazy_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, class_align)) + 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, class_align)) + goto error_alignment; + + htab->plt_got_eh_frame = sec; + } + + if (htab->plt_second != NULL) + { + sec = bfd_make_section_anyway_with_flags (dynobj, + ".eh_frame", + flags); + if (sec == NULL) + info->callbacks->einfo (_("%F: failed to create the second PLT .eh_frame section\n")); + + if (!bfd_set_section_alignment (dynobj, sec, class_align)) + goto error_alignment; + + htab->plt_second_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; +} diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index 45f2458..f0240b3 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -159,11 +159,11 @@ struct elf_x86_lazy_plt_layout unsigned int plt_lazy_offset; /* The first entry in a PIC lazy procedure linkage table looks like - this. This is used for i386 only. */ + this. */ const bfd_byte *pic_plt0_entry; /* Subsequent entries in a PIC lazy procedure linkage table look - like this. This is used for i386 only. */ + like this. */ const bfd_byte *pic_plt_entry; /* .eh_frame covering the lazy .plt section. */ @@ -176,8 +176,7 @@ struct elf_x86_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. - This is used for i386 only. */ + /* Entries in a PIC non-lazy procedure linkage table look like this. */ const bfd_byte *pic_plt_entry; unsigned int plt_entry_size; /* Size of each PLT entry. */ @@ -304,6 +303,27 @@ struct elf_x86_link_hash_table const char *tls_get_addr; }; +struct elf_x86_plt_layout_table +{ + /* The lazy PLT layout. */ + const struct elf_x86_lazy_plt_layout *lazy_plt; + + /* The non-lazy PLT layout. */ + const struct elf_x86_non_lazy_plt_layout *non_lazy_plt; + + /* The lazy PLT layout for IBT. */ + const struct elf_x86_lazy_plt_layout *lazy_ibt_plt; + + /* The non-lazy PLT layout for IBT. */ + const struct elf_x86_non_lazy_plt_layout *non_lazy_ibt_plt; + + /* TRUE if this is an normal x86 target. */ + bfd_boolean normal_target; + + /* TRUE if this is a VxWorks x86 target. */ + bfd_boolean is_vxworks; +}; + struct elf_x86_obj_tdata { struct elf_obj_tdata root; @@ -403,6 +423,9 @@ extern enum elf_property_kind _bfd_x86_elf_parse_gnu_properties extern bfd_boolean _bfd_x86_elf_merge_gnu_properties (struct bfd_link_info *, bfd *, elf_property *, elf_property *); +extern bfd * _bfd_x86_elf_link_setup_gnu_properties + (struct bfd_link_info *, struct elf_x86_plt_layout_table *); + #define bfd_elf64_bfd_link_hash_table_create \ _bfd_x86_elf_link_hash_table_create #define bfd_elf32_bfd_link_hash_table_create \ |