diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2022-11-01 11:36:04 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2023-09-29 07:58:53 -0700 |
commit | 832ca732b8a96ff9a3e7c4abf24098bf2a59a96d (patch) | |
tree | 5ee140bdc26d1d37696b865c80becee32ecde8c6 /bfd | |
parent | a78c3c9717e8fa98b11482f948e71c6d1d9d0e44 (diff) | |
download | binutils-832ca732b8a96ff9a3e7c4abf24098bf2a59a96d.zip binutils-832ca732b8a96ff9a3e7c4abf24098bf2a59a96d.tar.gz binutils-832ca732b8a96ff9a3e7c4abf24098bf2a59a96d.tar.bz2 |
x86-64: Add -z mark-plt and -z nomark-plt
The PLT entry in executables and shared libraries contains an indirect
branch, like
jmp *foo@GOTPCREL(%rip)
push $index_foo
jmp .PLT0
or
endbr64
jmp *foo@GOTPCREL(%rip)
NOP padding
which is used to branch to the function, foo, defined in another object.
Each R_X86_64_JUMP_SLOT relocation has a corresponding PLT entry.
The dynamic tags have been added to the x86-64 psABI to mark such PLT
entries:
https://gitlab.com/x86-psABIs/x86-64-ABI/-/commit/6d824a52a42d173eb838b879616c1be5870b593e
Add an x86-64 linker option, -z mark-plt, to mark PLT entries with
#define DT_X86_64_PLT (DT_LOPROC + 0)
#define DT_X86_64_PLTSZ (DT_LOPROC + 1)
#define DT_X86_64_PLTENT (DT_LOPROC + 3)
1. DT_X86_64_PLT: The address of the procedure linkage table.
2. DT_X86_64_PLTSZ: The total size, in bytes, of the procedure linkage
table.
3. DT_X86_64_PLTENT: The size, in bytes, of a procedure linkage table
entry.
and set the r_addend field of the R_X86_64_JUMP_SLOT relocation to the
memory offset of the indirect branch instruction. The dynamic linker
can use these tags to update the PLT section to direct branch.
bfd/
* elf-linker-x86.h (elf_linker_x86_params): Add mark_plt.
* elf64-x86-64.c (elf_x86_64_finish_dynamic_symbol): Set the
r_addend of R_X86_64_JUMP_SLOT to the indirect branch offset
in PLT entry for -z mark-plt.
* elfxx-x86.c (_bfd_x86_elf_size_dynamic_sections): Add
DT_X86_64_PLT, DT_X86_64_PLTSZ and DT_X86_64_PLTENT for
-z mark-plt.
(_bfd_x86_elf_finish_dynamic_sections): Set DT_X86_64_PLT,
DT_X86_64_PLTSZ and DT_X86_64_PLTENT.
(_bfd_x86_elf_get_synthetic_symtab): Ignore addend for
JUMP_SLOT relocation.
(_bfd_x86_elf_link_setup_gnu_properties): Set
plt_indirect_branch_offset.
* elfxx-x86.h (elf_x86_plt_layout): Add plt_indirect_branch_offset.
binutils/
* readelf.c (get_x86_64_dynamic_type): New function.
(get_dynamic_type): Call get_x86_64_dynamic_type.
include/
* elf/x86-64.h (DT_X86_64_PLT): New.
(DT_X86_64_PLTSZ): Likewise.
(DT_X86_64_PLTENT): Likewise.
ld/
* ld.texi: Document -z mark-plt and -z nomark-plt.
* emulparams/elf32_x86_64.sh: Source x86-64-plt.sh.
* emulparams/elf_x86_64.sh: Likewise.
* emulparams/x86-64-plt.sh: New file.
* testsuite/ld-x86-64/mark-plt-1.s: Likewise.
* testsuite/ld-x86-64/mark-plt-1a-x32.d: Likewise.
* testsuite/ld-x86-64/mark-plt-1a.d: Likewise.
* testsuite/ld-x86-64/mark-plt-1b-x32.d: Likewise.
* testsuite/ld-x86-64/mark-plt-1b.d: Likewise.
* testsuite/ld-x86-64/mark-plt-1c-x32.d: Likewise.
* testsuite/ld-x86-64/mark-plt-1c.d: Likewise.
* testsuite/ld-x86-64/mark-plt-1d-x32.d: Likewise.
* testsuite/ld-x86-64/mark-plt-1d.d: Likewise.
* testsuite/ld-x86-64/x86-64.exp: Run -z mark-plt tests.
Diffstat (limited to 'bfd')
-rw-r--r-- | bfd/elf-linker-x86.h | 3 | ||||
-rw-r--r-- | bfd/elf64-x86-64.c | 7 | ||||
-rw-r--r-- | bfd/elfxx-x86.c | 47 | ||||
-rw-r--r-- | bfd/elfxx-x86.h | 3 |
4 files changed, 58 insertions, 2 deletions
diff --git a/bfd/elf-linker-x86.h b/bfd/elf-linker-x86.h index e39dbf2..1e6ecb1 100644 --- a/bfd/elf-linker-x86.h +++ b/bfd/elf-linker-x86.h @@ -61,6 +61,9 @@ struct elf_linker_x86_params /* Report relative relocations. */ unsigned int report_relative_reloc : 1; + /* Mark PLT with dynamic tags. */ + unsigned int mark_plt : 1; + /* X86-64 ISA level needed. */ unsigned int isa_level; diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index e7a0a91..3b7a8ae 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -4455,7 +4455,12 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd, else { rela.r_info = htab->r_info (h->dynindx, R_X86_64_JUMP_SLOT); - rela.r_addend = 0; + if (htab->params->mark_plt) + rela.r_addend = (resolved_plt->output_section->vma + + plt_offset + + htab->plt.plt_indirect_branch_offset); + else + rela.r_addend = 0; plt_index = htab->next_jump_slot_index++; } diff --git a/bfd/elfxx-x86.c b/bfd/elfxx-x86.c index 103559d..58bd76d 100644 --- a/bfd/elfxx-x86.c +++ b/bfd/elfxx-x86.c @@ -2525,6 +2525,19 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd, } } + asection *resolved_plt = NULL; + + if (htab->params->mark_plt && htab->elf.dynamic_sections_created) + { + if (htab->plt_second != NULL) + resolved_plt = htab->plt_second; + else + resolved_plt = htab->elf.splt; + + if (resolved_plt != NULL && resolved_plt->size == 0) + resolved_plt = NULL; + } + /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ relocs = false; @@ -2673,6 +2686,12 @@ _bfd_x86_elf_size_dynamic_sections (bfd *output_bfd, _bfd_x86_elf_write_sframe_plt (output_bfd, info, SFRAME_PLT_SEC); } + if (resolved_plt != NULL + && (!_bfd_elf_add_dynamic_entry (info, DT_X86_64_PLT, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_X86_64_PLTSZ, 0) + || !_bfd_elf_add_dynamic_entry (info, DT_X86_64_PLTENT, 0))) + return false; + return _bfd_elf_maybe_vxworks_add_dynamic_tags (output_bfd, info, relocs); } @@ -2747,6 +2766,12 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd, if (sdyn == NULL || htab->elf.sgot == NULL) abort (); + asection *resolved_plt; + if (htab->plt_second != NULL) + resolved_plt = htab->plt_second; + else + resolved_plt = htab->elf.splt; + sizeof_dyn = bed->s->sizeof_dyn; dyncon = sdyn->contents; dynconend = sdyn->contents + sdyn->size; @@ -2791,6 +2816,19 @@ _bfd_x86_elf_finish_dynamic_sections (bfd *output_bfd, dyn.d_un.d_ptr = s->output_section->vma + s->output_offset + htab->elf.tlsdesc_got; break; + + case DT_X86_64_PLT: + s = resolved_plt->output_section; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; + break; + + case DT_X86_64_PLTSZ: + dyn.d_un.d_val = resolved_plt->size; + break; + + case DT_X86_64_PLTENT: + dyn.d_un.d_ptr = htab->plt.plt_entry_size; + break; } (*bed->s->swap_dyn_out) (output_bfd, &dyn, dyncon); @@ -3561,6 +3599,7 @@ _bfd_x86_elf_get_synthetic_symtab (bfd *abfd, bfd_vma (*get_plt_got_vma) (struct elf_x86_plt *, bfd_vma, bfd_vma, bfd_vma); bool (*valid_plt_reloc_p) (unsigned int); + unsigned int jump_slot_reloc; dynrelbuf = NULL; if (count == 0) @@ -3601,11 +3640,13 @@ _bfd_x86_elf_get_synthetic_symtab (bfd *abfd, { get_plt_got_vma = elf_x86_64_get_plt_got_vma; valid_plt_reloc_p = elf_x86_64_valid_plt_reloc_p; + jump_slot_reloc = R_X86_64_JUMP_SLOT; } else { get_plt_got_vma = elf_i386_get_plt_got_vma; valid_plt_reloc_p = elf_i386_valid_plt_reloc_p; + jump_slot_reloc = R_386_JUMP_SLOT; if (got_addr) { /* Check .got.plt and then .got to get the _GLOBAL_OFFSET_TABLE_ @@ -3710,7 +3751,9 @@ _bfd_x86_elf_get_synthetic_symtab (bfd *abfd, len = strlen ((*p->sym_ptr_ptr)->name); memcpy (names, (*p->sym_ptr_ptr)->name, len); names += len; - if (p->addend != 0) + /* There may be JUMP_SLOT and IRELATIVE relocations. + JUMP_SLOT r_addend should be ignored. */ + if (p->addend != 0 && p->howto->type != jump_slot_reloc) { char buf[30], *a; @@ -4275,6 +4318,7 @@ _bfd_x86_elf_link_setup_gnu_properties still be used with LD_AUDIT or LD_PROFILE if PLT entry is used for canonical function address. */ htab->plt.has_plt0 = 1; + htab->plt.plt_indirect_branch_offset = 0; normal_target = htab->elf.target_os == is_normal; if (normal_target) @@ -4283,6 +4327,7 @@ _bfd_x86_elf_link_setup_gnu_properties { htab->lazy_plt = init_table->lazy_ibt_plt; htab->non_lazy_plt = init_table->non_lazy_ibt_plt; + htab->plt.plt_indirect_branch_offset = 4; } else { diff --git a/bfd/elfxx-x86.h b/bfd/elfxx-x86.h index 3b4644c..0bc966b 100644 --- a/bfd/elfxx-x86.h +++ b/bfd/elfxx-x86.h @@ -502,6 +502,9 @@ struct elf_x86_plt_layout /* 1 has PLT0. */ unsigned int has_plt0; + /* Offset of indirect branch in plt_entry. */ + unsigned int plt_indirect_branch_offset; + /* Offsets into plt_entry that are to be replaced with... */ unsigned int plt_got_offset; /* ... address of this symbol in .got. */ |