# Support routines for LD testsuite.
-# Copyright (C) 1994-2014 Free Software Foundation, Inc.
+# Copyright (C) 1994-2016 Free Software Foundation, Inc.
#
# This file is part of the GNU Binutils.
#
proc run_host_cmd_yesno { prog command } {
global exec_output
+ global errcnt warncnt
set exec_output [prune_warnings [run_host_cmd "$prog" "$command"]]
+ # Ignore error and warning.
+ set errcnt 0
+ set warncnt 0
if [string match "" $exec_output] then {
return 1;
}
# run_dump_test will guess which program to run by seeing which of
# the flags options below is present.
#
+# readelf: FLAGS
# objdump: FLAGS
# nm: FLAGS
# objcopy: FLAGS
#
# error: REGEX
# An error with message matching REGEX must be emitted for the test
-# to pass. The PROG, objdump, nm and objcopy options have no
-# meaning and need not supplied if this is present. Multiple "error"
-# directives append to the expected linker error message.
+# to pass. The PROG, readelf, objdump, nm and objcopy options have
+# no meaning and need not be supplied if this is present. Multiple
+# "error" directives append to the expected linker error message.
+#
+# error_output: FILE
+# Means the same as 'error', except the regular expression lines
+# are contains in FILE.
#
# warning: REGEX
# Expect a linker warning matching REGEX. It is an error to issue
# both "error" and "warning". Multiple "warning" directives
# append to the expected linker warning message.
#
+# warning_output: FILE
+# Means the same as 'warning', except the regular expression
+# lines are contains in FILE.
+#
+# map: FILE
+# Adding this option will cause the linker to generate a linker
+# map file, using the -Map=MAPFILE command line option. If
+# there is no -Map=MAPFILE in the 'ld: FLAGS' then one will be
+# added to the linker command line. The contents of the
+# generated MAPFILE are then compared against the regexp lines
+# in FILE using `regexp_diff' (see below for details).
+#
# Each option may occur at most once unless otherwise mentioned.
#
# After the option lines come regexp lines. `run_dump_test' calls
set opts(dump) {}
set opts(error) {}
set opts(warning) {}
+ set opts(error_output) {}
+ set opts(warning_output) {}
set opts(objcopy_linked_file) {}
set opts(objcopy_objects) {}
+ set opts(map) {}
foreach i $opt_array {
set opt_name [lindex $i 0]
set program ""
# It's meaningless to require an output-testing method when we
# expect an error.
- if { $opts(error) == "" } {
+ if { $opts(error) == "" && $opts(error_output) == "" } {
if {$opts(PROG) != ""} {
switch -- $opts(PROG) {
objdump { set program objdump }
}
}
}
- if { $program == "" && $opts(warning) == "" } {
+ if { $program == "" \
+ && $opts(map) == "" \
+ && $opts(warning) == "" \
+ && $opts(warning_output) == "" \
+ && $opts(error) == "" \
+ && $opts(error_output) == "" } {
perror "dump program unspecified in $file.d"
unresolved $subdir/$name
return
set dfile $srcdir/$subdir/$opts(dump)
}
- if { [string match "*--compress-debug-sections*" $opts(as)] \
- && ![is_zlib_supported] } {
- unsupported $testname
- return
- }
-
# Time to setup xfailures.
foreach targ $opts(xfail) {
setup_xfail $targ
}
}
- set expmsg $opts(error)
- if { $opts(warning) != "" } {
- if { $expmsg != "" } {
- perror "$testname: mixing error and warning test-directives"
- return
- }
- set expmsg $opts(warning)
+ if { (($opts(warning) != "") && ($opts(error) != "")) \
+ || (($opts(warning) != "") && ($opts(error_output) != "")) \
+ || (($opts(warning) != "") && ($opts(warning_output) != "")) \
+ || (($opts(error) != "") && ($opts(warning_output) != "")) \
+ || (($opts(error) != "") && ($opts(error_output) != "")) \
+ || (($opts(warning_output) != "") && ($opts(error_output) != "")) } {
+ perror "$testname: bad mix of warning, error, warning_output, and error_output test-directives"
+ unresolved $testname
+ return
+ }
+
+ set check_ld(source) ""
+ if { $opts(error) != "" \
+ || $opts(warning) != "" \
+ || $opts(error_output) != "" \
+ || $opts(warning_output) != "" } {
+
+ if { $opts(error) != "" || $opts(error_output) != "" } {
+ set check_ld(terminal) 1
+ } else {
+ set check_ld(terminal) 0
+ }
+
+ if { $opts(error) != "" || $opts(warning) != "" } {
+ set check_ld(source) "regex"
+ if { $opts(error) != "" } {
+ set check_ld(regex) $opts(error)
+ } else {
+ set check_ld(regex) $opts(warning)
+ }
+ } else {
+ set check_ld(source) "file"
+ if { $opts(error_output) != "" } {
+ set check_ld(file) $opts(error_output)
+ } else {
+ set check_ld(file) $opts(warning_output)
+ }
+ }
}
# Perhaps link the file(s).
set cmd "$LD $LDFLAGS -L$srcdir/$subdir \
$opts(ld) -o $objfile $objfiles $opts(ld_after_inputfiles)"
+ # If needed then check for, or add a -Map option.
+ set mapfile ""
+ if { $opts(map) != "" } then {
+ if { [regexp -- "-Map=(\[^ \]+)" $cmd all mapfile] } then {
+ # Found existing mapfile option
+ verbose -log "Existing mapfile '$mapfile' found"
+ } else {
+ # No mapfile option.
+ set mapfile "tmpdir/dump.map"
+ verbose -log "Adding mapfile '$mapfile'"
+ set cmd "$cmd -Map=$mapfile"
+ }
+ }
+
send_log "$cmd\n"
set cmdret [remote_exec host [concat sh -c [list "$cmd 2>&1"]] "" "/dev/null" "ld.tmp"]
remote_upload host "ld.tmp"
}
regsub "\n$" $comp_output "" comp_output
- if { $cmdret != 0 || $comp_output != "" || $expmsg != "" } then {
+ if { $cmdret != 0 || $comp_output != "" || $check_ld(source) != "" } then {
set exitstat "succeeded"
if { $cmdret != 0 } { set exitstat "failed" }
- verbose -log "$exitstat with: <$comp_output>, expected: <$expmsg>"
+
+ if { $check_ld(source) == "regexp" } {
+ 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)"
+ set_file_contents "tmpdir/ld.messages" "$comp_output"
+ } else {
+ verbose -log "$exitstat with: <$comp_output>, no expected output"
+ }
send_log "$comp_output\n"
verbose "$comp_output" 3
- if { ($expmsg == "") == ($comp_output == "") \
- && [regexp $expmsg $comp_output] \
- && (($cmdret == 0) == ($opts(error) == "")) } {
- # We have the expected output from ld.
- if { $opts(error) != "" || $program == "" } {
+ if { (($check_ld(source) == "") == ($comp_output == "")) \
+ && (($cmdret == 0) == ($check_ld(terminal) == 0)) \
+ && ((($check_ld(source) == "regex") \
+ && ($check_ld(regex) == "") == ($comp_output == "") \
+ && [regexp $check_ld(regex) $comp_output]) \
+ || (($check_ld(source) == "file") \
+ && ([regexp_diff "tmpdir/ld.messages" "$srcdir/$subdir/$check_ld(file)"]))) } {
+ # We have the expected output from ld.
+ if { $check_ld(terminal) || $program == "" } {
pass $testname
return
}
} else {
- verbose -log "$exitstat with: <$comp_output>, expected: <$expmsg>"
fail $testname
return
}
}
+
+ if { $opts(map) != "" } then {
+ # Check the map file matches.
+ set map_pattern_file $srcdir/$subdir/$opts(map)
+ verbose -log "Compare '$mapfile' against '$map_pattern_file'"
+ if { [regexp_diff $mapfile $map_pattern_file] } then {
+ fail "$testname (map file check)"
+ } else {
+ pass "$testname (map file check)"
+ }
+
+ if { $program == "" } then {
+ return
+ }
+ }
} else {
set objfile "tmpdir/dump0.o"
}
proc ar_simple_create { ar aropts target objects } {
remote_file host delete $target
- set exec_output [run_host_cmd "$ar" "$aropts -rc $target $objects"]
+ set exec_output [run_host_cmd "$ar" "-rc $aropts $target $objects"]
set exec_output [prune_warnings $exec_output]
if [string match "" $exec_output] then {
|| [istarget i860-*-*]
|| [istarget ia64-*-*]
|| [istarget mep-*-*]
- || [istarget mn10200-*-*]
- || [istarget *-*-cygwin]
- || [istarget *-*-mingw*] } {
+ || [istarget mn10200-*-*] } {
set gc_sections_available_saved 0
return 0
}
&& ![istarget rx-*-*]
&& ![istarget spu-*-*]
&& ![istarget v850*-*-*]
+ && ![istarget visium-*-*]
+ && ![istarget xgate-*-*]
&& ![istarget xstormy16-*-*]
&& ![istarget *-*-irix*]
&& ![istarget *-*-rtems] } {
return $success
}
+# Returns true if IFUNC works.
+
+proc check_ifunc_available { } {
+ global ifunc_available_saved
+ global CC
+
+ if {![info exists ifunc_available_saved]} {
+ if { [which $CC] == 0 } {
+ set ifunc_available_saved 0
+ return 0
+ }
+ # Check if gcc supports -flto -fuse-linker-plugin
+ set flags ""
+ if [board_info [target_info name] exists cflags] {
+ append flags " [board_info [target_info name] cflags]"
+ }
+ if [board_info [target_info name] exists ldflags] {
+ append flags " [board_info [target_info name] ldflags]"
+ }
+
+ set basename "tmpdir/ifunc[pid]"
+ set src ${basename}.c
+ set output ${basename}.out
+ set f [open $src "w"]
+ puts $f "extern int library_func2 (void);"
+ puts $f "int main (void)"
+ puts $f "{"
+ puts $f " if (library_func2 () != 2) __builtin_abort ();"
+ puts $f " return 0; "
+ puts $f "}"
+ puts $f "static int library_func1 (void) {return 2; }"
+ puts $f "void *foo (void) __asm__ (\"library_func2\");"
+ puts $f "void *foo (void) { return library_func1; }"
+ puts $f "__asm__(\".type library_func2, %gnu_indirect_function\");"
+ close $f
+ remote_download host $src
+ set ifunc_available_saved [run_host_cmd_yesno "$CC" "$flags $src -o $output"]
+ if { $ifunc_available_saved == 1 } {
+ set ifunc_available_saved [run_host_cmd_yesno "$output" ""]
+ }
+ remote_file host delete $src
+ remote_file host delete $output
+ file delete $src
+ }
+ return $ifunc_available_saved
+}
+
+# Returns true if ifunc attribute works.
+
+proc check_ifunc_attribute_available { } {
+ global ifunc_attribute_available_saved
+ global CC
+
+ if {![info exists ifunc_attribute_available_saved]} {
+ if { [which $CC] == 0 } {
+ set ifunc_attribute_available_saved 0
+ return 0
+ }
+ # Check if gcc supports -flto -fuse-linker-plugin
+ set flags ""
+ if [board_info [target_info name] exists cflags] {
+ append flags " [board_info [target_info name] cflags]"
+ }
+ if [board_info [target_info name] exists ldflags] {
+ append flags " [board_info [target_info name] ldflags]"
+ }
+
+ set basename "tmpdir/ifunc[pid]"
+ set src ${basename}.c
+ set output ${basename}.out
+ set f [open $src "w"]
+ puts $f "extern int library_func2 (void) __attribute__ ((ifunc (\"foo\")));"
+ puts $f "int main (void)"
+ puts $f "{"
+ puts $f " if (library_func2 () != 2) __builtin_abort ();"
+ puts $f " return 0; "
+ puts $f "}"
+ puts $f "static int library_func1 (void) {return 2; }"
+ puts $f "void *foo (void) { return library_func1; }"
+ close $f
+ remote_download host $src
+ set ifunc_attribute_available_saved [run_host_cmd_yesno "$CC" "$flags $src -o $output"]
+ if { $ifunc_attribute_available_saved == 1 } {
+ set ifunc_attribute_available_saved [run_host_cmd_yesno "$output" ""]
+ }
+ remote_file host delete $src
+ remote_file host delete $output
+ file delete $src
+ }
+ return $ifunc_attribute_available_saved
+}
+
# Provide virtual target "cfi" for targets supporting CFI.
rename "istarget" "istarget_ld"