From d1ed1c7d69e6656de213b12594e702afec31a66d Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Tue, 8 Mar 2016 09:42:01 -0800 Subject: [PATCH] Handle local IFUNC symbols in shared object Increment PLT reference count for locally defined local IFUNC symbols in shared object since STT_GNU_IFUNC symbol must go through PLT even if it is locally defined and undefined symbol may turn out to be a STT_GNU_IFUNC symbol later. bfd/ PR ld/19784 * elf32-i386.c (elf_i386_check_relocs): Increment PLT reference count for locally defined local IFUNC symbols in shared object. * elf64-x86-64.c (elf_x86_64_check_relocs): Likewise. ld/ PR ld/19784 * testsuite/ld-i386/i386.exp: Remove pr19636-2e-nacl test. * testsuite/ld-i386/pr19636-2e-nacl.d: Moved to ... * testsuite/ld-i386/pr19636-2e.d: Here. Remove notarget. * testsuite/ld-ifunc/ifunc.exp: Run PR ld/19784 tests. * testsuite/ld-ifunc/pass.out: New file. * testsuite/ld-ifunc/pr19784a.c: Likewise. * testsuite/ld-ifunc/pr19784b.c: Likewise. * testsuite/ld-ifunc/pr19784c.c: Likewise. --- bfd/ChangeLog | 7 ++++++ bfd/elf32-i386.c | 10 ++++++++- bfd/elf64-x86-64.c | 10 ++++++++- ld/ChangeLog | 12 ++++++++++ ld/testsuite/ld-i386/i386.exp | 1 - ld/testsuite/ld-i386/pr19636-2e-nacl.d | 21 ------------------ ld/testsuite/ld-i386/pr19636-2e.d | 5 ++++- ld/testsuite/ld-ifunc/ifunc.exp | 40 ++++++++++++++++++++++++++++++++++ ld/testsuite/ld-ifunc/pass.out | 1 + ld/testsuite/ld-ifunc/pr19784a.c | 6 +++++ ld/testsuite/ld-ifunc/pr19784b.c | 11 ++++++++++ ld/testsuite/ld-ifunc/pr19784c.c | 11 ++++++++++ 12 files changed, 110 insertions(+), 25 deletions(-) delete mode 100644 ld/testsuite/ld-i386/pr19636-2e-nacl.d create mode 100644 ld/testsuite/ld-ifunc/pass.out create mode 100644 ld/testsuite/ld-ifunc/pr19784a.c create mode 100644 ld/testsuite/ld-ifunc/pr19784b.c create mode 100644 ld/testsuite/ld-ifunc/pr19784c.c diff --git a/bfd/ChangeLog b/bfd/ChangeLog index c3b9132..e2193a5 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,5 +1,12 @@ 2016-03-08 H.J. Lu + PR ld/19784 + * elf32-i386.c (elf_i386_check_relocs): Increment PLT reference + count for locally defined local IFUNC symbols in shared object. + * elf64-x86-64.c (elf_x86_64_check_relocs): Likewise. + +2016-03-08 H.J. Lu + PR ld/19579 * elflink.c (_bfd_elf_merge_symbol): Group common symbol checking together. diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index ab3945d..ac3c2f4 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1808,7 +1808,15 @@ elf_i386_check_relocs (bfd *abfd, if (eh != NULL && (sec->flags & SEC_CODE) != 0) eh->has_non_got_reloc = 1; do_relocation: - if (h != NULL && bfd_link_executable (info)) + /* STT_GNU_IFUNC symbol must go through PLT even if it is + locally defined and undefined symbol may turn out to be + a STT_GNU_IFUNC symbol later. */ + if (h != NULL + && (bfd_link_executable (info) + || ((h->type == STT_GNU_IFUNC + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined) + && SYMBOLIC_BIND (info, h)))) { /* If this reloc is in a read-only section, we might need a copy reloc. We can't check reliably at this diff --git a/bfd/elf64-x86-64.c b/bfd/elf64-x86-64.c index c696850..380376d 100644 --- a/bfd/elf64-x86-64.c +++ b/bfd/elf64-x86-64.c @@ -1999,7 +1999,15 @@ elf_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, pointer: if (eh != NULL && (sec->flags & SEC_CODE) != 0) eh->has_non_got_reloc = 1; - if (h != NULL && bfd_link_executable (info)) + /* STT_GNU_IFUNC symbol must go through PLT even if it is + locally defined and undefined symbol may turn out to be + a STT_GNU_IFUNC symbol later. */ + if (h != NULL + && (bfd_link_executable (info) + || ((h->type == STT_GNU_IFUNC + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined) + && SYMBOLIC_BIND (info, h)))) { /* If this reloc is in a read-only section, we might need a copy reloc. We can't check reliably at this diff --git a/ld/ChangeLog b/ld/ChangeLog index 960190f..73f67b0 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,5 +1,17 @@ 2016-03-08 H.J. Lu + PR ld/19784 + * testsuite/ld-i386/i386.exp: Remove pr19636-2e-nacl test. + * testsuite/ld-i386/pr19636-2e-nacl.d: Moved to ... + * testsuite/ld-i386/pr19636-2e.d: Here. Remove notarget. + * testsuite/ld-ifunc/ifunc.exp: Run PR ld/19784 tests. + * testsuite/ld-ifunc/pass.out: New file. + * testsuite/ld-ifunc/pr19784a.c: Likewise. + * testsuite/ld-ifunc/pr19784b.c: Likewise. + * testsuite/ld-ifunc/pr19784c.c: Likewise. + +2016-03-08 H.J. Lu + PR ld/19774 * testsuite/ld-ifunc/ifunc.exp: Link tmpdir/pr18808a.o before tmpdir/libpr18808.so. Link tmpdir/pr18841a.o before diff --git a/ld/testsuite/ld-i386/i386.exp b/ld/testsuite/ld-i386/i386.exp index 5b9d790..a032ca7 100644 --- a/ld/testsuite/ld-i386/i386.exp +++ b/ld/testsuite/ld-i386/i386.exp @@ -337,7 +337,6 @@ run_dump_test "pr19636-2c-nacl" run_dump_test "pr19636-2d" run_dump_test "pr19636-2d-nacl" run_dump_test "pr19636-2e" -run_dump_test "pr19636-2e-nacl" run_dump_test "pr19636-3a" run_dump_test "pr19636-3b" run_dump_test "pr19636-3c" diff --git a/ld/testsuite/ld-i386/pr19636-2e-nacl.d b/ld/testsuite/ld-i386/pr19636-2e-nacl.d deleted file mode 100644 index f791128..0000000 --- a/ld/testsuite/ld-i386/pr19636-2e-nacl.d +++ /dev/null @@ -1,21 +0,0 @@ -#source: pr19636-2.s -#as: --32 -mrelax-relocations=no -#ld: -shared -Bsymbolic -m elf_i386 -#readelf : -r --wide --dyn-syms -#target: i?86-*-nacl* x86_64-*-nacl* - -Relocation section '\.rel\.dyn' at offset [0x0-9a-f]+ contains 3 entries: - +Offset +Info +Type +Sym. Value +Symbol's Name -[0-9a-f]+ +[0-9a-f]+ +R_386_32 +0+ +func -[0-9a-f]+ +[0-9a-f]+ +R_386_PC32 +0+ +func -[0-9a-f]+ +[0-9a-f]+ +R_386_GLOB_DAT +0+ +func - -Relocation section '\.rel\.plt' at offset [0x0-9a-f]+ contains 1 entries: - +Offset +Info +Type +Sym. Value +Symbol's Name -[0-9a-f]+ +[0-9a-f]+ +R_386_JUMP_SLOT +0+ +func - -Symbol table '\.dynsym' contains [0-9]+ entries: - +Num: +Value +Size Type +Bind +Vis +Ndx Name -#... - +[0-9]+: +[a-f0-9]+ +0 +NOTYPE +WEAK +DEFAULT +UND +func -#pass diff --git a/ld/testsuite/ld-i386/pr19636-2e.d b/ld/testsuite/ld-i386/pr19636-2e.d index 148e306..c985242 100644 --- a/ld/testsuite/ld-i386/pr19636-2e.d +++ b/ld/testsuite/ld-i386/pr19636-2e.d @@ -2,7 +2,6 @@ #as: --32 -mrelax-relocations=no #ld: -shared -Bsymbolic -m elf_i386 #readelf : -r --wide --dyn-syms -#notarget: i?86-*-nacl* x86_64-*-nacl* Relocation section '\.rel\.dyn' at offset [0x0-9a-f]+ contains 3 entries: +Offset +Info +Type +Sym. Value +Symbol's Name @@ -10,6 +9,10 @@ Relocation section '\.rel\.dyn' at offset [0x0-9a-f]+ contains 3 entries: [0-9a-f]+ +[0-9a-f]+ +R_386_PC32 +0+ +func [0-9a-f]+ +[0-9a-f]+ +R_386_GLOB_DAT +0+ +func +Relocation section '\.rel\.plt' at offset [0x0-9a-f]+ contains 1 entries: + +Offset +Info +Type +Sym. Value +Symbol's Name +[0-9a-f]+ +[0-9a-f]+ +R_386_JUMP_SLOT +0+ +func + Symbol table '\.dynsym' contains [0-9]+ entries: +Num: +Value +Size Type +Bind +Vis +Ndx Name #... diff --git a/ld/testsuite/ld-ifunc/ifunc.exp b/ld/testsuite/ld-ifunc/ifunc.exp index 96627e7..e860f36 100644 --- a/ld/testsuite/ld-ifunc/ifunc.exp +++ b/ld/testsuite/ld-ifunc/ifunc.exp @@ -505,6 +505,30 @@ run_cc_link_tests [list \ {} \ "libpr18841c.so" \ ] \ + [list \ + "Build libpr19784a.so" \ + "-shared -Wl,-Bsymbolic-functions" \ + "-fPIC -O2 -g" \ + { pr19784b.c pr19784c.c } \ + {} \ + "libpr19784a.so" \ + ] \ + [list \ + "Build libpr19784b.so" \ + "-shared -Wl,-Bsymbolic-functions" \ + "-fPIC -O2 -g" \ + { pr19784c.c pr19784b.c } \ + {} \ + "libpr19784b.so" \ + ] \ + [list \ + "Build pr19784a.o" \ + "" \ + "" \ + { pr19784a.c } \ + "" \ + "" \ + ] \ ] run_ld_link_exec_tests [] [list \ @@ -532,4 +556,20 @@ run_ld_link_exec_tests [] [list \ "pr18841c" \ "pr18841.out" \ ] \ + [list \ + "Run pr19784a" \ + "tmpdir/pr19784a.o tmpdir/libpr19784a.so" \ + "" \ + { dummy.c } \ + "pr19784a" \ + "pass.out" \ + ] \ + [list \ + "Run pr19784b" \ + "--as-needed tmpdir/pr19784a.o tmpdir/libpr19784b.so" \ + "" \ + { dummy.c } \ + "pr19784b" \ + "pass.out" \ + ] \ ] diff --git a/ld/testsuite/ld-ifunc/pass.out b/ld/testsuite/ld-ifunc/pass.out new file mode 100644 index 0000000..7ef22e9 --- /dev/null +++ b/ld/testsuite/ld-ifunc/pass.out @@ -0,0 +1 @@ +PASS diff --git a/ld/testsuite/ld-ifunc/pr19784a.c b/ld/testsuite/ld-ifunc/pr19784a.c new file mode 100644 index 0000000..c922cb9 --- /dev/null +++ b/ld/testsuite/ld-ifunc/pr19784a.c @@ -0,0 +1,6 @@ +void bar(void); +int main(void) +{ + bar(); + return 0; +} diff --git a/ld/testsuite/ld-ifunc/pr19784b.c b/ld/testsuite/ld-ifunc/pr19784b.c new file mode 100644 index 0000000..8ea7ce2 --- /dev/null +++ b/ld/testsuite/ld-ifunc/pr19784b.c @@ -0,0 +1,11 @@ +int foo (int x) __attribute__ ((ifunc ("resolve_foo"))); + +static int foo_impl(int x) +{ + return x; +} + +void *resolve_foo (void) +{ + return (void *) foo_impl; +} diff --git a/ld/testsuite/ld-ifunc/pr19784c.c b/ld/testsuite/ld-ifunc/pr19784c.c new file mode 100644 index 0000000..117dfec --- /dev/null +++ b/ld/testsuite/ld-ifunc/pr19784c.c @@ -0,0 +1,11 @@ +#include + +extern void abort (void); +extern int foo (int) __attribute__ ((visibility("hidden"))); + +int bar() +{ + if (foo (5) != 5) + abort (); + printf("PASS\n"); +} -- 2.7.4