Optimize out i386/x86-64 JUMP_SLOT relocation
authorH.J. Lu <hjl.tools@gmail.com>
Tue, 25 Nov 2014 13:05:39 +0000 (05:05 -0800)
committerH.J. Lu <hjl.tools@gmail.com>
Tue, 25 Nov 2014 13:05:39 +0000 (05:05 -0800)
commitdd7e64d45b317128f5fe813a8da0b13b4ad046ae
tree3a7cd48d0ddc44e1840ea97120155a6c73ea31cc
parent07e94edf043090a6771eb3b8e7e03339cab8e607
Optimize out i386/x86-64 JUMP_SLOT relocation

When there are both PLT and GOT references to the same function symbol,
linker will create a GOTPLT slot for PLT entry and a GOT slot for GOT
reference.  A run-time JUMP_SLOT relocation is created to update the
GOTPLT slot and a run-time GLOB_DAT relocation is created to update the
GOT slot.  Both JUMP_SLOT and GLOB_DAT relocations will apply the same
symbol value to GOTPLT and GOT slots, respectively, at run-time.

This optimization combines GOTPLT and GOT slots into a single GOT slot
and removes the run-time JUMP_SLOT relocation.  It replaces the regular
PLT entry:

indirect jump [GOTPLT slot]
push relocation index
jump PLT0

with an GOT PLT entry with an indirect jump via the GOT slot:

indirect jump [GOT slot]
nop

and resolves PLT reference to the GOT PLT entry.

We must avoid this optimization if pointer equality is needed since
we don't clear symbol value in this case and the dynamic linker won't
update the GOT slot.  Otherwise, the resulting binary will get into an
infinite loop at run-time.

bfd/

* elf32-i386.c (elf_i386_got_plt_entry): New.
(elf_i386_pic_got_plt_entry): Likewise.
(elf_i386_link_hash_entry): Add plt_got.
(elf_i386_link_hash_table): Likewise.
(elf_i386_link_hash_newfunc): Initialize plt_got.offset to -1.
(elf_i386_get_local_sym_hash): Likewise.
(elf_i386_check_relocs): Create the GOT PLT if there are both
PLT and GOT references when the regular PLT is used.
(elf_i386_allocate_dynrelocs): Use the GOT PLT if there are
both PLT and GOT references unless pointer equality is needed.
(elf_i386_relocate_section): Also check the GOT PLT when
resolving R_386_PLT32.
(elf_i386_finish_dynamic_symbol): Use the GOT PLT if it is
available.

* elf64-x86-64.c (elf_x86_64_link_hash_entry): Add plt_got.
(elf_x86_64_link_hash_table): Likewise.
(elf_x86_64_link_hash_newfunc): Initialize plt_got.offset to -1.
(elf_x86_64_get_local_sym_hash): Likewise.
(elf_x86_64_check_relocs): Create the GOT PLT if there are both
PLT and GOT references when the regular PLT is used.
(elf_x86_64_allocate_dynrelocs): Use the GOT PLT if there are
both PLT and GOT references unless pointer equality is needed.
(elf_x86_64_relocate_section): Also check the GOT PLT when
resolving R_X86_64_PLT32.
(elf_x86_64_finish_dynamic_symbol): Use the GOT PLT if it is
available.

ld/

* emulparams/elf_i386.sh (TINY_READONLY_SECTION): New.
* emulparams/elf_x86_64.sh (TINY_READONLY_SECTION): Add .plt.got.

ld/testsuite/

* ld-i386/i386.exp: Add run-time relocation tests for plt-main.
* ld-i386/plt-main.rd: New file.
* ld-x86-64/plt-main-bnd.dd: Likewise.
* ld-x86-64/plt-main.rd: Likewise.
* ld-x86-64/x86-64.exp: Add run-time relocation tests for
plt-main.
12 files changed:
bfd/ChangeLog
bfd/elf32-i386.c
bfd/elf64-x86-64.c
ld/ChangeLog
ld/emulparams/elf_i386.sh
ld/emulparams/elf_x86_64.sh
ld/testsuite/ChangeLog
ld/testsuite/ld-i386/i386.exp
ld/testsuite/ld-i386/plt-main.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/plt-main-bnd.dd [new file with mode: 0644]
ld/testsuite/ld-x86-64/plt-main.rd [new file with mode: 0644]
ld/testsuite/ld-x86-64/x86-64.exp