diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2016-06-18 09:16:52 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2016-06-18 09:17:25 -0700 |
commit | 233cc9c13af8e8182d0ce5b306526b59f5b11f37 (patch) | |
tree | 6381519cd959d8a585cd640de586e6aab3ca715b /bfd/elf32-i386.c | |
parent | 854594f5ce00381eb0ed57e3c7fa08b5971eabec (diff) | |
download | gdb-233cc9c13af8e8182d0ce5b306526b59f5b11f37.zip gdb-233cc9c13af8e8182d0ce5b306526b59f5b11f37.tar.gz gdb-233cc9c13af8e8182d0ce5b306526b59f5b11f37.tar.bz2 |
Don't generate PLT for IFUNC GOT/pointer reference
If a backend supports it, PLT entry isn't needed when all references
to a STT_GNU_IFUNC symbols are done via GOT or static function pointers.
For GOT entries, We generate dynamic R_*_GLOB_DAT relocations for
preemptable symbols and R_*_IRELATIVE relocations for non-preemptable
symbols to update them with real function address. For static pointer
pointers, we generate dynamic pointer relocations and store them in:
1. .rel[a].ifunc section in PIC object.
2. .rel[a].got section in dynamic executable.
3. .rel[a].iplt section in static executable.
We don't allocate GOT entry if it isn't used.
bfd/
PR ld/20253
* elf-bfd.h (_bfd_elf_allocate_ifunc_dyn_relocs): Add an
bfd_boolean argument.
* elf-ifunc.c (_bfd_elf_create_ifunc_sections): Replace
"shared object" with "PIC object" in comments.
(_bfd_elf_allocate_ifunc_dyn_relocs): Updated. Replace
"shared object" with "PIC object" in comments. Avoid PLT if
requested. Generate dynamic relocations for non-GOT references.
Make room for the special first entry in PLT and allocate PLT
entry only for PLT and PC-relative references. Store dynamic
GOT relocations in .rel[a].iplt section for static executables.
If PLT isn't used, always use GOT for symbol value. Don't
allocate GOT entry if it isn't used.
* elf32-i386.c (elf_i386_check_relocs): Increment PLT reference
count only in the code section. Allocate dynamic pointer
relocation against STT_GNU_IFUNC symbol in the non-code section.
(elf_i386_adjust_dynamic_symbol): Increment PLT reference count
only for PC-relative references.
(elf_i386_allocate_dynrelocs): Pass TRUE to
_bfd_elf_allocate_ifunc_dyn_relocs.
(elf_i386_relocate_section): Allow R_386_GOT32/R_386_GOT32X
relocations against STT_GNU_IFUNC symbols without PLT. Generate
dynamic pointer relocation against STT_GNU_IFUNC symbol in
the non-code section and store it in the proper REL section.
Don't allow non-pointer relocation against STT_GNU_IFUNC symbol
without PLT.
(elf_i386_finish_dynamic_symbol): Generate dynamic
R_386_IRELATIVE and R_386_GLOB_DAT GOT relocations against
STT_GNU_IFUNC symbols without PLT.
(elf_i386_finish_dynamic_sections): Don't handle local
STT_GNU_IFUNC symbols here.
(elf_i386_output_arch_local_syms): Handle local STT_GNU_IFUNC
symbols here.
(elf_backend_output_arch_local_syms): New.
* elf32-x86-64.c (elf_i386_check_relocs): Increment PLT reference
count only in the code section. Allocate dynamic pointer
relocation against STT_GNU_IFUNC symbol in the non-code section.
(elf_x86_64_adjust_dynamic_symbol): Increment PLT reference
count only for PC-relative references.
(elf_x86_64_allocate_dynrelocs): Pass TRUE to
_bfd_elf_allocate_ifunc_dyn_relocs.
(elf_x86_64_relocate_section): Allow R_X86_64_GOTPCREL,
R_X86_64_GOTPCRELX, R_X86_64_REX_GOTPCRELX and
R_X86_64_GOTPCREL64 relocations against STT_GNU_IFUNC symbols
without PLT. Generate dynamic pointer relocation against
STT_GNU_IFUNC symbol in the non-code section and store it in
the proper RELA section. Don't allow non-pointer relocation
against STT_GNU_IFUNC symbol without PLT.
(elf_x86_64_finish_dynamic_symbol): Generate dynamic
R_X86_64_IRELATIVE and R_X86_64_GLOB_DAT GOT relocations against
STT_GNU_IFUNC symbols without PLT.
(elf_x86_64_finish_dynamic_sections): Don't handle local
STT_GNU_IFUNC symbols here.
(elf_x86_64_output_arch_local_syms): Handle local STT_GNU_IFUNC
symbols here.
(elf_backend_output_arch_local_syms): New.
* elfnn-aarch64.c (elfNN_aarch64_allocate_ifunc_dynrelocs):
Pass FALSE to _bfd_elf_allocate_ifunc_dyn_relocs.
ld/
PR ld/20253
* testsuite/ld-i386/i386.exp: Run PR ld/20253 tests.
* testsuite/ld-i386/no-plt.exp: Likewise.
* testsuite/ld-x86-64/no-plt.exp: Likewise.
* testsuite/ld-i386/pr13302.d: Remove .rel.plt section.
* testsuite/ld-ifunc/ifunc-13-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-13-x86-64.d: Likewise.
* testsuite/ld-ifunc/ifunc-15-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-15-x86-64.d: Likewise.
* testsuite/ld-x86-64/pr13082-5a.d: Likewise.
* testsuite/ld-x86-64/pr13082-5b.d: Likewise.
* testsuite/ld-x86-64/pr13082-6a.d: Likewise.
* testsuite/ld-x86-64/pr13082-6b.d: Likewise.
* testsuite/ld-i386/pr20244-2a.d: Remove .plt section.
* testsuite/ld-ifunc/ifunc-21-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-21-x86-64.d: Likewise.
* testsuite/ld-ifunc/ifunc-22-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-22-x86-64.d: Likewise.
* testsuite/ld-i386/pr20244-2b.d: Updated.
* testsuite/ld-i386/pr20244-2c.d: Likewise.
* testsuite/ld-ifunc/ifunc-18a-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-18a-x86-64.d: Likewise.
* testsuite/ld-ifunc/ifunc-18b-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-18b-x86-64.d: Likewise.
* testsuite/ld-i386/pr20253-1a.c: New file.
* testsuite/ld-i386/pr20253-1b.S: Likewise.
* testsuite/ld-i386/pr20253-1c.S: Likewise.
* testsuite/ld-i386/pr20253-1d.S: Likewise.
* testsuite/ld-i386/pr20253-2a.c: Likewise.
* testsuite/ld-i386/pr20253-2b.S: Likewise.
* testsuite/ld-i386/pr20253-2c.S: Likewise.
* testsuite/ld-i386/pr20253-2d.S: Likewise.
* testsuite/ld-i386/pr20253-3.d: Likewise.
* testsuite/ld-i386/pr20253-3.s: Likewise.
* testsuite/ld-i386/pr20253-4.s: Likewise.
* testsuite/ld-i386/pr20253-4a.d: Likewise.
* testsuite/ld-i386/pr20253-4b.d: Likewise.
* testsuite/ld-i386/pr20253-4c.d: Likewise.
* testsuite/ld-i386/pr20253-5.d: Likewise.
* testsuite/ld-i386/pr20253-5.s: Likewise.
* testsuite/ld-ifunc/ifunc-23-x86.s: Likewise.
* testsuite/ld-ifunc/ifunc-23a-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-23b-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-23c-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-24-x86.s: Likewise.
* testsuite/ld-ifunc/ifunc-24a-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-24b-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-24c-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-25-x86.s: Likewise.
* testsuite/ld-ifunc/ifunc-25a-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-25b-x86.d: Likewise.
* testsuite/ld-ifunc/ifunc-25c-x86.d: Likewise.
* testsuite/ld-x86-64/pr20253-1.s: Likewise.
* testsuite/ld-x86-64/pr20253-1a.d: Likewise.
* testsuite/ld-x86-64/pr20253-1b.d: Likewise.
* testsuite/ld-x86-64/pr20253-1c.d: Likewise.
* testsuite/ld-x86-64/pr20253-1d.d: Likewise.
* testsuite/ld-x86-64/pr20253-1e.d: Likewise.
* testsuite/ld-x86-64/pr20253-1f.d: Likewise.
* testsuite/ld-x86-64/pr20253-1g.d: Likewise.
* testsuite/ld-x86-64/pr20253-1h.d: Likewise.
* testsuite/ld-x86-64/pr20253-1i.d: Likewise.
* testsuite/ld-x86-64/pr20253-1j.d: Likewise.
* testsuite/ld-x86-64/pr20253-1k.d: Likewise.
* testsuite/ld-x86-64/pr20253-1l.d: Likewise.
* testsuite/ld-x86-64/pr20253-2a.c: Likewise.
* testsuite/ld-x86-64/pr20253-2b.S: Likewise.
* testsuite/ld-x86-64/pr20253-2c.S: Likewise.
* testsuite/ld-x86-64/pr20253-2d.S: Likewise.
* testsuite/ld-x86-64/pr20253-3.d: Likewise.
* testsuite/ld-x86-64/pr20253-3.s: Likewise.
* testsuite/ld-x86-64/pr20253-4.s: Likewise.
* testsuite/ld-x86-64/pr20253-4a.d: Likewise.
* testsuite/ld-x86-64/pr20253-4b.d: Likewise.
* testsuite/ld-x86-64/pr20253-4c.d: Likewise.
* testsuite/ld-x86-64/pr20253-4d.d: Likewise.
* testsuite/ld-x86-64/pr20253-4e.d: Likewise.
* testsuite/ld-x86-64/pr20253-4f.d: Likewise.
* testsuite/ld-x86-64/pr20253-5.s: Likewise.
* testsuite/ld-x86-64/pr20253-5a.d: Likewise.
* testsuite/ld-x86-64/pr20253-5b.d: Likewise.
* testsuite/ld-ifunc/ifunc-18a-i386.d: Remove extra IRELATIVE
relocation.
* testsuite/ld-ifunc/ifunc-18a-x86-64.d: Likewise.
* testsuite/ld-ifunc/ifunc-18b-i386.d: Likewise.
* testsuite/ld-ifunc/ifunc-18b-x86-64.d: Likewise.
* testsuite/ld-ifunc/ifunc-18a.s: Fix a typo.
* testsuite/ld-x86-64/x86-64.exp: Run pr20253-1 tests.
Diffstat (limited to 'bfd/elf32-i386.c')
-rw-r--r-- | bfd/elf32-i386.c | 262 |
1 files changed, 175 insertions, 87 deletions
diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 2b7de33..4179572 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -2164,9 +2164,13 @@ do_relocation: adjust_dynamic_symbol. */ h->non_got_ref = 1; - /* We may need a .plt entry if the function this reloc - refers to is in a shared lib. */ - h->plt.refcount += 1; + /* We may need a .plt entry if the symbol is a function + defined in a shared lib or is a STT_GNU_IFUNC function + referenced from the code or read-only section. */ + if (!h->def_regular + || (sec->flags & (SEC_CODE | SEC_READONLY)) != 0) + h->plt.refcount += 1; + if (r_type == R_386_PC32) { /* Since something like ".long foo - ." may be used @@ -2207,7 +2211,10 @@ do_size: If on the other hand, we are creating an executable, we may need to keep relocations for symbols satisfied by a dynamic library if we manage to avoid copy relocs for the - symbol. */ + symbol. + + Generate dynamic pointer relocation against STT_GNU_IFUNC + symbol in the non-code section. */ if ((bfd_link_pic (info) && (r_type != R_386_PC32 || (h != NULL @@ -2215,6 +2222,10 @@ do_size: || SYMBOLIC_BIND (info, h)) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) + || (h != NULL + && h->type == STT_GNU_IFUNC + && r_type == R_386_32 + && (sec->flags & SEC_CODE) == 0) || (ELIMINATE_COPY_RELOCS && !bfd_link_pic (info) && h != NULL @@ -2448,12 +2459,17 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, if (pc_count || count) { - h->needs_plt = 1; h->non_got_ref = 1; - if (h->plt.refcount <= 0) - h->plt.refcount = 1; - else - h->plt.refcount += 1; + if (pc_count) + { + /* Increment PLT reference count only for PC-relative + references. */ + h->needs_plt = 1; + if (h->plt.refcount <= 0) + h->plt.refcount = 1; + else + h->plt.refcount += 1; + } } } @@ -2643,7 +2659,7 @@ elf_i386_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) return _bfd_elf_allocate_ifunc_dyn_relocs (info, h, &eh->dyn_relocs, &htab->readonly_dynrelocs_against_ifunc, plt_entry_size, - plt_entry_size, 4); + plt_entry_size, 4, TRUE); /* 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 @@ -3898,8 +3914,6 @@ elf_i386_relocate_section (bfd *output_bfd, continue; abort (); } - else if (h->plt.offset == (bfd_vma) -1) - abort (); /* STT_GNU_IFUNC symbol must go through PLT. */ if (htab->elf.splt != NULL) @@ -3913,77 +3927,10 @@ elf_i386_relocate_section (bfd *output_bfd, gotplt = htab->elf.igotplt; } - relocation = (plt->output_section->vma - + plt->output_offset + h->plt.offset); - switch (r_type) { default: - if (h->root.root.string) - name = h->root.root.string; - else - name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, - NULL); - (*_bfd_error_handler) - (_("%B: relocation %s against STT_GNU_IFUNC " - "symbol `%s' isn't handled by %s"), input_bfd, - elf_howto_table[r_type].name, - name, __FUNCTION__); - bfd_set_error (bfd_error_bad_value); - return FALSE; - - case R_386_32: - /* Generate dynamic relcoation only when there is a - non-GOT reference in a shared object. */ - if (bfd_link_pic (info) && h->non_got_ref) - { - Elf_Internal_Rela outrel; - asection *sreloc; - bfd_vma offset; - - /* Need a dynamic relocation to get the real function - adddress. */ - offset = _bfd_elf_section_offset (output_bfd, - info, - input_section, - rel->r_offset); - if (offset == (bfd_vma) -1 - || offset == (bfd_vma) -2) - abort (); - - outrel.r_offset = (input_section->output_section->vma - + input_section->output_offset - + offset); - - if (h->dynindx == -1 - || h->forced_local - || bfd_link_executable (info)) - { - /* This symbol is resolved locally. */ - outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); - bfd_put_32 (output_bfd, - (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset), - contents + offset); - } - else - outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); - - sreloc = htab->elf.irelifunc; - elf_append_rel (output_bfd, sreloc, &outrel); - - /* If this reloc is against an external symbol, we - do not want to fiddle with the addend. Otherwise, - we need to include the symbol value so that it - becomes an addend for the dynamic reloc. For an - internal symbol, we have updated addend. */ - continue; - } - /* FALLTHROUGH */ - case R_386_PC32: - case R_386_PLT32: - goto do_relocation; + break; case R_386_GOT32: case R_386_GOT32X: @@ -3999,6 +3946,9 @@ elf_i386_relocate_section (bfd *output_bfd, even just remember the offset, as finish_dynamic_symbol would use that as offset into .got. */ + if (h->plt.offset == (bfd_vma) -1) + abort (); + if (htab->elf.splt != NULL) { plt_index = h->plt.offset / plt_entry_size - 1; @@ -4059,6 +4009,99 @@ elf_i386_relocate_section (bfd *output_bfd, } goto do_relocation; + } + + if (h->plt.offset == (bfd_vma) -1) + { + /* Handle static pointers of STT_GNU_IFUNC symbols. */ + if (r_type == R_386_32 + && (input_section->flags & SEC_CODE) == 0) + goto do_ifunc_pointer; + goto bad_ifunc_reloc; + } + + relocation = (plt->output_section->vma + + plt->output_offset + h->plt.offset); + + switch (r_type) + { + default: +bad_ifunc_reloc: + if (h->root.root.string) + name = h->root.root.string; + else + name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, + NULL); + (*_bfd_error_handler) + (_("%B: relocation %s against STT_GNU_IFUNC " + "symbol `%s' isn't supported"), input_bfd, + howto->name, name); + bfd_set_error (bfd_error_bad_value); + return FALSE; + + case R_386_32: + /* Generate dynamic relcoation only when there is a + non-GOT reference in a shared object. */ + if ((bfd_link_pic (info) && h->non_got_ref) + || h->plt.offset == (bfd_vma) -1) + { + Elf_Internal_Rela outrel; + asection *sreloc; + bfd_vma offset; + +do_ifunc_pointer: + /* Need a dynamic relocation to get the real function + adddress. */ + offset = _bfd_elf_section_offset (output_bfd, + info, + input_section, + rel->r_offset); + if (offset == (bfd_vma) -1 + || offset == (bfd_vma) -2) + abort (); + + outrel.r_offset = (input_section->output_section->vma + + input_section->output_offset + + offset); + + if (h->dynindx == -1 + || h->forced_local + || bfd_link_executable (info)) + { + /* This symbol is resolved locally. */ + outrel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); + bfd_put_32 (output_bfd, + (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset), + contents + offset); + } + else + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); + + /* Dynamic relocations are stored in + 1. .rel.ifunc section in PIC object. + 2. .rel.got section in dynamic executable. + 3. .rel.iplt section in static executable. */ + if (bfd_link_pic (info)) + sreloc = htab->elf.irelifunc; + else if (htab->elf.splt != NULL) + sreloc = htab->elf.srelgot; + else + sreloc = htab->elf.irelplt; + elf_append_rel (output_bfd, sreloc, &outrel); + + /* If this reloc is against an external symbol, we + do not want to fiddle with the addend. Otherwise, + we need to include the symbol value so that it + becomes an addend for the dynamic reloc. For an + internal symbol, we have updated addend. */ + continue; + } + /* FALLTHROUGH */ + case R_386_PC32: + case R_386_PLT32: + goto do_relocation; case R_386_GOTOFF: relocation -= (gotplt->output_section->vma @@ -5432,6 +5475,7 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, && !local_undefweak) { Elf_Internal_Rela rel; + asection *relgot = htab->elf.srelgot; /* This symbol has an entry in the global offset table. Set it up. */ @@ -5451,7 +5495,28 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd, if (h->def_regular && h->type == STT_GNU_IFUNC) { - if (bfd_link_pic (info)) + if (h->plt.offset == (bfd_vma) -1) + { + /* STT_GNU_IFUNC is referenced without PLT. */ + if (htab->elf.splt == NULL) + { + /* use .rel[a].iplt section to store .got relocations + in static executable. */ + relgot = htab->elf.irelplt; + } + if (SYMBOL_REFERENCES_LOCAL (info, h)) + { + bfd_put_32 (output_bfd, + (h->root.u.def.value + + h->root.u.def.section->output_section->vma + + h->root.u.def.section->output_offset), + htab->elf.sgot->contents + h->got.offset); + rel.r_info = ELF32_R_INFO (0, R_386_IRELATIVE); + } + else + goto do_glob_dat; + } + else if (bfd_link_pic (info)) { /* Generate R_386_GLOB_DAT. */ goto do_glob_dat; @@ -5489,7 +5554,7 @@ do_glob_dat: rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); } - elf_append_rel (output_bfd, htab->elf.srelgot, &rel); + elf_append_rel (output_bfd, relgot, &rel); } if (h->needs_copy) @@ -5826,11 +5891,6 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, if (htab->elf.sgot && htab->elf.sgot->size > 0) elf_section_data (htab->elf.sgot->output_section)->this_hdr.sh_entsize = 4; - /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ - htab_traverse (htab->loc_hash_table, - elf_i386_finish_local_dynamic_symbol, - info); - /* Fill PLT entries for undefined weak symbols in PIE. */ if (bfd_link_pie (info)) bfd_hash_traverse (&info->hash->table, @@ -5840,6 +5900,33 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, return TRUE; } +/* Fill PLT/GOT entries and allocate dynamic relocations for local + STT_GNU_IFUNC symbols, which aren't in the ELF linker hash table. + It has to be done before elf_link_sort_relocs is called so that + dynamic relocations are properly sorted. */ + +static bfd_boolean +elf_i386_output_arch_local_syms + (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info, + void *flaginfo ATTRIBUTE_UNUSED, + int (*func) (void *, const char *, + Elf_Internal_Sym *, + asection *, + struct elf_link_hash_entry *) ATTRIBUTE_UNUSED) +{ + struct elf_i386_link_hash_table *htab = elf_i386_hash_table (info); + if (htab == NULL) + return FALSE; + + /* Fill PLT and GOT entries for local STT_GNU_IFUNC symbols. */ + htab_traverse (htab->loc_hash_table, + elf_i386_finish_local_dynamic_symbol, + info); + + return TRUE; +} + /* Return an array of PLT entry symbol values. */ static bfd_vma * @@ -5982,6 +6069,7 @@ elf_i386_hash_symbol (struct elf_link_hash_entry *h) #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 +#define elf_backend_output_arch_local_syms elf_i386_output_arch_local_syms #define elf_backend_gc_mark_hook elf_i386_gc_mark_hook #define elf_backend_grok_prstatus elf_i386_grok_prstatus #define elf_backend_grok_psinfo elf_i386_grok_psinfo |