# Support routines for LD testsuite.
-# Copyright (C) 1994-2016 Free Software Foundation, Inc.
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
#
# This file is part of the GNU Binutils.
#
set CC [find_gcc]
}
if { $CC == "" } {
- return 0
+ return 0
}
set state [remote_exec host $CC --version]
+ if { [lindex $state 0] != 0 } {
+ return 0;
+ }
set tmp "[lindex $state 1]\n"
# Look for (eg) 4.6.1 in the version output.
set ver_re "\[^\\.0-9\]+(\[1-9\]\[0-9\]*)\\.(\[0-9\]+)(?:\\.\[0-9\]+)?"
return $flags
}
-# Link a program using ld.
+# Link a program using ld
#
proc default_ld_link { ld target objects } {
- global HOSTING_EMU
- global HOSTING_CRT0
- global HOSTING_SCRT0
- global HOSTING_LIBS
- global HOSTING_SLIBS
- global LIBS
- global host_triplet
- global link_output
- global exec_output
-
- if { [ string match "* -pie *" $objects ] } {
- set objs "$HOSTING_SCRT0 $objects"
- set libs "$LIBS $HOSTING_SLIBS"
- } else {
- set objs "$HOSTING_CRT0 $objects"
- set libs "$LIBS $HOSTING_LIBS"
- }
-
- if [is_endian_output_format $objects] then {
- set flags [big_or_little_endian]
- } else {
- set flags ""
- }
-
- remote_file host delete $target
-
- return [run_host_cmd_yesno "$ld" "$HOSTING_EMU $flags -o $target $objs $libs"]
-}
-
-# Link a program using ld, without including any libraries.
-#
-proc default_ld_simple_link { ld target objects } {
global host_triplet
global exec_output
remote_file build delete "ld.tmp"
remote_file host delete "ld.tmp"
set exec_output [prune_warnings $exec_output]
+ # Versions of gcc up to and including pre-release gcc-7, at least on
+ # some targets, generate .section directives with incorrect type.
+ # Ignore warnings from the assembler about this.
+ regsub -all "(^|\n)\[^\n\]*: ignoring incorrect section type \[^\n\]*" $exec_output "" exec_output
+ regsub -all "^\[^\n\]*: Assembler messages:\n" $exec_output "" exec_output
if [string match "" $exec_output] then {
if {![file exists $object]} then {
regexp ".*/(\[^/\]*)$" $source all dobj
# Define various symbols needed when not linking against all
# target libs.
-proc ld_simple_link_defsyms {} {
+proc ld_link_defsyms {} {
set flags "--defsym __stack_chk_fail=0"
global OBJDUMPFLAGS NMFLAGS ASFLAGS OBJCOPYFLAGS READELFFLAGS LDFLAGS
global host_triplet runtests
global env verbose
+ global ld_elf_shared_opt
+
+ if { [is_elf_format] && [check_shared_lib_support] } {
+ set ld_extra_opt "$ld_elf_shared_opt"
+ } else {
+ set ld_extra_opt ""
+ }
if [string match "*/*" $name] {
set file $name
set dumpfile tmpdir/dump.out
set run_ld 0
set run_objcopy 0
+ set objfile_names {}
set opts(as) {}
set opts(ld) {}
set opts(ld_after_inputfiles) {}
} else {
lappend asflags {}
}
+
+ # Create the object file name based on nothing but the source
+ # file name.
+ set new_objfile \
+ [concat tmpdir/[file rootname [file tail [lindex $opt_val 0]]].o]
+ # But, sometimes, we have the exact same source filename in
+ # different directories (foo/src.s bar/src.s) which would lead
+ # us to try and create two src.o files. We detect this
+ # conflict here, and instead create src.o and src1.o.
+ set j 0
+ while { [lsearch $objfile_names $new_objfile] != -1 } {
+ incr j
+ set new_objfile \
+ [concat tmpdir/[file rootname [file tail [lindex $opt_val 0]]]${j}.o]
+ }
+ lappend objfile_names $new_objfile
}
default {
if [string length $opts($opt_name)] {
if { $opts(source) == "" } {
set sourcefiles [list ${file}.s]
set asflags [list ""]
+ set objfile_names [list tmpdir/[file tail ${file}].o]
} else {
set sourcefiles {}
foreach sf $opts(source) {
}
regsub "RUN_OBJCOPY" $sourceasflags "" sourceasflags
- set objfile "tmpdir/dump$i.o"
+ set objfile [lindex $objfile_names $i]
catch "exec rm -f $objfile" exec_output
lappend objfiles $objfile
set cmd "$AS $ASFLAGS $opts(as) $sourceasflags -o $objfile $sourcefile"
remote_file build delete "ld.tmp"
if { [lindex $cmdret 0] != 0 || ![string match "" $comp_output] } then {
- send_log "$comp_output\n"
+ send_log -- "$comp_output\n"
verbose "$comp_output" 3
set exitstat "succeeded"
if { [lindex $cmdret 0] != 0 \
|| ![string match "" $comp_output] } {
- send_log "$comp_output\n"
+ send_log -- "$comp_output\n"
verbose "$comp_output" 3
set exitstat "succeeded"
# Add -L$srcdir/$subdir so that the linker command can use
# linker scripts in the source directory.
- set cmd "$LD $LDFLAGS -L$srcdir/$subdir \
+ set cmd "$LD $ld_extra_opt $LDFLAGS -L$srcdir/$subdir \
$opts(ld) -o $objfile $objfiles $opts(ld_after_inputfiles)"
# If needed then check for, or add a -Map option.
set exitstat "succeeded"
if { $cmdret != 0 } { set exitstat "failed" }
- if { $check_ld(source) == "regexp" } {
+ if { $check_ld(source) == "regex" } {
verbose -log "$exitstat with: <$comp_output>, expected: <$check_ld(regex)>"
} elseif { $check_ld(source) == "file" } {
verbose -log "$exitstat with: <$comp_output>, expected in file $check_ld(file)"
} else {
verbose -log "$exitstat with: <$comp_output>, no expected output"
}
- send_log "$comp_output\n"
+ send_log -- "$comp_output\n"
verbose "$comp_output" 3
if { (($check_ld(source) == "") == ($comp_output == "")) \
}
}
} else {
- set objfile "tmpdir/dump0.o"
+ set objfile [lindex $objfiles 0]
}
# We must not have expected failure if we get here.
# in all other cases, any output from the linker during linking is
# treated as a sign of an error and FAILs the test.
#
-proc run_ld_link_tests { ldtests } {
+# args is an optional list of target triplets to be xfailed.
+#
+proc run_ld_link_tests { ldtests args } {
global ld
global as
global nm
global CFLAGS
global runtests
global exec_output
+ global ld_elf_shared_opt
+
+ if { [is_elf_format] && [check_shared_lib_support] } {
+ set ld_extra_opt "$ld_elf_shared_opt"
+ } else {
+ set ld_extra_opt ""
+ }
foreach testitem $ldtests {
set testname [lindex $testitem 0]
continue
}
+ foreach target $args {
+ setup_xfail $target
+ }
+
set ld_options [lindex $testitem 1]
set ld_after [lindex $testitem 2]
set as_options [lindex $testitem 3]
if { ![ar_simple_create $ar $ld_options $binfile "$objfiles $ld_after"] } {
set failed 1
}
- } elseif { ![ld_simple_link $ld $binfile "-L$srcdir/$subdir $ld_options $objfiles $ld_after"] } {
+ } elseif { ![ld_link $ld $binfile "$ld_extra_opt -L$srcdir/$subdir $ld_options $objfiles $ld_after"] } {
set maybe_failed 1
set ld_output "$exec_output"
}
}
}
-# targets_to_xfail is a list of target triplets to be xfailed.
# ldtests contains test-items with 3 items followed by 1 lists, 2 items
# and 3 optional items:
# 0:name
# 6:compiler flags (optional)
# 7:language (optional)
# 8:linker warning (optional)
+# args is an optional list of target triplets to be xfailed.
-proc run_ld_link_exec_tests { targets_to_xfail ldtests } {
+proc run_ld_link_exec_tests { ldtests args } {
global ld
global as
global srcdir
global CXXFLAGS
global errcnt
global exec_output
+ global board_cflags
+
+ # When using GCC as the linker driver, we need to specify board cflags when
+ # linking because cflags may contain linker options. For example when
+ # linker options are included in GCC spec files then we need the -specs
+ # option.
+ if [board_info [target_info name] exists cflags] {
+ set board_cflags " [board_info [target_info name] cflags]"
+ } else {
+ set board_cflags ""
+ }
foreach testitem $ldtests {
- foreach target $targets_to_xfail {
+ foreach target $args {
setup_xfail $target
}
set testname [lindex $testitem 0]
set objfile "tmpdir/$fileroot.o"
lappend objfiles $objfile
- # We ignore warnings since some compilers may generate
- # incorrect section attributes and the assembler will warn
- # them.
if { [ string match "c++" $lang ] } {
- ld_compile "$CXX -c $CXXFLAGS $cflags" $srcdir/$subdir/$src_file $objfile
+ set cmd "$CXX -c $CXXFLAGS $cflags"
} else {
- ld_compile "$CC -c $CFLAGS $cflags" $srcdir/$subdir/$src_file $objfile
+ set cmd "$CC -c $CFLAGS $cflags"
}
+ if ![ld_compile $cmd $srcdir/$subdir/$src_file $objfile] {
+ set failed 1
+ break
+ }
+ }
+ if { $failed != 0 } {
+ unresolved $testname
+ continue
}
- # We have to use $CC to build PIE and shared library.
- if { [ string match "c" $lang ] } {
- set link_proc ld_simple_link
- set link_cmd $CC
- } elseif { [ string match "c++" $lang ] } {
- set link_proc ld_simple_link
+ if { [ string match "c++" $lang ] } {
+ set link_proc ld_link
set link_cmd $CXX
- } elseif { [ string match "-shared" $ld_options ] \
- || [ string match "-pie" $ld_options ] } {
- set link_proc ld_simple_link
- set link_cmd $CC
} else {
set link_proc ld_link
- set link_cmd $ld
+ set link_cmd $CC
}
if { $binfile eq "tmpdir/" } {
# compile only
pass $testname
continue;
- } elseif ![$link_proc $link_cmd $binfile "-L$srcdir/$subdir $ld_options $objfiles"] {
+ } elseif ![$link_proc $link_cmd $binfile "$board_cflags -L$srcdir/$subdir $ld_options $objfiles"] {
set failed 1
}
}
}
- if { $failed == 0 } {
+ if { $failed == 0 && [isnative] } {
send_log "Running: $binfile > $binfile.out\n"
verbose "Running: $binfile > $binfile.out"
catch "exec $binfile > $binfile.out" exec_output
if { $failed != 0 } {
fail $testname
+ } elseif ![isnative] {
+ unsupported $testname
} else {
set errcnt 0
pass $testname
# 4:action and options.
# 5:name of output file
# 6:language (optional)
-# 7:linker warnings (optional)
#
# Actions:
# objdump: Apply objdump options on result. Compare with regex (last arg).
# nm: Apply nm options on result. Compare with regex (last arg).
# readelf: Apply readelf options on result. Compare with regex (last arg).
+# warning: Check linker output against regex (last arg).
+# error: Like 'warning' but checking output in error case.
+# warning_output: Check linker output against regex in a file (last arg).
+# error_output: Like 'warning_output' but checking output in error case.
#
proc run_cc_link_tests { ldtests } {
global nm
set actions [lindex $testitem 4]
set binfile tmpdir/[lindex $testitem 5]
set lang [lindex $testitem 6]
- set warnings [lindex $testitem 7]
set objfiles {}
set is_unresolved 0
set failed 0
+ set check_ld(terminal) 0
+ set check_ld(source) ""
#verbose -log "testname is $testname"
#verbose -log "ldflags is $ldflags"
#verbose -log "actions is $actions"
#verbose -log "binfile is $binfile"
#verbose -log "lang is $lang"
- #verbose -log "warnings is $warnings"
+
+ foreach actionlist $actions {
+ set action [lindex $actionlist 0]
+ set progopts [lindex $actionlist 1]
+
+ # Find actions related to error/warning processing.
+ switch -- $action {
+ error
+ {
+ set check_ld(source) "regexp"
+ set check_ld(regexp) $progopts
+ set check_ld(terminal) 1
+ }
+ warning
+ {
+ set check_ld(source) "regexp"
+ set check_ld(regexp) $progopts
+ }
+ error_output
+ {
+ set check_ld(source) "file"
+ set check_ld(file) $progopts
+ set check_ld(terminal) 1
+ }
+ warning_output
+ {
+ set check_ld(source) "file"
+ set check_ld(file) $progopts
+ }
+ }
+ }
# Compile each file in the test.
foreach src_file $src_files {
set objfile "tmpdir/$fileroot.o"
lappend objfiles $objfile
- # We ignore warnings since some compilers may generate
- # incorrect section attributes and the assembler will warn
- # them.
if { [ string match "c++" $lang ] } {
- ld_compile "$CXX -c $CXXFLAGS $cflags" $srcdir/$subdir/$src_file $objfile
+ set cmd "$CXX -c $CXXFLAGS $cflags"
} else {
- ld_compile "$CC -c $CFLAGS $cflags" $srcdir/$subdir/$src_file $objfile
+ set cmd "$CC -c $CFLAGS $cflags"
}
+ if ![ld_compile $cmd $srcdir/$subdir/$src_file $objfile] {
+ set failed 1
+ break
+ }
+ }
+ if { $failed != 0 } {
+ unresolved $testname
+ continue
}
# Clear error and warning counts.
# compile only
} elseif { [regexp ".*\\.a$" $binfile] } {
if { ![ar_simple_create $ar $ldflags $binfile "$objfiles"] } {
- fail $testname
set failed 1
}
} else {
- if { ![ld_simple_link $cc_cmd $binfile "$board_cflags -L$srcdir/$subdir $ldflags $objfiles"] } {
- set failed 1
- }
+ ld_link $cc_cmd $binfile "$board_cflags -L$srcdir/$subdir $ldflags $objfiles"
+ set ld_output "$exec_output"
- # Check if exec_output is expected.
- if { $warnings != "" } then {
- verbose -log "returned with: <$exec_output>, expected: <$warnings>"
- if { [regexp $warnings $exec_output] } then {
- set failed 0
- } else {
+ if { $check_ld(source) == "regexp" } then {
+ # Match output against regexp argument.
+ verbose -log "returned with: <$ld_output>, expected: <$check_ld(regexp)>"
+ if { ![regexp $check_ld(regexp) $ld_output] } then {
+ set failed 1
+ }
+ } elseif { $check_ld(source) == "file" } then {
+ # Match output against patterns in a file.
+ set_file_contents "tmpdir/ld.messages" "$ld_output"
+ verbose "ld.messages has '[file_contents tmpdir/ld.messages]'"
+ if { [regexp_diff "tmpdir/ld.messages" "$srcdir/$subdir/$check_ld(file)"] } then {
+ verbose "output is $ld_output" 2
set failed 1
}
}
- if { $failed == 1 } {
- fail $testname
+ if { $check_ld(source) != "" } then {
+ if { $ld_output == "" } then {
+ verbose -log "Linker was expected to give error or warning"
+ set failed 1
+ }
+ } else {
+ if { $ld_output != "" } then {
+ verbose -log "Unexpected linker warning or error"
+ set failed 1
+ }
}
}
{ set dump_prog $nm }
readelf
{ set dump_prog $READELF }
+ error {}
+ warning {}
+ error_output {}
+ warning_output {}
default
{
perror "Unrecognized action $action"
}
}
- if { $failed != 0 } {
+ if { $failed } {
fail $testname
- } elseif { $is_unresolved == 0 } {
- pass $testname
- } else {
+ } elseif { $is_unresolved } {
unresolved $testname
- continue
+ } else {
+ pass $testname
}
}
}
if {![info exists gc_sections_available_saved]} {
# Some targets don't support gc-sections despite whatever's
# advertised by ld's options.
- if { [istarget arc*-*-*]
- || [istarget d30v-*-*]
+ if { [istarget d30v-*-*]
|| [istarget dlx-*-*]
|| [istarget i960-*-*]
|| [istarget pj*-*-*]
+ || [istarget pru*-*-*]
|| [istarget alpha-*-*]
|| [istarget hppa*64-*-*]
|| [istarget i370-*-*]
proc check_shared_lib_support { } {
if {![istarget aarch64*-*-elf]
- && ![istarget arc*-*-*]
+ && ![istarget arc*-*-elf*]
&& ![istarget arm*-*-elf]
&& ![istarget avr-*-*]
&& ![istarget cr16-*-*]
&& ![istarget dlx-*-*]
&& ![istarget epiphany-*-*]
&& ![istarget fr30-*-*]
- && ![istarget ft32-*-*]
&& ![istarget frv-*-*]
+ && ![istarget ft32-*-*]
&& ![istarget h8300-*-*]
&& ![istarget i860-*-*]
&& ![istarget i960-*-*]
&& ![istarget msp430-*-*]
&& ![istarget mt-*-*]
&& ![istarget nds32*-*-*]
+ && ![istarget nios2-*-elf]
&& ![istarget or1k*-*-*]
&& ![istarget pj-*-*]
+ && ![istarget pru-*-*]
&& ![istarget rl78-*-*]
&& ![istarget rx-*-*]
&& ![istarget spu-*-*]
&& ![istarget v850*-*-*]
&& ![istarget visium-*-*]
+ && ![istarget xc16x-*-elf]
&& ![istarget xgate-*-*]
&& ![istarget xstormy16-*-*]
&& ![istarget *-*-irix*]
return 0
}
+# Return true if target uses genelf.em (assuming it is ELF).
+proc is_generic_elf { } {
+ if { [istarget "d30v-*-*"]
+ || [istarget "dlx-*-*"]
+ || [istarget "fr30-*-*"]
+ || ([istarget "frv-*-*"] && ![istarget "frv-*-linux*"])
+ || [istarget "ft32-*-*"]
+ || [istarget "i860-*-*"]
+ || [istarget "i960-*-*"]
+ || [istarget "iq2000-*-*"]
+ || [istarget "mn10200-*-*"]
+ || [istarget "moxie-*-*"]
+ || [istarget "msp430-*-*"]
+ || [istarget "mt-*-*"]
+ || [istarget "pj*-*-*"] } {
+ return 1;
+ }
+ return 0;
+}
+
# Returns true if the target ld supports the plugin API.
proc check_plugin_api_available { } {
global plugin_api_available_saved
return $ld_sysroot_available_saved
}
+# Returns 1 if plugin is enabled in gcc. Returns 0 otherwise.
+proc check_gcc_plugin_enabled { } {
+ global CC
+
+ if {![info exists CC]} {
+ set CC [find_gcc]
+ }
+ if { $CC == ""} {
+ return 0
+ }
+ set state [remote_exec host $CC -v]
+ if { [lindex $state 0] != 0 } {
+ return 0;
+ }
+ for { set i 1 } { $i < [llength $state] } { incr i } {
+ set v [lindex $state $i]
+ if { [ string match "*--disable-plugin*" $v ] } {
+ verbose "plugin is disabled by $v"
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
# Returns true if the target compiler supports LTO
proc check_lto_available { } {
global lto_available_saved
global CC
if {![info exists lto_available_saved]} {
- if { [which $CC] == 0 } {
+ if { ![check_gcc_plugin_enabled] } {
set lto_available_saved 0
return 0
}
global CC
if {![info exists lto_fat_available_saved]} {
- if { [which $CC] == 0 } {
+ if { ![check_gcc_plugin_enabled] } {
set lto_fat_available_saved 0
return 0
}
global CC
if {![info exists lto_shared_available_saved]} {
- if { [which $CC] == 0 } {
+ if { ![check_gcc_plugin_enabled] } {
set lto_shared_available_saved 0
return 0
}
}
return [istarget_ld $target]
}
+
+# Return true if libdl is supported.
+
+proc check_libdl_available { } {
+ global libdl_available_saved
+ global CC
+
+ if {![info exists libdl_available_saved]} {
+ if { [which $CC] == 0 } {
+ set libdl_available_saved 0
+ return 0
+ }
+
+ set basename "tmpdir/dl_avail_test[pid]"
+ set src ${basename}.c
+ set output ${basename}.out
+ set f [open $src "w"]
+ # Sample test file.
+ puts $f "#include <dlfcn.h>"
+ puts $f "int main (void)"
+ puts $f "{"
+ puts $f " dlopen (\"dummy.so\", RTLD_NOW);"
+ puts $f " return 0; "
+ puts $f "}"
+ close $f
+ if [is_remote host] {
+ set src [remote_download host $src]
+ }
+ set libdl_available_saved [run_host_cmd_yesno "$CC" "$src -o $output -ldl"]
+ remote_file host delete $src
+ remote_file host delete $output
+ file delete $src
+ }
+ return $libdl_available_saved
+}