x86-64: Use PLT address for PC-relative reloc

Since PLT in PDE and PC-relative PLT in PIE can be used as function
address, there is no need for dynamic PC-relative relocation against
a dynamic function definition in PIE.  Linker should resolve PC-relative
reference to its PLT address.

NB: i386 has non-PIC PLT and PIC PLT.  Only non-PIC PLT in PDE can
be used as function address.  PIC PLT in PIE can't be used as
function address.

bfd/

	PR ld/22842
	* elf32-i386.c (elf_i386_check_relocs): Pass FALSE for non
	PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
	* elf64-x86-64.c (elf_x86_64_check_relocs): Create PLT for
	R_X86_64_PC32 reloc against dynamic function in data section.
	Pass TRUE for PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
	(elf_x86_64_relocate_section): Use PLT for R_X86_64_PC32 reloc
	against dynamic function in data section.
	* elfxx-x86.c (elf_x86_allocate_dynrelocs): Use PLT in PIE as
	function address only if pcrel_plt is true.
	(_bfd_x86_elf_link_hash_table_create): Set pcrel_plt.
	* elfxx-x86.h (NEED_DYNAMIC_RELOCATION_P): Add PCREL_PLT for
	PC-relative PLT.  If PLT is PC-relative, don't generate dynamic
	PC-relative relocation against a function definition in data
	secton in PIE.  Remove the obsolete comments.
	(elf_x86_link_hash_table): Add pcrel_plt.

ld/

	PR ld/22842
	* testsuite/ld-i386/i386.exp: Run PR ld/22842 tests.
	* testsuite/ld-x86-64/x86-64.exp: Likewise.
	* testsuite/ld-i386/pr22842a.c: New file.
	* testsuite/ld-i386/pr22842b.S: Likewise.
	* testsuite/ld-x86-64/pr22842a.c: Likewise.
	* testsuite/ld-x86-64/pr22842a.rd: Likewise.
	* testsuite/ld-x86-64/pr22842b.S: Likewise.
	* testsuite/ld-x86-64/pr22842b.rd: Likewise.
This commit is contained in:
H.J. Lu 2018-02-14 03:50:40 -08:00
parent f98b2e334f
commit 451875b4f9
14 changed files with 251 additions and 28 deletions

View File

@ -1,3 +1,22 @@
2018-02-14 H.J. Lu <hongjiu.lu@intel.com>
PR ld/22842
* elf32-i386.c (elf_i386_check_relocs): Pass FALSE for non
PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
* elf64-x86-64.c (elf_x86_64_check_relocs): Create PLT for
R_X86_64_PC32 reloc against dynamic function in data section.
Pass TRUE for PC-relative PLT to NEED_DYNAMIC_RELOCATION_P.
(elf_x86_64_relocate_section): Use PLT for R_X86_64_PC32 reloc
against dynamic function in data section.
* elfxx-x86.c (elf_x86_allocate_dynrelocs): Use PLT in PIE as
function address only if pcrel_plt is true.
(_bfd_x86_elf_link_hash_table_create): Set pcrel_plt.
* elfxx-x86.h (NEED_DYNAMIC_RELOCATION_P): Add PCREL_PLT for
PC-relative PLT. If PLT is PC-relative, don't generate dynamic
PC-relative relocation against a function definition in data
secton in PIE. Remove the obsolete comments.
(elf_x86_link_hash_table): Add pcrel_plt.
2018-02-13 H.J. Lu <hongjiu.lu@intel.com>
* elfxx-x86.c (elf_x86_allocate_dynrelocs): Check bfd_link_dll,

View File

@ -1812,7 +1812,7 @@ do_relocation:
size_reloc = FALSE;
do_size:
if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type,
if (NEED_DYNAMIC_RELOCATION_P (info, FALSE, h, sec, r_type,
R_386_32))
{
struct elf_dyn_relocs *p;

View File

@ -2135,7 +2135,17 @@ pointer:
as pointer, make sure that PLT is used if foo is
a function defined in a shared library. */
if ((sec->flags & SEC_CODE) == 0)
h->pointer_equality_needed = 1;
{
h->pointer_equality_needed = 1;
if (bfd_link_pie (info)
&& h->type == STT_FUNC
&& !h->def_regular
&& h->def_dynamic)
{
h->needs_plt = 1;
h->plt.refcount = 1;
}
}
}
else if (r_type != R_X86_64_PC32_BND
&& r_type != R_X86_64_PC64)
@ -2173,7 +2183,7 @@ pointer:
size_reloc = FALSE;
do_size:
if (NEED_DYNAMIC_RELOCATION_P (info, h, sec, r_type,
if (NEED_DYNAMIC_RELOCATION_P (info, TRUE, h, sec, r_type,
htab->pointer_r_type))
{
struct elf_dyn_relocs *p;
@ -2968,6 +2978,7 @@ do_ifunc_pointer:
break;
}
use_plt:
if (h->plt.offset != (bfd_vma) -1)
{
if (htab->plt_second != NULL)
@ -3046,6 +3057,15 @@ do_ifunc_pointer:
return elf_x86_64_need_pic (info, input_bfd, input_section,
h, NULL, NULL, howto);
}
/* Since x86-64 has PC-relative PLT, we can use PLT in PIE
as function address. */
else if (h != NULL
&& (input_section->flags & SEC_CODE) == 0
&& bfd_link_pie (info)
&& h->type == STT_FUNC
&& !h->def_regular
&& h->def_dynamic)
goto use_plt;
/* Fall through. */
case R_X86_64_8:

View File

@ -179,6 +179,7 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
asection *s = htab->elf.splt;
asection *second_s = htab->plt_second;
asection *got_s = htab->plt_got;
bfd_boolean use_plt;
/* If this is the first .plt entry, make room for the special
first entry. The .plt section is used by prelink to undo
@ -196,12 +197,19 @@ elf_x86_allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf)
}
/* If this symbol is not defined in a regular file, and we are
not generating a shared library, then set the symbol to this
location in the .plt. This is required to make function
pointers compare as equal between the normal executable and
the shared library. */
if (! bfd_link_dll (info)
&& !h->def_regular)
generating PDE, then set the symbol to this location in the
.plt. This is required to make function pointers compare
as equal between PDE and the shared library.
NB: If PLT is PC-relative, we can use the .plt in PIE for
function address. */
if (h->def_regular)
use_plt = FALSE;
else if (htab->pcrel_plt)
use_plt = ! bfd_link_dll (info);
else
use_plt = bfd_link_pde (info);
if (use_plt)
{
if (use_plt_got)
{
@ -771,6 +779,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
ret->dt_reloc_sz = DT_RELASZ;
ret->dt_reloc_ent = DT_RELAENT;
ret->got_entry_size = 8;
ret->pcrel_plt = TRUE;
ret->tls_get_addr = "__tls_get_addr";
}
if (ABI_64_P (abfd))
@ -798,6 +807,7 @@ _bfd_x86_elf_link_hash_table_create (bfd *abfd)
ret->dt_reloc_ent = DT_RELENT;
ret->sizeof_reloc = sizeof (Elf32_External_Rel);
ret->got_entry_size = 4;
ret->pcrel_plt = FALSE;
ret->pointer_r_type = R_386_32;
ret->dynamic_interpreter = ELF32_DYNAMIC_INTERPRETER;
ret->dynamic_interpreter_size

View File

@ -76,14 +76,11 @@
into the shared library. However, if we are linking with -Bsymbolic,
we do not need to copy a reloc against a global symbol which is
defined in an object we are including in the link (i.e., DEF_REGULAR
is set). At this point we have not seen all the input files, so it
is possible that DEF_REGULAR is not set now but will be set later (it
is never cleared). In case of a weak definition, DEF_REGULAR may be
cleared later by a strong definition in a shared library. We account
for that possibility below by storing information in the relocs_copied
field of the hash table entry. A similar situation occurs when
creating shared libraries and symbol visibility changes render the
symbol local.
is set).
If PCREL_PLT is true, don't generate dynamic relocation in PIE for
PC-relative relocation against a dynamic function definition in data
section when PLT address can be used.
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
@ -91,23 +88,30 @@
We also need to generate dynamic pointer relocation against
STT_GNU_IFUNC symbol in the non-code section. */
#define NEED_DYNAMIC_RELOCATION_P(INFO, H, SEC, R_TYPE, POINTER_TYPE) \
#define NEED_DYNAMIC_RELOCATION_P(INFO, PCREL_PLT, H, SEC, R_TYPE, \
POINTER_TYPE) \
((bfd_link_pic (INFO) \
&& (! X86_PCREL_TYPE_P (R_TYPE) \
|| ((H) != NULL \
&& (! (bfd_link_pie (INFO) \
|| SYMBOLIC_BIND ((INFO), (H))) \
|| (H)->root.type == bfd_link_hash_defweak \
|| !(H)->def_regular)))) \
|| ((H) != NULL \
&& (H)->type == STT_GNU_IFUNC \
&& (R_TYPE) == POINTER_TYPE \
&& ((SEC)->flags & SEC_CODE) == 0) \
|| (ELIMINATE_COPY_RELOCS \
&& !bfd_link_pic (INFO) \
&& (H) != NULL \
&& ((H)->root.type == bfd_link_hash_defweak \
|| !(H)->def_regular)))
|| (!(bfd_link_pie (INFO) \
&& (PCREL_PLT) \
&& (H)->plt.refcount > 0 \
&& ((SEC)->flags & SEC_CODE) == 0 \
&& (H)->type == STT_FUNC \
&& (H)->def_dynamic) \
&& !(H)->def_regular))))) \
|| ((H) != NULL \
&& (H)->type == STT_GNU_IFUNC \
&& (R_TYPE) == POINTER_TYPE \
&& ((SEC)->flags & SEC_CODE) == 0) \
|| (ELIMINATE_COPY_RELOCS \
&& !bfd_link_pic (INFO) \
&& (H) != NULL \
&& ((H)->root.type == bfd_link_hash_defweak \
|| !(H)->def_regular)))
/* TRUE if dynamic relocation should be generated. Don't copy a
pc-relative relocation into the output file if the symbol needs
@ -482,6 +486,14 @@ struct elf_x86_link_hash_table
/* TRUE if GOT is referenced. */
unsigned int got_referenced : 1;
/* TRUE if PLT is PC-relative. PLT in PDE and PC-relative PLT in PIE
can be used as function address.
NB: i386 has non-PIC PLT and PIC PLT. Only non-PIC PLT in PDE can
be used as function address. PIC PLT in PIE can't be used as
function address. */
unsigned int pcrel_plt : 1;
bfd_vma (*r_info) (bfd_vma, bfd_vma);
bfd_vma (*r_sym) (bfd_vma);
bfd_boolean (*is_reloc_section) (const char *);

View File

@ -1,3 +1,15 @@
2018-02-14 H.J. Lu <hongjiu.lu@intel.com>
PR ld/22842
* testsuite/ld-i386/i386.exp: Run PR ld/22842 tests.
* testsuite/ld-x86-64/x86-64.exp: Likewise.
* testsuite/ld-i386/pr22842a.c: New file.
* testsuite/ld-i386/pr22842b.S: Likewise.
* testsuite/ld-x86-64/pr22842a.c: Likewise.
* testsuite/ld-x86-64/pr22842a.rd: Likewise.
* testsuite/ld-x86-64/pr22842b.S: Likewise.
* testsuite/ld-x86-64/pr22842b.rd: Likewise.
2018-02-14 Maciej W. Rozycki <macro@mips.com>
* ldlex.h (ldlex_command): Remove prototype.

View File

@ -1273,6 +1273,14 @@ if { [isnative]
{} \
"pr21997-1.so" \
] \
[list \
"Build pr22842.so" \
"-shared" \
"-fPIC" \
{ pr22842a.c } \
{} \
"pr22842.so" \
] \
]
run_ld_link_exec_tests [list \
@ -1371,6 +1379,14 @@ if { [isnative]
"pr21997-1-pie-2" \
"pass.out" \
] \
[list \
"Build pr22842" \
"-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
"" \
{ pr22842b.S } \
"pr22842" \
"pass.out" \
] \
]
if { [at_least_gcc_version 5 0] } {

View File

@ -0,0 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
void
test (void)
{
static int count;
if (count)
printf("PASS\n");
count++;
}
void
foo (void (*bar) (void))
{
if (bar != test)
abort ();
bar ();
test ();
}

View File

@ -0,0 +1,41 @@
.text
.globl main
.type main, @function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ebx
pushl %ecx
call __x86.get_pc_thunk.bx
addl $_GLOBAL_OFFSET_TABLE_, %ebx
subl $12, %esp
movl bar@GOT(%ebx), %eax
addl (%eax), %eax
pushl %eax
call foo@PLT
addl $16, %esp
leal -8(%ebp), %esp
xorl %eax, %eax
popl %ecx
popl %ebx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.section .text.__x86.get_pc_thunk.bx,"axG",@progbits,__x86.get_pc_thunk.bx,comdat
.globl __x86.get_pc_thunk.bx
.hidden __x86.get_pc_thunk.bx
.type __x86.get_pc_thunk.bx, @function
__x86.get_pc_thunk.bx:
movl (%esp), %ebx
ret
.data
.p2align 2
bar:
.long test - .
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,20 @@
#include <stdio.h>
#include <stdlib.h>
void
test (void)
{
static int count;
if (count)
printf("PASS\n");
count++;
}
void
foo (void (*bar) (void))
{
if (bar != test)
abort ();
bar ();
test ();
}

View File

@ -0,0 +1,4 @@
#failif
#...
[0-9a-f ]+R_X86_64_NONE.*
#...

View File

@ -0,0 +1,20 @@
.text
.globl main
.type main,@function
main:
pushq %rax
movslq bar(%rip), %rax
leaq bar(%rip), %rdi
addq %rax, %rdi
callq foo
xorl %eax, %eax
popq %rcx
retq
.data
.p2align 2
bar:
.long test - .
.section .note.GNU-stack,"",@progbits

View File

@ -0,0 +1,4 @@
#failif
#...
[0-9a-f ]+R_X86_64_PC32 +[0-9a-f]+ +test \+ 0
#...

View File

@ -1190,6 +1190,23 @@ if { [isnative] && [which $CC] != 0 } {
{{readelf -drW pr22791-2.rd}} \
"pr22791-2" \
] \
[list \
"Build pr22842.so" \
"-shared" \
"-fPIC" \
{ pr22842a.c } \
{} \
"pr22842.so" \
] \
[list \
"Build pr22842" \
"-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
"" \
{ pr22842b.S } \
{{readelf -rW pr22842a.rd} \
{readelf -rW pr22842b.rd}} \
"pr22842" \
] \
]
if {[istarget "x86_64-*-linux*-gnux32"]} {
@ -1524,6 +1541,14 @@ if { [isnative] && [which $CC] != 0 } {
"pass.out" \
"$NOPIE_CFLAGS" \
] \
[list \
"Build pr22842" \
"-pie -Wl,--no-as-needed tmpdir/pr22842.so" \
"" \
{ pr22842b.S } \
"pr22842" \
"pass.out" \
] \
]
# Run-time tests which require working ifunc attribute support.