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.
This commit is contained in:
Alan Modra 2014-07-02 15:07:18 +09:30
parent 9b11e3a732
commit d1eca1e41d
10 changed files with 226 additions and 19 deletions

View file

@ -1,3 +1,9 @@
2014-07-02 Alan Modra <amodra@gmail.com>
* 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 <amodra@gmail.com> 2014-07-02 Alan Modra <amodra@gmail.com>
* elf32-ppc.c (ppc_elf_check_relocs): Set DF_STATIC_TLS for PIEs too. * elf32-ppc.c (ppc_elf_check_relocs): Set DF_STATIC_TLS for PIEs too.

View file

@ -5506,9 +5506,21 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
will go to this object, or will remain undefined. */ will go to this object, or will remain undefined. */
h->plt.plist = NULL; h->plt.plist = NULL;
h->needs_plt = 0; h->needs_plt = 0;
h->pointer_equality_needed = 0;
} }
else 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 /* After adjust_dynamic_symbol, non_got_ref set in the
non-shared case means that we have allocated space in non-shared case means that we have allocated space in
.dynbss for the symbol and thus dyn_relocs for this .dynbss for the symbol and thus dyn_relocs for this
@ -5518,7 +5530,7 @@ ppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
relocations against this symbol to the PLT entry. Allow relocations against this symbol to the PLT entry. Allow
dynamic relocs if the reference is weak, and the dynamic dynamic relocs if the reference is weak, and the dynamic
relocs will not cause text relocation. */ relocs will not cause text relocation. */
if (!h->ref_regular_nonweak else if (!h->ref_regular_nonweak
&& h->non_got_ref && h->non_got_ref
&& h->type != STT_GNU_IFUNC && h->type != STT_GNU_IFUNC
&& !htab->is_vxworks && !htab->is_vxworks

View file

@ -6993,9 +6993,21 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
{ {
h->plt.plist = NULL; h->plt.plist = NULL;
h->needs_plt = 0; h->needs_plt = 0;
h->pointer_equality_needed = 0;
} }
else if (abiversion (info->output_bfd) == 2) 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 /* After adjust_dynamic_symbol, non_got_ref set in the
non-shared case means that we have allocated space in non-shared case means that we have allocated space in
.dynbss for the symbol and thus dyn_relocs for this .dynbss for the symbol and thus dyn_relocs for this
@ -7005,7 +7017,7 @@ ppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info,
relocations against this symbol to the PLT entry. Allow relocations against this symbol to the PLT entry. Allow
dynamic relocs if the reference is weak, and the dynamic dynamic relocs if the reference is weak, and the dynamic
relocs will not cause text relocation. */ relocs will not cause text relocation. */
if (!h->ref_regular_nonweak else if (!h->ref_regular_nonweak
&& h->non_got_ref && h->non_got_ref
&& h->type != STT_GNU_IFUNC && h->type != STT_GNU_IFUNC
&& !readonly_dynrelocs (h)) && !readonly_dynrelocs (h))

View file

@ -1,3 +1,11 @@
2014-07-02 Alan Modra <amodra@gmail.com>
* 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 <kyle@redhat.com> 2014-06-25 Kyle McMartin <kyle@redhat.com>
* ld-arm/tls-gdierelax2.d: Fix expected offsets. * ld-arm/tls-gdierelax2.d: Fix expected offsets.

View file

@ -1,12 +1,44 @@
#source: startv1.s #source: startv1.s
#source: funref.s #source: funref.s
#as: -a64 #as: -a64
#ld: -melf64ppc #ld: -melf64ppc --emit-stub-syms
#ld_after_inputfiles: tmpdir/funv1.so #ld_after_inputfiles: tmpdir/funv1.so
#readelf: -r --wide #readelf: -rs --wide
# check that we do the right thing with funref.s that doesn't have # Check that we do the right thing with funref.s that doesn't have
# anything to mark it as ELFv1 or ELFv2 # 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: Relocation section .* contains 1 entries:
.* .*
.* R_PPC64_ADDR64 +0+ my_func \+ 0 .* 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

View file

@ -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

View file

@ -1,12 +1,51 @@
#source: startv2.s #source: startv2.s
#source: funref.s #source: funref.s
#as: -a64 #as: -a64
#ld: -melf64ppc #ld: -melf64ppc --emit-stub-syms
#ld_after_inputfiles: tmpdir/funv2.so #ld_after_inputfiles: tmpdir/funv2.so
#readelf: -r --wide #readelf: -rs --wide
# check that we do the right thing with funref.s that doesn't have # Check that we do the right thing with funref.s that doesn't have
# anything to mark it as ELFv1 or ELFv2 # 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:
.*
.* R_PPC64_ADDR64 .* my_func \+ 0
Relocation section .* contains 1 entries: Relocation section .* contains 1 entries:
.* .*
.* R_PPC64_JMP_SLOT .* my_func \+ 0 .* 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

View file

@ -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

View file

@ -0,0 +1,4 @@
.section .rodata,"a",@progbits
.globl func_tab
func_tab:
.dc.a my_func

View file

@ -275,7 +275,9 @@ if [ supports_ppc64 ] then {
run_dump_test "elfv2-2so" run_dump_test "elfv2-2so"
run_dump_test "elfv2-2exe" run_dump_test "elfv2-2exe"
run_dump_test "ambiguousv1" run_dump_test "ambiguousv1"
run_dump_test "ambiguousv1b"
run_dump_test "ambiguousv2" run_dump_test "ambiguousv2"
run_dump_test "ambiguousv2b"
} }
if { [istarget "powerpc*-eabi*"] } { if { [istarget "powerpc*-eabi*"] } {