x86; Allow IFUNC pointer defined in PDE

If IFUNC symbol is defined in position-dependent executable, we should
change it to the normal function and set its address to its PLT entry
which should be resolved by R_*_IRELATIVE at run-time.  All external
references should be resolved to its PLT in executable.

bfd/

	PR ld/23169
	* elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Don't issue
	an error on IFUNC pointer defined in PDE.
	* elf32-i386.c (elf_i386_finish_dynamic_symbol): Call
	_bfd_x86_elf_link_fixup_ifunc_symbol.
	* elf64-x86-64.c (elf_x86_64_finish_dynamic_symbol): Likewise.
	* elfxx-x86.c (_bfd_x86_elf_link_fixup_ifunc_symbol): New
	function.
	* elfxx-x86.h (_bfd_x86_elf_link_fixup_ifunc_symbol): New.

ld/

	PR ld/23169
	* testsuite/ld-ifunc/ifunc-9-i386.d: New file.
	* testsuite/ld-ifunc/ifunc-9-x86-64.d: Likewise.
	* testsuite/ld-ifunc/pr23169a.c: Likewise.
	* testsuite/ld-ifunc/pr23169a.rd: Likewise.
	* testsuite/ld-ifunc/pr23169b.c: Likewise.
	* testsuite/ld-ifunc/pr23169b.c: Likewise.
	* testsuite/ld-ifunc/pr23169c.rd: Likewise.
	* testsuite/ld-ifunc/pr23169c.rd: Likewise.
	* testsuite/ld-ifunc/ifunc-9-x86.d: Removed.
	* testsuite/ld-ifunc/ifunc.exp: Run PR ld/23169 tests.
This commit is contained in:
H.J. Lu 2018-05-14 03:55:37 -07:00
parent 9bc935ef33
commit 4ec0995016
17 changed files with 290 additions and 4 deletions

View File

@ -1,3 +1,15 @@
2018-05-14 H.J. Lu <hongjiu.lu@intel.com>
PR ld/23169
* elf-ifunc.c (_bfd_elf_allocate_ifunc_dyn_relocs): Don't issue
an error on IFUNC pointer defined in PDE.
* elf32-i386.c (elf_i386_finish_dynamic_symbol): Call
_bfd_x86_elf_link_fixup_ifunc_symbol.
* elf64-x86-64.c (elf_x86_64_finish_dynamic_symbol): Likewise.
* elfxx-x86.c (_bfd_x86_elf_link_fixup_ifunc_symbol): New
function.
* elfxx-x86.h (_bfd_x86_elf_link_fixup_ifunc_symbol): New.
2018-05-14 H.J. Lu <hongjiu.lu@intel.com>
PR ld/23162

View File

@ -131,8 +131,15 @@ _bfd_elf_allocate_ifunc_dyn_relocs (struct bfd_link_info *info,
the resolved function may be used. But in non-PIC executable,
the address of its .plt slot may be used. Pointer equality may
not work correctly. PIE or non-PLT reference should be used if
pointer equality is required here. */
pointer equality is required here.
If STT_GNU_IFUNC symbol is defined in position-dependent executable,
backend should change it to the normal function and set its address
to its PLT entry which should be resolved by R_*_IRELATIVE at
run-time. All external references should be resolved to its PLT in
executable. */
if (!need_dynreloc
&& !(bfd_link_pde (info) && h->def_regular)
&& (h->dynindx != -1
|| info->export_dynamic)
&& h->pointer_equality_needed)

View File

@ -3805,6 +3805,8 @@ elf_i386_finish_dynamic_symbol (bfd *output_bfd,
sym->st_value = 0;
}
_bfd_x86_elf_link_fixup_ifunc_symbol (info, htab, h, sym);
/* Don't generate dynamic GOT relocation against undefined weak
symbol in executable. */
if (h->got.offset != (bfd_vma) -1

View File

@ -4147,6 +4147,8 @@ elf_x86_64_finish_dynamic_symbol (bfd *output_bfd,
sym->st_value = 0;
}
_bfd_x86_elf_link_fixup_ifunc_symbol (info, htab, h, sym);
/* Don't generate dynamic GOT relocation against undefined weak
symbol in executable. */
if (h->got.offset != (bfd_vma) -1

View File

@ -1730,6 +1730,52 @@ _bfd_x86_elf_fixup_symbol (struct bfd_link_info *info,
return TRUE;
}
/* Change the STT_GNU_IFUNC symbol defined in position-dependent
executable into the normal function symbol and set its address
to its PLT entry, which should be resolved by R_*_IRELATIVE at
run-time. */
void
_bfd_x86_elf_link_fixup_ifunc_symbol (struct bfd_link_info *info,
struct elf_x86_link_hash_table *htab,
struct elf_link_hash_entry *h,
Elf_Internal_Sym *sym)
{
if (bfd_link_pde (info)
&& h->def_regular
&& h->dynindx != -1
&& h->plt.offset != (bfd_vma) -1
&& h->type == STT_GNU_IFUNC
&& h->pointer_equality_needed)
{
asection *plt_s;
bfd_vma plt_offset;
bfd *output_bfd = info->output_bfd;
if (htab->plt_second)
{
struct elf_x86_link_hash_entry *eh
= (struct elf_x86_link_hash_entry *) h;
plt_s = htab->plt_second;
plt_offset = eh->plt_second.offset;
}
else
{
plt_s = htab->elf.splt;
plt_offset = h->plt.offset;
}
sym->st_size = 0;
sym->st_info = ELF_ST_INFO (ELF_ST_BIND (sym->st_info), STT_FUNC);
sym->st_shndx
= _bfd_elf_section_from_bfd_section (output_bfd,
plt_s->output_section);
sym->st_value = (plt_s->output_section->vma
+ plt_s->output_offset + plt_offset);
}
}
/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */
bfd_boolean

View File

@ -674,6 +674,10 @@ extern bfd_boolean _bfd_x86_elf_merge_gnu_properties
extern bfd * _bfd_x86_elf_link_setup_gnu_properties
(struct bfd_link_info *, struct elf_x86_init_table *);
extern void _bfd_x86_elf_link_fixup_ifunc_symbol
(struct bfd_link_info *, struct elf_x86_link_hash_table *,
struct elf_link_hash_entry *, Elf_Internal_Sym *sym);
#define bfd_elf64_mkobject \
_bfd_x86_elf_mkobject
#define bfd_elf32_mkobject \

View File

@ -1,3 +1,17 @@
2018-05-14 H.J. Lu <hongjiu.lu@intel.com>
PR ld/23169
* testsuite/ld-ifunc/ifunc-9-i386.d: New file.
* testsuite/ld-ifunc/ifunc-9-x86-64.d: Likewise.
* testsuite/ld-ifunc/pr23169a.c: Likewise.
* testsuite/ld-ifunc/pr23169a.rd: Likewise.
* testsuite/ld-ifunc/pr23169b.c: Likewise.
* testsuite/ld-ifunc/pr23169b.c: Likewise.
* testsuite/ld-ifunc/pr23169c.rd: Likewise.
* testsuite/ld-ifunc/pr23169c.rd: Likewise.
* testsuite/ld-ifunc/ifunc-9-x86.d: Removed.
* testsuite/ld-ifunc/ifunc.exp: Run PR ld/23169 tests.
2018-05-14 H.J. Lu <hongjiu.lu@intel.com>
PR ld/23162

View File

@ -0,0 +1,9 @@
#source: ifunc-9-x86.s
#as: --32
#ld: -m elf_i386 --export-dynamic
#readelf: -r --wide
#target: x86_64-*-* i?86-*-*
Relocation section '.rel.plt' at .*
[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_386_IRELATIVE[ ]*

View File

@ -0,0 +1,9 @@
#source: ifunc-9-x86.s
#as: --64
#ld: -melf_x86_64 --export-dynamic
#readelf: -r --wide
#target: x86_64-*-*
Relocation section '.rela.plt' at .*
[ ]+Offset[ ]+Info[ ]+Type[ ]+.*
[0-9a-f]+[ ]+[0-9a-f]+[ ]+R_X86_64_IRELATIVE[ ]+[0-9a-f]*

View File

@ -1,3 +0,0 @@
#ld: --export-dynamic
#error: .*dynamic STT_GNU_IFUNC symbol `foo' with pointer equality in `.*.o' can not be used when making an executable; recompile with -fPIE and relink with -pie
#target: x86_64-*-* i?86-*-*

View File

@ -581,6 +581,76 @@ run_cc_link_tests [list \
{} \
"libpr18841cn.so" \
] \
[list \
"Build libpr23169a.so" \
"-shared" \
"-fPIC -O2 -g" \
{ pr23169a.c } \
{} \
"libpr23169a.so" \
] \
[list \
"Build libpr23169b.so" \
"-shared -Wl,-z,now" \
"-fPIC -O2 -g" \
{ pr23169a.c } \
{} \
"libpr23169b.so" \
] \
[list \
"Build pr23169a" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
"$NOPIE_CFLAGS -O2 -g" \
{ pr23169b.c pr23169c.c } \
{{readelf {--dyn-syms} pr23169a.rd} \
{readelf {-r -W} pr23169b.rd}} \
"pr23169a" \
] \
[list \
"Build pr23169b" \
"-pie -Wl,--no-as-needed tmpdir/libpr23169a.so" \
"-fPIE -O2 -g" \
{ pr23169b.c pr23169c.c } \
{{readelf {--dyn-syms} pr23169c.rd} \
{readelf {-r -W} pr23169b.rd}} \
"pr23169b" \
] \
[list \
"Build pr23169c" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
"-fPIE -O2 -g" \
{ pr23169b.c pr23169c.c } \
{{readelf {--dyn-syms} pr23169c.rd} \
{readelf {-r -W} pr23169b.rd}} \
"pr23169c" \
] \
[list \
"Build pr23169d" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
"$NOPIE_CFLAGS -O2 -g" \
{ pr23169b.c pr23169c.c } \
{{readelf {--dyn-syms} pr23169a.rd} \
{readelf {-r -W} pr23169b.rd}} \
"pr23169d" \
] \
[list \
"Build pr23169e" \
"-pie -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
"-fPIE -O2 -g" \
{ pr23169b.c pr23169c.c } \
{{readelf {--dyn-syms} pr23169c.rd} \
{readelf {-r -W} pr23169b.rd}} \
"pr23169e" \
] \
[list \
"Build pr23169f" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
"-fPIE -O2 -g" \
{ pr23169b.c pr23169c.c } \
{{readelf {--dyn-syms} pr23169c.rd} \
{readelf {-r -W} pr23169b.rd}} \
"pr23169f" \
] \
]
run_ld_link_exec_tests [list \
@ -632,4 +702,58 @@ run_ld_link_exec_tests [list \
"pr18841cn" \
"pr18841.out" \
] \
[list \
"Run pr23169a" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
"" \
{ pr23169b.c pr23169c.c } \
"pr23169a" \
"pass.out" \
"$NOPIE_CFLAGS -O2 -g" \
] \
[list \
"Run pr23169b" \
"-pie -Wl,--no-as-needed tmpdir/libpr23169a.so" \
"" \
{ pr23169b.c pr23169c.c } \
"pr23169b" \
"pass.out" \
"-fPIE -O2 -g" \
] \
[list \
"Run pr23169c" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed tmpdir/libpr23169a.so" \
"" \
{ pr23169b.c pr23169c.c } \
"pr23169c" \
"pass.out" \
"-fPIE -O2 -g" \
] \
[list \
"Run pr23169d" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
"" \
{ pr23169b.c pr23169c.c } \
"pr23169d" \
"pass.out" \
"$NOPIE_CFLAGS -O2 -g" \
] \
[list \
"Run pr23169e" \
"-pie -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
"" \
{ pr23169b.c pr23169c.c } \
"pr23169e" \
"pass.out" \
"-fPIE -O2 -g" \
] \
[list \
"Run pr23169f" \
"$NOPIE_LDFLAGS -Wl,--no-as-needed,-z,now tmpdir/libpr23169b.so" \
"" \
{ pr23169b.c pr23169c.c } \
"pr23169f" \
"pass.out" \
"-fPIE -O2 -g" \
] \
]

View File

@ -0,0 +1,9 @@
int (*func_p) (void);
extern int func (void);
void
foo (void)
{
if (func_p != &func || func_p () != 0xbadbeef)
__builtin_abort ();
}

View File

@ -0,0 +1,6 @@
Symbol table '\.dynsym' contains [0-9]+ entries:
+Num: +Value +Size Type +Bind +Vis +Ndx Name
#...
+[0-9]+: +[a-f0-9]+ +0 +FUNC +GLOBAL +DEFAULT +[0-9]+ +func
#...

View File

@ -0,0 +1,23 @@
#include <stdio.h>
extern int (*func_p) (void);
extern int func (void);
extern void foo (void);
void
bar (void)
{
if (func_p != &func || func_p () != 0xbadbeef)
__builtin_abort ();
}
int
main ()
{
func_p = &func;
foo ();
bar ();
printf ("PASS\n");
return 0;
}

View File

@ -0,0 +1,3 @@
#failif
[a-f0-9]+ +[0-9a-f]+ +R_.*_* +[a-f0-9]+ +func(| \+ 0)
...

View File

@ -0,0 +1,13 @@
static int
ifunc (void)
{
return 0xbadbeef;
}
void func(void) __attribute__((ifunc("resolve_func")));
static void *
resolve_func (void)
{
return ifunc;
}

View File

@ -0,0 +1,6 @@
Symbol table '\.dynsym' contains [0-9]+ entries:
+Num: +Value +Size Type +Bind +Vis +Ndx Name
#...
+[0-9]+: +[a-f0-9]+ +[0-9]+ +IFUNC +GLOBAL +DEFAULT +[0-9]+ +func
#...