From 647d4de92e061a3a2be83740d7f1bf63e5669630 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 24 Aug 2017 09:26:37 +0930 Subject: [PATCH] Test undefined symbols in shared libraries git commit 46434633f9 said Make undefined symbols in allocate_dynrelocs dynamic ..if they have dynamic relocs. An undefined symbol in a PIC object that finds no definition ought to become dynamic in order to support --allow-shlib-undefined, but there is nothing in the generic ELF linker code to do this if the reference isn't via the GOT or PLT. (An initialized function pointer is an example.) So it falls to backend code to ensure the symbol is made dynamic. The above isn't true. Undefined symbols are indeed made dynamic for shared libraries. Undefined symbols are not automatically made dynamic in executables, and it was the PIE case that triggered an internal consistency assertion on powerpc64. I guess I could have jumped the other way when fixing PR21988, and not created a dynamic reloc. Either way, it doesn't matter a great deal. We're going to get an error on strong undefined symbols in an executable anyway, and broken binaries if you try to use --unresolved-symbols=ignore-all to disable the error. * testsuite/ld-undefined/fundef.s: New test. * testsuite/ld-undefined/undefined.exp: Test that undefined symbols in shared libraries are made dynamic. --- ld/ChangeLog | 6 + ld/testsuite/ld-undefined/fundef.s | 31 +++ ld/testsuite/ld-undefined/undefined.exp | 256 +++++++++++++++--------- 3 files changed, 195 insertions(+), 98 deletions(-) create mode 100644 ld/testsuite/ld-undefined/fundef.s diff --git a/ld/ChangeLog b/ld/ChangeLog index 930a6cc3d4a..bf303708671 100644 --- a/ld/ChangeLog +++ b/ld/ChangeLog @@ -1,3 +1,9 @@ +2017-08-24 Alan Modra + + * testsuite/ld-undefined/fundef.s: New test. + * testsuite/ld-undefined/undefined.exp: Test that undefined + symbols in shared libraries are made dynamic. + 2017-08-23 H.J. Lu * testsuite/ld-elf/pr21903c.d: Add '\' before --. diff --git a/ld/testsuite/ld-undefined/fundef.s b/ld/testsuite/ld-undefined/fundef.s new file mode 100644 index 00000000000..96eb668ac6e --- /dev/null +++ b/ld/testsuite/ld-undefined/fundef.s @@ -0,0 +1,31 @@ + .text + .type undef_fun_typed %function + .ifdef BL + bl undef_fun_typed + nop + bl undef_fun_notype + nop + .endif + .ifdef BLPLT + bl undef_fun_typed@plt + nop + bl undef_fun_notype@plt + nop + .endif + .ifdef CALLPLT + call undef_fun_typed@plt + call undef_fun_notype@plt + .endif + .ifdef HPPA + bl undef_fun_typed,%r2 + nop + bl undef_fun_notype,%r2 + nop + .endif + + .data + .type undef_data %object + .dc.a undef_data + .type undef_pfun %function + .dc.a undef_pfun + .dc.a undef_notype diff --git a/ld/testsuite/ld-undefined/undefined.exp b/ld/testsuite/ld-undefined/undefined.exp index a9ba9bb83e0..c0c9012e750 100644 --- a/ld/testsuite/ld-undefined/undefined.exp +++ b/ld/testsuite/ld-undefined/undefined.exp @@ -29,119 +29,179 @@ if { ![is_remote host] && [which $CC] == 0 } { untested $testund untested $testfn untested $testline - return -} - -if ![ld_compile "$CC -g" $srcdir/$subdir/undefined.c tmpdir/undefined.o] { +} elseif { ![ld_compile "$CC -g" $srcdir/$subdir/undefined.c tmpdir/undefined.o] } { verbose "Unable to compile test file!" 1 unresolved $testund unresolved $testfn unresolved $testline - return -} +} else { + remote_file host delete "tmpdir/undefined" -remote_file host delete "tmpdir/undefined" + set flags [big_or_little_endian] -set flags [big_or_little_endian] + # Using -e start prevents the SunOS linker from trying to build a + # shared library. + send_log "$ld -e start $flags -o tmpdir/undefined tmpdir/undefined.o\n" + set exec_output [run_host_cmd "$ld" "-e start $flags -o tmpdir/undefined tmpdir/undefined.o"] -# Using -e start prevents the SunOS linker from trying to build a -# shared library. -send_log "$ld -e start $flags -o tmpdir/undefined tmpdir/undefined.o\n" -set exec_output [run_host_cmd "$ld" "-e start $flags -o tmpdir/undefined tmpdir/undefined.o"] + send_log "$exec_output\n" + verbose "$exec_output" -send_log "$exec_output\n" -verbose "$exec_output" + proc checkund { string testname } { + global exec_output -proc checkund { string testname } { - global exec_output - - if [string match "*$string*" $exec_output] { - pass $testname - } else { - fail $testname + if [string match "*$string*" $exec_output] { + pass $testname + } else { + fail $testname + } } -} -set mu "undefined reference to `*this_function_is_not_defined'" -checkund $mu $testund + set mu "undefined reference to `*this_function_is_not_defined'" + checkund $mu $testund -# ARM PE defaults to using stabs debugging, which we can't handle for -# a COFF file. -#setup_xfail "arm*-*-pe*" + # ARM PE defaults to using stabs debugging, which we can't handle + # for a COFF file. + #setup_xfail "arm*-*-pe*" -# For Xtensa on GNU Linux systems (or any other system where PIC code is -# always used), the address of the undefined function is in a literal pool -# outside the function, so that both the "undefined function" and "undefined -# line" tests fail. -setup_xfail xtensa*-*-linux* + # For Xtensa on GNU Linux systems (or any other system where PIC + # code is always used), the address of the undefined function is + # in a literal pool outside the function, so that both the + # "undefined function" and "undefined line" tests fail. + setup_xfail xtensa*-*-linux* -set mf "tmpdir/undefined.o* In function `function':" -checkund $mf $testfn + set mf "tmpdir/undefined.o* In function `function':" + checkund $mf $testfn -if ![is_elf_format] { - # COFF SH gets this test wrong--it reports line 10, because although - # the jump is at line 9, the function address, and the reloc, is - # stored at the end of the function. - setup_xfail "sh-*-*" + if ![is_elf_format] { + # COFF SH gets this test wrong--it reports line 10, because + # although the jump is at line 9, the function address, and + # the reloc, is stored at the end of the function. + setup_xfail "sh-*-*" - # ARM PE defaults to using stabs debugging, which we can't handle for - # a COFF file. - #setup_xfail "arm*-*-pe*" + # ARM PE defaults to using stabs debugging, which we can't + # handle for a COFF file. + #setup_xfail "arm*-*-pe*" + } + + set ml "undefined.c:9: undefined reference to `*this_function_is_not_defined'" + # With targets that use elf/dwarf2, such as the arm-elf toolchain, + # the code in bfd/elf.c:_bfd_elf_find_nearest_line() is called in + # order to locate the file name/line number where the undefined + # reference occurs. Unfortunately this tries to use the dwarf2 + # debug information held in the .debug_info section. This section + # contains a series of comp_unit structures, each of which has a + # low/high address range representing the span of memory locations + # covered by that structure. The structures also index into other + # structures held in the .debug_line section and together they can + # translate memory locations back into file/function/line number + # addresses in the source code. Since the information about the + # memory region covered by a comp_unit is only determined at link + # time, the low/high addresses in the .debug_info section and the + # line addresses in the .debug_line section are computed by + # generating relocs against known symbols in the object code. + # + # When the undefined reference is detected, the relocs in the + # dwarf2 debug sections have not yet been resolved, so the + # low/high addresses and the line number address are all set at + # zero. Thus when _bfd_elf_find_nearest_line() calls + # _bfd_dwarf2_find_nearest_line() no comp_unit can be found which + # actually covers the address where the reference occurred, and so + # _bfd_elf_find_nearest_line() fails. + # + # The upshot of all of this, is that the error message reported by + # the linker, instead of having a source file name & line number + # as in: + # + # undefined.c:9: undefined reference to `this_function_is_not_defined' + # + # has an object file & section address instead: + # + # undefined.0(.text+0xc): undefined reference to `this_function_is_not_defined' + # + # hence the xfails below. + + setup_xfail mcore-*-elf + setup_xfail mep-*-* + setup_xfail mips-sgi-irix6* + setup_xfail "sh64-*-*" + # Fails for the MSP430 because it uses SYM_DIFF relocs but it does + # not provide a special_function for handling them. If + # optimization is enabled then this test passes because + # function()'s prologue is eliminated. + setup_xfail "msp430-*-*" + + # The undefined test fails on 31 bit s/390 because the address of + # the function `this_function_is_not_defined' is stored in the + # literal pool of the function. Therefore the line number in the + # error message is 8 instead of 9. On 64 bit s/390 this works + # because of the new brasl instruction that doesn't need a literal + # pool entry. + setup_xfail s390-*-* + + # See comments above for Xtensa. + setup_xfail xtensa*-*-linux* + setup_xfail hppa*64*-*-* + + checkund $ml $testline } -set ml "undefined.c:9: undefined reference to `*this_function_is_not_defined'" -# With targets that use elf/dwarf2, such as the arm-elf -# toolchain, the code in bfd/elf.c:_bfd_elf_find_nearest_line() is called -# in order to locate the file name/line number where the undefined -# reference occurs. Unfortunately this tries to use the dwarf2 debug -# information held in the .debug_info section. This section contains a series -# of comp_unit structures, each of which has a low/high address range -# representing the span of memory locations covered by that structure. The -# structures also index into other structures held in the .debug_line section -# and together they can translate memory locations back into file/function/line -# number addresses in the source code. Since the information about the memory -# region covered by a comp_unit is only determined at link time, the low/high -# addresses in the .debug_info section and the line addresses in the .debug_line -# section are computed by generating relocs against known symbols in the object -# code. -# -# When the undefined reference is detected, the relocs in the dwarf2 -# debug sections have not yet been resolved, so the low/high addresses and the -# line number address are all set at zero. Thus when _bfd_elf_find_nearest_line() -# calls _bfd_dwarf2_find_nearest_line() no comp_unit can be found which -# actually covers the address where the reference occurred, and so -# _bfd_elf_find_nearest_line() fails. -# -# The upshot of all of this, is that the error message reported by the -# linker, instead of having a source file name & line number as in: -# -# undefined.c:9: undefined reference to `this_function_is_not_defined' -# -# has an object file & section address instead: -# -# undefined.0(.text+0xc): undefined reference to `this_function_is_not_defined' -# -# hence the xfails below. - -setup_xfail mcore-*-elf -setup_xfail mep-*-* -setup_xfail mips-sgi-irix6* -setup_xfail "sh64-*-*" -# Fails for the MSP430 because it uses SYM_DIFF relocs but it does -# not provide a special_function for handling them. If optimization -# is enabled then this test passes because function()'s prologue is -# eliminated. -setup_xfail "msp430-*-*" - -# The undefined test fails on 31 bit s/390 because the address of the -# function `this_function_is_not_defined' is stored in the literal pool of -# the function. Therefore the line number in the error message is 8 instead -# of 9. On 64 bit s/390 this works because of the new brasl instruction that -# doesn't need a literal pool entry. -setup_xfail s390-*-* - -# See comments above for Xtensa. -setup_xfail xtensa*-*-linux* -setup_xfail hppa*64*-*-* - -checkund $ml $testline +# Undefined symbols should become dynamic when linking a shared lib. +set testname "undefined symbols in shared lib" + +set asflags "" +switch -glob $target_triplet { + aarch64* - + arm* - + powerpc64* { set asflags "--defsym BL=1" } + powerpc* { set asflags "--defsym BLPLT=1" } + hppa* { set asflags "--defsym HPPA=1" } + i\[3-7\]86* - + x86_64* { set asflags "--defsym CALLPLT=1" } +} + +if { ![is_elf_format] || ![check_shared_lib_support]} then { + unsupported $testname +} elseif {![ld_assemble $as "$asflags $srcdir/$subdir/fundef.s" \ + tmpdir/fundef.o]} then { + fail $testname +} elseif {![ld_link $ld tmpdir/fundef.so \ + "-shared --allow-shlib-undefined tmpdir/fundef.o"]} then { + setup_xfail tic6x-*-* + fail $testname +} else { + if {![is_remote host] && [which $nm] == 0} then { + unresolved "$testname (dyn sym)" + } else { + set exec_output [run_host_cmd "$nm" "-D tmpdir/fundef.so"] + set exec_output [prune_warnings $exec_output] + + if { ($asflags == "" + || ([regexp ".* undef_fun_typed.*" $exec_output] + && [regexp ".* undef_fun_notype.*" $exec_output])) + && [regexp ".* undef_data.*" $exec_output] + && [regexp ".* undef_pfun.*" $exec_output] + && [regexp ".* undef_notype.*" $exec_output]} then { + pass "$testname (dyn sym)" + } else { + fail "$testname (dyn sym)" + } + } + + global READELF + if {![is_remote host] && [which $READELF] == 0} then { + unresolved "$testname (dyn reloc)" + } else { + set exec_output [run_host_cmd "$READELF" "-r tmpdir/fundef.so"] + set exec_output [prune_warnings $exec_output] + + # we ought to get two .rel{a}.plt and three .rel{a}.dyn relocs + if { ($asflags == "" || [regexp ".* contains 2 .*" $exec_output]) + && [regexp ".* contains 3 .*" $exec_output] + && ![regexp "_NONE" $exec_output]} then { + pass "$testname (dyn reloc)" + } else { + fail "$testname (dyn reloc)" + } + } +} -- 2.30.2