From: Alan Modra Date: Wed, 2 Jul 2014 05:37:18 +0000 (+0930) Subject: Taking an undefined function's address in an executable X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=d1eca1e41ddae8c3cd925be827640de919301432;p=binutils-gdb.git Taking an undefined function's address in an executable doesn't always mean you need to define a function symbol on plt code. If all references are in read-write sections, then using dynamic relocs is OK. bfd/ * elf32-ppc.c (ppc_elf_adjust_dynamic_symbol): Clear pointer_equality_needed when !readonly_dynrelocs. * elf64-ppc.c (ppc64_elf_adjust_dynamic_symbol): Likewise. ld/testsuite/ * ld-powerpc/ambiguousv1.d: Match symbol table too. * ld-powerpc/ambiguousv2.d: Likewise. * ld-powerpc/ambiguousv1b.d: New. * ld-powerpc/ambiguousv2b.d: New. * ld-powerpc/powerpc.exp: Run new tests. --- diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 9eb3edaf80a..1218fc97008 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2014-07-02 Alan Modra + + * elf32-ppc.c (ppc_elf_adjust_dynamic_symbol): Clear + pointer_equality_needed when !readonly_dynrelocs. + * elf64-ppc.c (ppc64_elf_adjust_dynamic_symbol): Likewise. + 2014-07-02 Alan Modra * elf32-ppc.c (ppc_elf_check_relocs): Set DF_STATIC_TLS for PIEs too. diff --git a/bfd/elf32-ppc.c b/bfd/elf32-ppc.c index 0a9c8f996f7..e20e804ce7e 100644 --- a/bfd/elf32-ppc.c +++ b/bfd/elf32-ppc.c @@ -5506,9 +5506,21 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, will go to this object, or will remain undefined. */ h->plt.plist = NULL; h->needs_plt = 0; + h->pointer_equality_needed = 0; } else { + /* Taking a function's address in a read/write section + doesn't require us to define the function symbol in the + executable on a global entry stub. A dynamic reloc can + be used instead. */ + if (h->pointer_equality_needed + && !readonly_dynrelocs (h)) + { + h->pointer_equality_needed = 0; + h->non_got_ref = 0; + } + /* After adjust_dynamic_symbol, non_got_ref set in the non-shared case means that we have allocated space in .dynbss for the symbol and thus dyn_relocs for this @@ -5518,12 +5530,12 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, relocations against this symbol to the PLT entry. Allow dynamic relocs if the reference is weak, and the dynamic relocs will not cause text relocation. */ - if (!h->ref_regular_nonweak - && h->non_got_ref - && h->type != STT_GNU_IFUNC - && !htab->is_vxworks - && !ppc_elf_hash_entry (h)->has_sda_refs - && !readonly_dynrelocs (h)) + else if (!h->ref_regular_nonweak + && h->non_got_ref + && h->type != STT_GNU_IFUNC + && !htab->is_vxworks + && !ppc_elf_hash_entry (h)->has_sda_refs + && !readonly_dynrelocs (h)) h->non_got_ref = 0; } return TRUE; diff --git a/bfd/elf64-ppc.c b/bfd/elf64-ppc.c index 81e54a76f70..0efc6025aab 100644 --- a/bfd/elf64-ppc.c +++ b/bfd/elf64-ppc.c @@ -6993,9 +6993,21 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, { h->plt.plist = NULL; h->needs_plt = 0; + h->pointer_equality_needed = 0; } else if (abiversion (info->output_bfd) == 2) { + /* Taking a function's address in a read/write section + doesn't require us to define the function symbol in the + executable on a global entry stub. A dynamic reloc can + be used instead. */ + if (h->pointer_equality_needed + && !readonly_dynrelocs (h)) + { + h->pointer_equality_needed = 0; + h->non_got_ref = 0; + } + /* After adjust_dynamic_symbol, non_got_ref set in the non-shared case means that we have allocated space in .dynbss for the symbol and thus dyn_relocs for this @@ -7005,10 +7017,10 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, relocations against this symbol to the PLT entry. Allow dynamic relocs if the reference is weak, and the dynamic relocs will not cause text relocation. */ - if (!h->ref_regular_nonweak - && h->non_got_ref - && h->type != STT_GNU_IFUNC - && !readonly_dynrelocs (h)) + else if (!h->ref_regular_nonweak + && h->non_got_ref + && h->type != STT_GNU_IFUNC + && !readonly_dynrelocs (h)) h->non_got_ref = 0; /* If making a plt entry, then we don't need copy relocs. */ diff --git a/ld/testsuite/ChangeLog b/ld/testsuite/ChangeLog index 561abaf5d0e..b59f584840f 100644 --- a/ld/testsuite/ChangeLog +++ b/ld/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2014-07-02 Alan Modra + + * ld-powerpc/ambiguousv1.d: Match symbol table too. + * ld-powerpc/ambiguousv2.d: Likewise. + * ld-powerpc/ambiguousv1b.d: New. + * ld-powerpc/ambiguousv2b.d: New. + * ld-powerpc/powerpc.exp: Run new tests. + 2014-06-25 Kyle McMartin * ld-arm/tls-gdierelax2.d: Fix expected offsets. diff --git a/ld/testsuite/ld-powerpc/ambiguousv1.d b/ld/testsuite/ld-powerpc/ambiguousv1.d index 73beab942db..458c554e838 100644 --- a/ld/testsuite/ld-powerpc/ambiguousv1.d +++ b/ld/testsuite/ld-powerpc/ambiguousv1.d @@ -1,12 +1,44 @@ #source: startv1.s #source: funref.s #as: -a64 -#ld: -melf64ppc +#ld: -melf64ppc --emit-stub-syms #ld_after_inputfiles: tmpdir/funv1.so -#readelf: -r --wide -# check that we do the right thing with funref.s that doesn't have -# anything to mark it as ELFv1 or ELFv2 +#readelf: -rs --wide +# Check that we do the right thing with funref.s that doesn't have +# anything to mark it as ELFv1 or ELFv2. We should get a dynamic +# reloc on the function address, and my_func should be undefined +# dynamic with value zero. Relocation section .* contains 1 entries: .* .* R_PPC64_ADDR64 +0+ my_func \+ 0 + +Symbol table '\.dynsym' contains 5 entries: +.* + 0: .* + 1: 0+00000000 0 FUNC GLOBAL DEFAULT UND my_func + 2: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 __bss_start + 3: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 _edata + 4: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 _end + +Symbol table '\.symtab' contains 19 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: .* + 1: 0+10000158 0 SECTION LOCAL DEFAULT 1 + 2: 0+10000170 0 SECTION LOCAL DEFAULT 2 + 3: 0+10000198 0 SECTION LOCAL DEFAULT 3 + 4: 0+10000210 0 SECTION LOCAL DEFAULT 4 + 5: 0+10000248 0 SECTION LOCAL DEFAULT 5 + 6: 0+10000260 0 SECTION LOCAL DEFAULT 6 + 7: 0+10000264 0 SECTION LOCAL DEFAULT 7 + 8: 0+10010268 0 SECTION LOCAL DEFAULT 8 + 9: 0+10010368 0 SECTION LOCAL DEFAULT 9 + 10: 0+10010370 0 SECTION LOCAL DEFAULT 10 + 11: 0+10010388 0 SECTION LOCAL DEFAULT 11 + 12: 0+10010268 0 OBJECT LOCAL DEFAULT 8 _DYNAMIC + 13: 0+10010368 0 NOTYPE GLOBAL DEFAULT 9 func_tab + 14: 0+00000000 0 FUNC GLOBAL DEFAULT UND my_func + 15: 0+10010370 0 FUNC GLOBAL DEFAULT 10 _start + 16: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 __bss_start + 17: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 _edata + 18: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 _end diff --git a/ld/testsuite/ld-powerpc/ambiguousv1b.d b/ld/testsuite/ld-powerpc/ambiguousv1b.d new file mode 100644 index 00000000000..69bee95a629 --- /dev/null +++ b/ld/testsuite/ld-powerpc/ambiguousv1b.d @@ -0,0 +1,45 @@ +#source: startv1.s +#source: funref2.s +#as: -a64 +#ld: -melf64ppc --emit-stub-syms +#ld_after_inputfiles: tmpdir/funv1.so +#readelf: -rs --wide +# Check that we do the right thing with funref2.s that doesn't have +# anything to mark it as ELFv1 or ELFv2. Since my_func address is +# taken in a read-only section we should get a copy reloc for the OPD +# entry. + +Relocation section .* contains 1 entries: +.* +.* R_PPC64_COPY .* my_func \+ 0 + +Symbol table '\.dynsym' contains 5 entries: +.* + 0: .* + 1: 0+10010390 4 FUNC GLOBAL DEFAULT 12 my_func + 2: 0+10010390 0 NOTYPE GLOBAL DEFAULT 12 __bss_start + 3: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 _edata + 4: 0+10010398 0 NOTYPE GLOBAL DEFAULT 12 _end + +Symbol table '\.symtab' contains 20 entries: +.* + 0: .* + 1: 0+10000158 0 SECTION LOCAL DEFAULT 1 + 2: 0+10000170 0 SECTION LOCAL DEFAULT 2 + 3: 0+10000198 0 SECTION LOCAL DEFAULT 3 + 4: 0+10000210 0 SECTION LOCAL DEFAULT 4 + 5: 0+10000248 0 SECTION LOCAL DEFAULT 5 + 6: 0+10000260 0 SECTION LOCAL DEFAULT 6 + 7: 0+10000264 0 SECTION LOCAL DEFAULT 7 + 8: 0+1000026c 0 SECTION LOCAL DEFAULT 8 + 9: 0+10010270 0 SECTION LOCAL DEFAULT 9 + 10: 0+10010370 0 SECTION LOCAL DEFAULT 10 + 11: 0+10010388 0 SECTION LOCAL DEFAULT 11 + 12: 0+10010390 0 SECTION LOCAL DEFAULT 12 + 13: 0+10010270 0 OBJECT LOCAL DEFAULT 9 _DYNAMIC + 14: 0+10000264 0 NOTYPE GLOBAL DEFAULT 7 func_tab + 15: 0+10010390 4 FUNC GLOBAL DEFAULT 12 my_func + 16: 0+10010370 0 FUNC GLOBAL DEFAULT 10 _start + 17: 0+10010390 0 NOTYPE GLOBAL DEFAULT 12 __bss_start + 18: 0+10010390 0 NOTYPE GLOBAL DEFAULT 11 _edata + 19: 0+10010398 0 NOTYPE GLOBAL DEFAULT 12 _end diff --git a/ld/testsuite/ld-powerpc/ambiguousv2.d b/ld/testsuite/ld-powerpc/ambiguousv2.d index 5cf047bba1e..cfa5cb47a5b 100644 --- a/ld/testsuite/ld-powerpc/ambiguousv2.d +++ b/ld/testsuite/ld-powerpc/ambiguousv2.d @@ -1,12 +1,51 @@ #source: startv2.s #source: funref.s #as: -a64 -#ld: -melf64ppc +#ld: -melf64ppc --emit-stub-syms #ld_after_inputfiles: tmpdir/funv2.so -#readelf: -r --wide -# check that we do the right thing with funref.s that doesn't have -# anything to mark it as ELFv1 or ELFv2 +#readelf: -rs --wide +# Check that we do the right thing with funref.s that doesn't have +# anything to mark it as ELFv1 or ELFv2. We should get a dynamic +# reloc on the function address, not have a global entry stub, and +# my_func should be undefined dynamic with value zero. +# FIXME someday: No need for a plt entry. -Relocation section .*contains 1 entries: +Relocation section .* contains 1 entries: +.* +.* R_PPC64_ADDR64 .* my_func \+ 0 + +Relocation section .* contains 1 entries: .* .* R_PPC64_JMP_SLOT .* my_func \+ 0 + +Symbol table '\.dynsym' contains 5 entries: +.* + 0: .* + 1: 0+00000000 0 FUNC GLOBAL DEFAULT UND my_func + 2: 0+10010438 0 NOTYPE GLOBAL DEFAULT 12 __bss_start + 3: 0+10010438 0 NOTYPE GLOBAL DEFAULT 11 _edata + 4: 0+10010450 0 NOTYPE GLOBAL DEFAULT 12 _end + +Symbol table '\.symtab' contains 21 entries: +.* + 0: .* + 1: 0+10000158 0 SECTION LOCAL DEFAULT 1 + 2: 0+10000170 0 SECTION LOCAL DEFAULT 2 + 3: 0+10000198 0 SECTION LOCAL DEFAULT 3 + 4: 0+10000210 0 SECTION LOCAL DEFAULT 4 + 5: 0+10000248 0 SECTION LOCAL DEFAULT 5 + 6: 0+10000260 0 SECTION LOCAL DEFAULT 6 + 7: 0+10000278 0 SECTION LOCAL DEFAULT 7 + 8: 0+100002c4 0 SECTION LOCAL DEFAULT 8 + 9: 0+100102c8 0 SECTION LOCAL DEFAULT 9 + 10: 0+10010428 0 SECTION LOCAL DEFAULT 10 + 11: 0+10010430 0 SECTION LOCAL DEFAULT 11 + 12: 0+10010438 0 SECTION LOCAL DEFAULT 12 + 13: 0+100102c8 0 OBJECT LOCAL DEFAULT 9 _DYNAMIC + 14: 0+10000288 0 NOTYPE LOCAL DEFAULT 7 __glink_PLTresolve + 15: 0+10010428 0 NOTYPE GLOBAL DEFAULT 10 func_tab + 16: 0+00000000 0 FUNC GLOBAL DEFAULT UND my_func + 17: 0+10000278 0 NOTYPE GLOBAL DEFAULT 7 _start + 18: 0+10010438 0 NOTYPE GLOBAL DEFAULT 12 __bss_start + 19: 0+10010438 0 NOTYPE GLOBAL DEFAULT 11 _edata + 20: 0+10010450 0 NOTYPE GLOBAL DEFAULT 12 _end diff --git a/ld/testsuite/ld-powerpc/ambiguousv2b.d b/ld/testsuite/ld-powerpc/ambiguousv2b.d new file mode 100644 index 00000000000..a95faa7476b --- /dev/null +++ b/ld/testsuite/ld-powerpc/ambiguousv2b.d @@ -0,0 +1,47 @@ +#source: startv2.s +#source: funref2.s +#as: -a64 +#ld: -melf64ppc --emit-stub-syms +#ld_after_inputfiles: tmpdir/funv2.so +#readelf: -rs --wide +# Check that we do the right thing with funref2.s that doesn't have +# anything to mark it as ELFv1 or ELFv2. Since my_func address is +# taken in a read-only section we should get a plt entry, a global +# entry stub, and my_func should be undefined dynamic with non-zero +# value. + +Relocation section .* contains 1 entries: +.* +.* R_PPC64_JMP_SLOT .* my_func \+ 0 + +Symbol table '\.dynsym' contains 5 entries: +.* + 0: .* + 1: 0+100002b8 0 FUNC GLOBAL DEFAULT UND my_func + 2: 0+10010408 0 NOTYPE GLOBAL DEFAULT 11 __bss_start + 3: 0+10010408 0 NOTYPE GLOBAL DEFAULT 10 _edata + 4: 0+10010420 0 NOTYPE GLOBAL DEFAULT 11 _end + +Symbol table '\.symtab' contains 21 entries: +.* + 0: .* + 1: 0+10000158 0 SECTION LOCAL DEFAULT 1 + 2: 0+10000170 0 SECTION LOCAL DEFAULT 2 + 3: 0+10000198 0 SECTION LOCAL DEFAULT 3 + 4: 0+10000210 0 SECTION LOCAL DEFAULT 4 + 5: 0+10000248 0 SECTION LOCAL DEFAULT 5 + 6: 0+10000260 0 SECTION LOCAL DEFAULT 6 + 7: 0+100002c8 0 SECTION LOCAL DEFAULT 7 + 8: 0+100002d0 0 SECTION LOCAL DEFAULT 8 + 9: 0+100102d0 0 SECTION LOCAL DEFAULT 9 + 10: 0+10010400 0 SECTION LOCAL DEFAULT 10 + 11: 0+10010408 0 SECTION LOCAL DEFAULT 11 + 12: 0+100102d0 0 OBJECT LOCAL DEFAULT 9 _DYNAMIC + 13: 0+100002b8 0 NOTYPE LOCAL DEFAULT 6 00000011\.global_entry\.my_func + 14: 0+10000270 0 NOTYPE LOCAL DEFAULT 6 __glink_PLTresolve + 15: 0+100002c8 0 NOTYPE GLOBAL DEFAULT 7 func_tab + 16: 0+100002b8 0 FUNC GLOBAL DEFAULT UND my_func + 17: 0+10000260 0 NOTYPE GLOBAL DEFAULT 6 _start + 18: 0+10010408 0 NOTYPE GLOBAL DEFAULT 11 __bss_start + 19: 0+10010408 0 NOTYPE GLOBAL DEFAULT 10 _edata + 20: 0+10010420 0 NOTYPE GLOBAL DEFAULT 11 _end diff --git a/ld/testsuite/ld-powerpc/funref2.s b/ld/testsuite/ld-powerpc/funref2.s new file mode 100644 index 00000000000..a2bf9491264 --- /dev/null +++ b/ld/testsuite/ld-powerpc/funref2.s @@ -0,0 +1,4 @@ + .section .rodata,"a",@progbits + .globl func_tab +func_tab: + .dc.a my_func diff --git a/ld/testsuite/ld-powerpc/powerpc.exp b/ld/testsuite/ld-powerpc/powerpc.exp index 1eaedaaf163..08a7e2b53fb 100644 --- a/ld/testsuite/ld-powerpc/powerpc.exp +++ b/ld/testsuite/ld-powerpc/powerpc.exp @@ -275,7 +275,9 @@ if [ supports_ppc64 ] then { run_dump_test "elfv2-2so" run_dump_test "elfv2-2exe" run_dump_test "ambiguousv1" + run_dump_test "ambiguousv1b" run_dump_test "ambiguousv2" + run_dump_test "ambiguousv2b" } if { [istarget "powerpc*-eabi*"] } {