PATCH: Make STT_GNU_IFUNC symbol dynamic
H.J. Lu
hongjiu.lu@intel.com
Sat May 23 03:45:00 GMT 2009
On Fri, May 22, 2009 at 01:02:25PM -0700, H.J. Lu wrote:
> Hi,
>
> Even if a STT_GNU_IFUNC symbol is hidden, we have to make it dynamic.
> Otherwise, it won't work correctly when it is called within the shared
> library.
>
>
Here is the patch with a testcase. OK for trunk?
Thanks.
H.J.
---
bfd/
2009-05-22 H.J. Lu <hongjiu.lu@intel.com>
* elflink.c (bfd_elf_link_record_dynamic_symbol): Make
STT_GNU_IFUNC symbol dynamic.
(_bfd_elf_fix_symbol_flags): Don't hide STT_GNU_IFUNC symbol.
(elf_link_add_object_symbols): Likewise.
(_bfd_elf_symbol_refs_local_p): Return FALSE on STT_GNU_IFUNC
symbol.
ld/testsuite/
2009-05-22 H.J. Lu <hongjiu.lu@intel.com>
* ld-ifunc/ifunc.exp: Run *.d.
* ld-ifunc/ifunc-1-x86.d: New.
* ld-ifunc/ifunc-1-x86.s: Likewise.
Index: ld/testsuite/ld-ifunc/ifunc.exp
===================================================================
--- ld/testsuite/ld-ifunc/ifunc.exp (revision 5928)
+++ ld/testsuite/ld-ifunc/ifunc.exp (working copy)
@@ -252,3 +252,10 @@ if { $verbose < 1 } {
remote_file host delete "tmpdir/static_prog"
remote_file host delete "tmpdir/static_nonifunc_prog"
}
+
+set test_list [lsort [glob -nocomplain $srcdir/$subdir/*.d]]
+foreach t $test_list {
+ # We need to strip the ".d", but can leave the dirname.
+ verbose [file rootname $t]
+ run_dump_test [file rootname $t]
+}
Index: ld/testsuite/ld-ifunc/ifunc-1-x86.s
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-1-x86.s (revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-1-x86.s (revision 0)
@@ -0,0 +1,16 @@
+ .type foo, %gnu_indirect_function
+ .global __GI_foo
+ .hidden __GI_foo
+ .set __GI_foo, foo
+ .text
+.globl foo
+ .type foo, @function
+foo:
+ ret
+ .size foo, .-foo
+.globl bar
+ .type bar, @function
+bar:
+ call __GI_foo@PLT
+ ret
+ .size bar, .-bar
Index: ld/testsuite/ld-ifunc/ifunc-1-x86.d
===================================================================
--- ld/testsuite/ld-ifunc/ifunc-1-x86.d (revision 0)
+++ ld/testsuite/ld-ifunc/ifunc-1-x86.d (revision 0)
@@ -0,0 +1,7 @@
+#ld: -shared
+#objdump: -dw
+#target: x86_64-*-* i?86-*-*
+
+#...
+[ \t0-9a-f]+:[ \t0-9a-f]+call[ \t0-9a-fq]+<__GI_foo@plt>
+#pass
Index: bfd/elflink.c
===================================================================
--- bfd/elflink.c (revision 5928)
+++ bfd/elflink.c (working copy)
@@ -417,7 +417,9 @@ bfd_elf_link_record_dynamic_symbol (stru
&& h->root.type != bfd_link_hash_undefweak)
{
h->forced_local = 1;
- if (!elf_hash_table (info)->is_relocatable_executable)
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if (ELF_ST_TYPE (h->type) != STT_GNU_IFUNC
+ && !elf_hash_table (info)->is_relocatable_executable)
return TRUE;
}
@@ -2507,10 +2509,11 @@ _bfd_elf_fix_symbol_flags (struct elf_li
symbol was defined in a regular object, then it actually doesn't
need a PLT entry. Likewise, if the symbol has non-default
visibility. If the symbol has hidden or internal visibility, we
- will force it local. */
+ will force it local. STT_GNU_IFUNC symbol must go through PLT. */
if (h->needs_plt
&& eif->info->shared
&& is_elf_hash_table (eif->info->hash)
+ && ELF_ST_TYPE (h->type) != STT_GNU_IFUNC
&& (SYMBOLIC_BIND (eif->info, h)
|| ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
&& h->def_regular)
@@ -2845,6 +2848,10 @@ _bfd_elf_symbol_refs_local_p (struct elf
if (h == NULL)
return TRUE;
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if (h->type == STT_GNU_IFUNC)
+ return FALSE;
+
/* STV_HIDDEN or STV_INTERNAL ones must be local. */
if (ELF_ST_VISIBILITY (h->other) == STV_HIDDEN
|| ELF_ST_VISIBILITY (h->other) == STV_INTERNAL)
@@ -4395,8 +4402,12 @@ elf_link_add_object_symbols (bfd *abfd,
{
case STV_INTERNAL:
case STV_HIDDEN:
- (*bed->elf_backend_hide_symbol) (info, h, TRUE);
- dynsym = FALSE;
+ /* STT_GNU_IFUNC symbol must go through PLT. */
+ if (ELF_ST_TYPE (h->type) != STT_GNU_IFUNC)
+ {
+ (*bed->elf_backend_hide_symbol) (info, h, TRUE);
+ dynsym = FALSE;
+ }
break;
}
More information about the Libc-alpha
mailing list