+ } else {
+ pass $testname
+ }
+ }
+}
+
+# Returns true if --gc-sections is supported on the target.
+
+proc check_gc_sections_available { } {
+ global gc_sections_available_saved
+ global ld
+
+ if {![info exists gc_sections_available_saved]} {
+ # Some targets don't support gc-sections despite whatever's
+ # advertised by ld's options.
+ if { [istarget alpha-*-*]
+ || [istarget d30v-*-*]
+ || [istarget dlx-*-*]
+ || [istarget hppa*64-*-*]
+ || [istarget ia64-*-*]
+ || [istarget mep-*-*]
+ || [istarget mn10200-*-*]
+ || [istarget pj*-*-*]
+ || [istarget pru*-*-*]
+ || [istarget xgate-*-*] } {
+ set gc_sections_available_saved 0
+ return 0
+ }
+
+ # elf2flt uses -q (--emit-relocs), which is incompatible with
+ # --gc-sections.
+ if { [board_info target exists ldflags]
+ && [regexp " -elf2flt\[ =\]" " [board_info target ldflags] "] } {
+ set gc_sections_available_saved 0
+ return 0
+ }
+
+ # Check if the ld used by gcc supports --gc-sections.
+ # FIXME: this test is useless since ld --help always says
+ # --gc-sections is available
+ set ld_output [remote_exec host $ld "--help"]
+ if { [ string first "--gc-sections" $ld_output ] >= 0 } {
+ set gc_sections_available_saved 1
+ } else {
+ set gc_sections_available_saved 0
+ }
+ }
+ return $gc_sections_available_saved
+}
+
+# Returns true if -shared is supported on the target
+
+proc check_shared_lib_support { } {
+ global shared_available_saved
+ global ld
+
+ if {![info exists shared_available_saved]} {
+ set ld_output [remote_exec host $ld "-shared"]
+ if { [ string first "not supported" $ld_output ] >= 0 } {
+ set shared_available_saved 0
+ } else {
+ set shared_available_saved 1
+ }
+ }
+ return $shared_available_saved
+}
+
+# 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 "iq2000-*-*"]
+ || [istarget "mn10200-*-*"]
+ || [istarget "moxie-*-*"]
+ || [istarget "msp430-*-*"]
+ || [istarget "mt-*-*"]
+ || [istarget "pj*-*-*"]
+ || [istarget "xgate-*-*"] } {
+ return 1;
+ }
+ return 0;
+}
+
+proc is_underscore_target { } {
+ global is_underscore_target_saved
+ global target_triplet
+ global srcdir
+
+ if { ![info exists is_underscore_target_saved] } {
+ set cmd "targ=$target_triplet . $srcdir/../../bfd/config.bfd &&"
+ append cmd { echo "$targ_underscore"}
+ verbose -log "$cmd"
+ set status [catch {exec sh -c $cmd} result]
+ if { $status == 0 && [string match "yes" $result] } {
+ set is_underscore_target_saved 1
+ } else {
+ set is_underscore_target_saved 0
+ }
+ }
+ return $is_underscore_target_saved
+}
+
+# Returns true if the target ld supports the plugin API.
+proc check_plugin_api_available { } {
+ global plugin_api_available_saved
+ global ld
+ if {![info exists plugin_api_available_saved]} {
+ # Check if the ld used by gcc supports --plugin.
+ set ld_output [remote_exec host $ld "--help"]
+ if { [ string first "-plugin PLUGIN" $ld_output ] >= 0 } {
+ set plugin_api_available_saved 1
+ } else {
+ set plugin_api_available_saved 0
+ }
+ }
+ return $plugin_api_available_saved
+}
+
+# Sets ld_sysroot to the current sysroot (empty if not supported) and
+# returns true if the target ld supports sysroot.
+proc check_sysroot_available { } {
+ global ld_sysroot_available_saved ld ld_sysroot
+ if {![info exists ld_sysroot_available_saved]} {
+ # Check if ld supports --sysroot *other* than empty.
+ set ld_sysroot [string trimright [lindex [remote_exec host $ld "--print-sysroot"] 1]]
+ if { $ld_sysroot == "" } {
+ set ld_sysroot_available_saved 0
+ } else {
+ set ld_sysroot_available_saved 1
+ }
+ }
+ 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 { ![check_gcc_plugin_enabled] } {
+ set lto_available_saved 0
+ return 0
+ }
+ # This test will hide LTO bugs in ld. Since GCC 4.9 adds
+ # -ffat-lto-objects, we always run LTO tests on Linux with
+ # GCC 4.9 or newer.
+ if { [istarget "*-*-linux*"] && [at_least_gcc_version 4 9] } {
+ set lto_available_saved 1
+ return 1
+ }
+ # 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/lto[pid]"
+ set src ${basename}.c
+ set output ${basename}.out
+ set f [open $src "w"]
+ puts $f "int main() { return 0; }"
+ close $f
+ if [is_remote host] {
+ set src [remote_download host $src]
+ }
+ set lto_available_saved [run_host_cmd_yesno "$CC" "$flags -flto -fuse-linker-plugin $src -o $output"]
+ remote_file host delete $src
+ remote_file host delete $output
+ file delete $src
+ }
+ return $lto_available_saved
+}
+
+# Returns true if the target compiler supports LTO -ffat-lto-objects
+proc check_lto_fat_available { } {
+ global lto_fat_available_saved
+ global CC
+
+ if {![info exists lto_fat_available_saved]} {
+ if { ![check_gcc_plugin_enabled] } {
+ set lto_fat_available_saved 0
+ return 0
+ }
+ # This test will hide LTO bugs in ld. Since GCC 4.9 adds
+ # -ffat-lto-objects, we always run LTO tests on Linux with
+ # GCC 4.9 or newer.
+ if { [istarget "*-*-linux*"] && [at_least_gcc_version 4 9] } {
+ set lto_fat_available_saved 1
+ return 1
+ }
+ # 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/lto[pid]"
+ set src ${basename}.c
+ set output ${basename}.out
+ set f [open $src "w"]
+ puts $f "int main() { return 0; }"
+ close $f
+ if [is_remote host] {
+ set src [remote_download host $src]
+ }
+ set lto_fat_available_saved [run_host_cmd_yesno "$CC" "$flags -flto -ffat-lto-objects -fuse-linker-plugin $src -o $output"]
+ remote_file host delete $src
+ remote_file host delete $output
+ file delete $src
+ }
+ return $lto_fat_available_saved
+}
+
+# Returns true if the target compiler supports LTO and -shared
+proc check_lto_shared_available { } {
+ global lto_shared_available_saved
+ global CC
+
+ if {![info exists lto_shared_available_saved]} {
+ if { ![check_gcc_plugin_enabled] } {
+ set lto_shared_available_saved 0
+ return 0
+ }
+ # This test will hide LTO bugs in ld. Since GCC 4.9 adds
+ # -ffat-lto-objects, we always run LTO tests on Linux with
+ # GCC 4.9 or newer.
+ if { [istarget "*-*-linux*"] && [at_least_gcc_version 4 9] } {
+ set lto_shared_available_saved 1
+ return 1
+ }
+ # Check if gcc supports -flto -fuse-linker-plugin -shared
+ 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/lto_shared[pid]"
+ set src ${basename}.c
+ set output ${basename}.so
+ set f [open $src "w"]
+ puts $f ""
+ close $f
+ if [is_remote host] {
+ set src [remote_download host $src]
+ }
+ set lto_shared_available_saved [run_host_cmd_yesno "$CC" "$flags -shared -fPIC -flto -fuse-linker-plugin $src -o $output"]
+ remote_file host delete $src
+ remote_file host delete $output
+ file delete $src
+ }
+ return $lto_shared_available_saved
+}
+
+# Check if the assembler supports CFI statements.
+
+proc check_as_cfi { } {
+ global check_as_cfi_result
+ global as
+ if [info exists check_as_cfi_result] {
+ return $check_as_cfi_result
+ }
+ set as_file "tmpdir/check_as_cfi.s"
+ set as_fh [open $as_file w 0666]
+ puts $as_fh "# Generated file. DO NOT EDIT"
+ puts $as_fh "\t.cfi_startproc"
+ puts $as_fh "\t.cfi_endproc"
+ close $as_fh
+ remote_download host $as_file
+ verbose -log "Checking CFI support:"
+ rename "perror" "check_as_cfi_perror"
+ proc perror { args } { }
+ set success [ld_assemble $as $as_file "/dev/null"]
+ rename "perror" ""
+ rename "check_as_cfi_perror" "perror"
+ #remote_file host delete $as_file
+ set check_as_cfi_result $success
+ 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
+ if [is_remote host] {
+ set src [remote_download host $src]
+ }
+ set ifunc_available_saved [run_host_cmd_yesno "$CC" "$flags $src -o $output"]
+ if { [isnative] && $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
+ if [is_remote host] {
+ set src [remote_download host $src]
+ }
+ set ifunc_attribute_available_saved [run_host_cmd_yesno "$CC" "$flags $src -o $output"]
+ if { [isnative] && $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"
+proc istarget { target } {
+ if {$target == "cfi"} {
+ return [check_as_cfi]
+ }
+ if {$target == "shared"} {
+ return [check_shared_lib_support]
+ }
+ 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
+}
+
+# Returns true if GNU2 TLS works.
+
+proc check_gnu2_tls_available { } {
+ global gnu2_tls_available_saved
+ global CC
+ global GNU2_CFLAGS
+
+ if {![info exists gnu2_tls_available_saved]} {
+ if { [which $CC] == 0 || "$GNU2_CFLAGS" == "" } {
+ set gnu2_tls_available_saved 0
+ return 0
+ }
+ # Check if GNU2 TLS works.
+ set flags "$GNU2_CFLAGS"
+ 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/gnu2_tls[pid]"
+ set src1 ${basename}1.c
+ set output1 ${basename}.so
+ set f [open $src1 "w"]
+ puts $f "extern __thread int zzz;"
+ puts $f "int foo (void)"
+ puts $f "{"
+ puts $f " return zzz;"
+ puts $f "}"
+ close $f
+ if [is_remote host] {
+ set src1 [remote_download host $src1]
+ }
+ set src2 ${basename}2.c
+ set output2 ${basename}.exe
+ set f [open $src2 "w"]
+ puts $f "__thread int zzz = 20;"
+ puts $f "extern int foo (void);"
+ puts $f "int main (void)"
+ puts $f "{"
+ puts $f " if (foo () != 20) __builtin_abort ();"
+ puts $f " return 0; "
+ puts $f "}"
+ close $f
+ if [is_remote host] {
+ set src2 [remote_download host $src2]
+ }
+ set gnu2_tls_available_saved [run_host_cmd_yesno "$CC" "-fPIC -shared $flags $src1 -o $output1"]
+ if { $gnu2_tls_available_saved == 1 } {
+ set gnu2_tls_available_saved [run_host_cmd_yesno "$CC" "$flags $src2 $output1 -o $output2"]
+ if { $gnu2_tls_available_saved == 1 } {
+ set gnu2_tls_available_saved [run_host_cmd_yesno "$output2" ""]
+ }