Backport "="-ldscript-path-prefix changes from master.
authorHans-Peter Nilsson <hp@bitrange.com>
Wed, 15 Oct 2014 01:54:43 +0000 (03:54 +0200)
committerHans-Peter Nilsson <hp@bitrange.com>
Wed, 15 Oct 2014 01:54:43 +0000 (03:54 +0200)
ld/ChangeLog
ld/ld.texinfo
ld/ldgram.y
ld/ldlang.c
ld/ldlex.h
ld/ldlex.l
ld/testsuite/ChangeLog
ld/testsuite/ld-scripts/sysroot-prefix-x.s [new file with mode: 0644]
ld/testsuite/ld-scripts/sysroot-prefix-y.s [new file with mode: 0644]
ld/testsuite/ld-scripts/sysroot-prefix.exp [new file with mode: 0644]
ld/testsuite/lib/ld-lib.exp

index e02b109..9f620c9 100644 (file)
@@ -1,3 +1,27 @@
+2014-10-15  Hans-Peter Nilsson  <hp@axis.com>
+
+       Backport "="-ldscript-path-prefix changes from master.
+       * ldlex.l (INPUTLIST): New start condition.
+       (comment pattern, ",", "(", ")", "AS_NEEDED")
+       ({FILENAMECHAR1}{FILENAMECHAR}*, "-l"{FILENAMECHAR}+)
+       (quoted string pattern, whitespace pattern): Add INPUTLIST to
+       valid start conditions.
+       (<INPUTLIST>"="{FILENAMECHAR1}{FILENAMECHAR}*): New NAME rule.
+       (ldlex_inputlist): New start-condition-setter function.
+       * ldgram.y (input_list1): Rename from input_list.  All recursive
+       use changed.
+       (input_list): New wrapper rule for input_list1, setting
+       INPUTLIST lexer state for the duration of parsing input_list1.
+       * ldlang.c (lang_add_input_file): If the first character in the
+       filename is '=', prepend the sysroot and force the context of that
+       input file to non-sysroot.
+       * ld.texinfo (Options): When mentioning "=" and sysroot, mention
+       that --sysroot controls it, not only through the configuration.
+       (input files in linker scripts): When mentioning
+       behavior of first character "/" on scripts within sysroot, also
+       mention that effect can be forced by prefixing with "=" and
+       refer to SEARCH_DIR.
+
 2014-10-14  Tristan Gingold  <gingold@adacore.com>
 
        * NEWS: Add marker for 2.25.
index e71be5e..8eb7ba3 100644 (file)
@@ -706,7 +706,8 @@ how @command{ld} searches for a linker script unless @option{-T}
 option is specified.
 
 If @var{searchdir} begins with @code{=}, then the @code{=} will be replaced
-by the @dfn{sysroot prefix}, a path specified when the linker is configured.
+by the @dfn{sysroot prefix}, controlled by the @samp{--sysroot} option, or
+specified when the linker is configured.
 
 @ifset UsesEnvVars
 The default set of paths searched (without being specified with
@@ -3142,7 +3143,9 @@ with the @samp{/} character, and the script being processed was
 located inside the @dfn{sysroot prefix}, the filename will be looked
 for in the @dfn{sysroot prefix}.  Otherwise, the linker will try to
 open the file in the current directory.  If it is not found, the
-linker will search through the archive library search path.  See the
+linker will search through the archive library search path.
+The @dfn{sysroot prefix} can also be forced by specifying @code{=}
+as the first character in the filename path.  See also the
 description of @samp{-L} in @ref{Options,,Command Line Options}.
 
 If you use @samp{INPUT (-l@var{file})}, @command{ld} will transform the
index 4875fa7..e76a0a3 100644 (file)
@@ -365,38 +365,43 @@ ifile_p1:
        ;
 
 input_list:
+               { ldlex_inputlist(); }
+               input_list1
+               { ldlex_popstate(); }
+
+input_list1:
                NAME
                { lang_add_input_file($1,lang_input_file_is_search_file_enum,
                                 (char *)NULL); }
-       |       input_list ',' NAME
+       |       input_list1 ',' NAME
                { lang_add_input_file($3,lang_input_file_is_search_file_enum,
                                 (char *)NULL); }
-       |       input_list NAME
+       |       input_list1 NAME
                { lang_add_input_file($2,lang_input_file_is_search_file_enum,
                                 (char *)NULL); }
        |       LNAME
                { lang_add_input_file($1,lang_input_file_is_l_enum,
                                 (char *)NULL); }
-       |       input_list ',' LNAME
+       |       input_list1 ',' LNAME
                { lang_add_input_file($3,lang_input_file_is_l_enum,
                                 (char *)NULL); }
-       |       input_list LNAME
+       |       input_list1 LNAME
                { lang_add_input_file($2,lang_input_file_is_l_enum,
                                 (char *)NULL); }
        |       AS_NEEDED '('
                  { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
                    input_flags.add_DT_NEEDED_for_regular = TRUE; }
-                    input_list ')'
+                    input_list1 ')'
                  { input_flags.add_DT_NEEDED_for_regular = $<integer>3; }
-       |       input_list ',' AS_NEEDED '('
+       |       input_list1 ',' AS_NEEDED '('
                  { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
                    input_flags.add_DT_NEEDED_for_regular = TRUE; }
-                    input_list ')'
+                    input_list1 ')'
                  { input_flags.add_DT_NEEDED_for_regular = $<integer>5; }
-       |       input_list AS_NEEDED '('
+       |       input_list1 AS_NEEDED '('
                  { $<integer>$ = input_flags.add_DT_NEEDED_for_regular;
                    input_flags.add_DT_NEEDED_for_regular = TRUE; }
-                    input_list ')'
+                    input_list1 ')'
                  { input_flags.add_DT_NEEDED_for_regular = $<integer>4; }
        ;
 
index 5960e5c..c4da07f 100644 (file)
@@ -1118,6 +1118,26 @@ lang_add_input_file (const char *name,
                     lang_input_file_enum_type file_type,
                     const char *target)
 {
+  if (name != NULL && *name == '=')
+    {
+      lang_input_statement_type *ret;
+      char *sysrooted_name
+       = concat (ld_sysroot, name + 1, (const char *) NULL);
+
+      /* We've now forcibly prepended the sysroot, making the input
+        file independent of the context.  Therefore, temporarily
+        force a non-sysrooted context for this statement, so it won't
+        get the sysroot prepended again when opened.  (N.B. if it's a
+        script, any child nodes with input files starting with "/"
+        will be handled as "sysrooted" as they'll be found to be
+        within the sysroot subdirectory.)  */
+      unsigned int outer_sysrooted = input_flags.sysrooted;
+      input_flags.sysrooted = 0;
+      ret = new_afile (sysrooted_name, file_type, target, TRUE);
+      input_flags.sysrooted = outer_sysrooted;
+      return ret;
+    }
+
   return new_afile (name, file_type, target, TRUE);
 }
 
index 63f4c81..56cd121 100644 (file)
@@ -161,6 +161,7 @@ extern int yylex (void);
 extern void lex_push_file (FILE *, const char *, unsigned int);
 extern void lex_redirect (const char *, const char *, unsigned int);
 extern void ldlex_script (void);
+extern void ldlex_inputlist (void);
 extern void ldlex_mri_script (void);
 extern void ldlex_version_script (void);
 extern void ldlex_version_file (void);
index 234867c..d162128 100644 (file)
@@ -77,6 +77,7 @@ static void lex_warn_invalid (char *where, char *what);
 /* STATES
        EXPRESSION      definitely in an expression
        SCRIPT          definitely in a script
+       INPUTLIST       definitely in a script, a filename-list
        BOTH            either EXPRESSION or SCRIPT
        DEFSYMEXP       in an argument to -defsym
         MRI             in an MRI script
@@ -109,6 +110,7 @@ V_TAG [.$_a-zA-Z][._a-zA-Z0-9]*
 V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 
 %s SCRIPT
+%s INPUTLIST
 %s EXPRESSION
 %s BOTH
 %s DEFSYMEXP
@@ -134,7 +136,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
        }
     }
 
-<BOTH,SCRIPT,EXPRESSION,VERS_START,VERS_NODE,VERS_SCRIPT>"/*"  { comment (); }
+<BOTH,SCRIPT,EXPRESSION,VERS_START,VERS_NODE,VERS_SCRIPT,INPUTLIST>"/*"        { comment (); }
 
 
 <DEFSYMEXP>"-"                  { RTOKEN('-');}
@@ -221,7 +223,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <BOTH,SCRIPT,EXPRESSION,MRI>"|="       { RTOKEN(OREQ);}
 <BOTH,SCRIPT,EXPRESSION,MRI>"&&"       { RTOKEN(ANDAND);}
 <BOTH,SCRIPT,EXPRESSION,MRI>">"                { RTOKEN('>');}
-<BOTH,SCRIPT,EXPRESSION,MRI>","                { RTOKEN(',');}
+<BOTH,SCRIPT,EXPRESSION,MRI,INPUTLIST>","              { RTOKEN(',');}
 <BOTH,SCRIPT,EXPRESSION,MRI>"&"                { RTOKEN('&');}
 <BOTH,SCRIPT,EXPRESSION,MRI>"|"                { RTOKEN('|');}
 <BOTH,SCRIPT,EXPRESSION,MRI>"~"                { RTOKEN('~');}
@@ -236,8 +238,8 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <BOTH,SCRIPT,EXPRESSION,MRI>"="         { RTOKEN('=');}
 <BOTH,SCRIPT,EXPRESSION,MRI>"}"                { RTOKEN('}') ; }
 <BOTH,SCRIPT,EXPRESSION,MRI>"{"                { RTOKEN('{'); }
-<BOTH,SCRIPT,EXPRESSION,MRI>")"                { RTOKEN(')');}
-<BOTH,SCRIPT,EXPRESSION,MRI>"("                { RTOKEN('(');}
+<BOTH,SCRIPT,EXPRESSION,MRI,INPUTLIST>")"              { RTOKEN(')');}
+<BOTH,SCRIPT,EXPRESSION,MRI,INPUTLIST>"("              { RTOKEN('(');}
 <BOTH,SCRIPT,EXPRESSION,MRI>":"                { RTOKEN(':'); }
 <BOTH,SCRIPT,EXPRESSION,MRI>";"                { RTOKEN(';');}
 <BOTH,SCRIPT>"MEMORY"                  { RTOKEN(MEMORY);}
@@ -272,7 +274,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 <BOTH,SCRIPT>"OUTPUT"                  { RTOKEN(OUTPUT);}
 <BOTH,SCRIPT>"INPUT"                   { RTOKEN(INPUT);}
 <EXPRESSION,BOTH,SCRIPT>"GROUP"                { RTOKEN(GROUP);}
-<EXPRESSION,BOTH,SCRIPT>"AS_NEEDED"    { RTOKEN(AS_NEEDED);}
+<EXPRESSION,BOTH,SCRIPT,INPUTLIST>"AS_NEEDED"  { RTOKEN(AS_NEEDED);}
 <EXPRESSION,BOTH,SCRIPT>"DEFINED"      { RTOKEN(DEFINED);}
 <BOTH,SCRIPT>"CREATE_OBJECT_SYMBOLS"   { RTOKEN(CREATE_OBJECT_SYMBOLS);}
 <BOTH,SCRIPT>"CONSTRUCTORS"            { RTOKEN( CONSTRUCTORS);}
@@ -373,11 +375,16 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
                                }
 
 
-<BOTH>{FILENAMECHAR1}{FILENAMECHAR}*   {
+<BOTH,INPUTLIST>{FILENAMECHAR1}{FILENAMECHAR}* {
                                 yylval.name = xstrdup (yytext);
                                  return NAME;
                                }
-<BOTH>"-l"{FILENAMECHAR}+ {
+<INPUTLIST>"="{FILENAMECHAR1}{FILENAMECHAR}*   {
+/* Filename to be prefixed by --sysroot or when non-sysrooted, nothing.  */
+                                yylval.name = xstrdup (yytext);
+                                 return NAME;
+                               }
+<BOTH,INPUTLIST>"-l"{FILENAMECHAR}+ {
                                  yylval.name = xstrdup (yytext + 2);
                                  return LNAME;
                                }
@@ -406,7 +413,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
                  }
        }
 
-<EXPRESSION,BOTH,SCRIPT,VERS_NODE>"\""[^\"]*"\"" {
+<EXPRESSION,BOTH,SCRIPT,VERS_NODE,INPUTLIST>"\""[^\"]*"\"" {
                                        /* No matter the state, quotes
                                           give what's inside */
                                        yylval.name = xstrdup (yytext + 1);
@@ -447,7 +454,7 @@ V_IDENTIFIER [*?.$_a-zA-Z\[\]\-\!\^\\]([*?.$_a-zA-Z0-9\[\]\-\!\^\\]|::)*
 
 <VERS_START,VERS_NODE,VERS_SCRIPT>#.*          { /* Eat up comments */ }
 
-<VERS_START,VERS_NODE,VERS_SCRIPT>[ \t\r]+     { /* Eat up whitespace */ }
+<VERS_START,VERS_NODE,VERS_SCRIPT,INPUTLIST>[ \t\r]+           { /* Eat up whitespace */ }
 
 <<EOF>> {
   include_stack_ptr--;
@@ -566,6 +573,13 @@ ldlex_script (void)
 }
 
 void
+ldlex_inputlist (void)
+{
+  *(state_stack_p)++ = yy_start;
+  BEGIN (INPUTLIST);
+}
+
+void
 ldlex_mri_script (void)
 {
   *(state_stack_p)++ = yy_start;
index fd0c8ba..c01990c 100644 (file)
@@ -1,3 +1,10 @@
+2014-10-15  Hans-Peter Nilsson  <hp@axis.com>
+
+       Backport "="-ldscript-path-prefix changes from master.
+       * ld-scripts/sysroot-prefix.exp, ld-scripts/sysroot-prefix-x.s,
+       ld-scripts/sysroot-prefix-y.s: New files.
+       * lib/ld-lib.exp (check_sysroot_available): New proc.
+
 2014-10-04  Alan Modra  <amodra@gmail.com>
 
        * ld-elf/eh1.s: Don't create FDEs with zero address ranges.
diff --git a/ld/testsuite/ld-scripts/sysroot-prefix-x.s b/ld/testsuite/ld-scripts/sysroot-prefix-x.s
new file mode 100644 (file)
index 0000000..9b81905
--- /dev/null
@@ -0,0 +1,5 @@
+       .data
+       .globl x
+x:
+       .dc.a y
+
diff --git a/ld/testsuite/ld-scripts/sysroot-prefix-y.s b/ld/testsuite/ld-scripts/sysroot-prefix-y.s
new file mode 100644 (file)
index 0000000..f05ffa0
--- /dev/null
@@ -0,0 +1,4 @@
+       .data
+       .globl y
+y:
+       .dc.a 0
diff --git a/ld/testsuite/ld-scripts/sysroot-prefix.exp b/ld/testsuite/ld-scripts/sysroot-prefix.exp
new file mode 100644 (file)
index 0000000..cf434df
--- /dev/null
@@ -0,0 +1,183 @@
+# Copyright (C) 2014 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# Check that scripts using the "=" sysroot-prefix work, for both
+# toolchains with and without --sysroot support.
+
+# We test this by emitting archives into a subdirectory and expect
+# constructs such as GROUP and AS_NEEDED (the only two constructs
+# actually tested) to find them (or not); both quoted and unquoted
+# paths, with different prefixes on the path and with --sysroot
+# present or not, with different arguments.
+
+# Find out if the linker supports sysroot; if it was configured
+# "--with-sysroot X".  We ignore that X can actually be set to
+# interfere with the tests, as that's unlikely to be useful, and
+# assume that the build-directory (aka. $base_dir) does not contain X.
+set with_sysroot [check_sysroot_available]
+verbose -log "Has (non-empty) sysroot support: $with_sysroot"
+
+# Entries in the array-tables:
+# 0: Testtype (1: only non-sysroot, 2: only sysroot, 3: either).
+# 1: Description, forming part of the dejagnu test-name.
+# 2: Replacement for @p@.
+# 3: Option to pass to linker (usually something with --sysroot).
+# 4: Message substring; a substring to match against the error message
+# if an error is expected, or empty if no error is expected.
+#
+# If the replacement or option contains @cwd@, that'll be replaced by
+# "$base_dir/tmpdir", the full path to the location of the script
+# (with the actual files in the "sysroot" subdirectory).  If the
+# description contains @cwd@, that will be replaced by "<CWD>".
+
+set sysroot_prefix_tests {
+    {3 "plain -Lpath" "sysroot/" {} ""}
+    {3 "root-anchored but -Lpath" "/sysroot/" {} "cannot find"}
+    {3 "full-path" "@cwd@/sysroot/" {} ""}
+    {3 "root-anchored =-prefixed -Lpath" "=/sysroot/" {} "cannot find"}
+    {3 "full-path =-prefixed with empty" "=@cwd@/sysroot/" "--sysroot=" ""}
+    {3 "plain =-prefixed with empty" "=sysroot/" "--sysroot=" ""}
+    {2 "root-anchored but script outside sysroot" "/" "--sysroot=@cwd@/sysroot" "cannot find"}
+    {2 "root-anchored and script inside sysroot" "/sysroot/" "--sysroot=@cwd@" ""}
+    {2 "root-anchored =-prefixed script outside" "=/" "--sysroot=@cwd@/sysroot" ""}
+    {2 "root-anchored =-prefixed script inside" "=/sysroot/" "--sysroot=@cwd@" ""}
+    {2 "plain =-prefixed without but -Lpath" "=sysroot/" {} "cannot find"}
+    {2 "full-path =-prefixed without" "=@cwd@/sysroot/" {} "cannot find"}
+    {1 "plain =-prefixed -Lpath" "=sysroot/" {} ""}
+    {1 "full-path =-prefixed without" "=@cwd@/sysroot/" {} ""}
+}
+
+# May have to provide a target-specific assembler option for some targets.
+set gasopt ""
+
+# Intentionally similar to the ubiquitous glibc libc.so script.
+set template "GROUP ( @q@@p@tmp/ldtest-xyzzy/libx.a@q@ AS_NEEDED ( @q@@p@tmp/ldtest-xyzzy/liby.a@q@ ) )"
+
+# Set up everything from the variables above.
+proc sysroot_prefix_test_setup { } {
+    global as gasopt srcdir subdir ar
+
+    if {![ld_assemble_flags $as $gasopt $srcdir/$subdir/pr14962a.s tmpdir/main.o]} {
+       error "Error assembling a trivial file for sysroot-prefix tests framework"
+       return 0
+    }
+
+    # We need somewhere under tmpdir to point the sysroot, a subdirectory
+    # that is benevolent if it escapes into "/".
+    remote_exec host "mkdir -p tmpdir/sysroot/tmp/ldtest-xyzzy"
+
+    # 0: a "main" object that needs a symbol (x) (most portably by
+    # using a pre-existing file).  1: a library with an object that
+    # provides that symbol and needs another one (y).  2: another
+    # library with a third object providing that other symbol.
+    set sysroot_prefix_tests_framework_objects  {
+       {"pr14962a.s" "main" ""}
+       {"sysroot-prefix-x.s" "x" "x"}
+       {"sysroot-prefix-y.s" "y"  "y"}
+    }
+
+    foreach test_object $sysroot_prefix_tests_framework_objects {
+       set sname [lindex $test_object 0]
+       set onamebase [lindex $test_object 1]
+       set oname "tmpdir/$onamebase.o"
+       set libnamebase [lindex $test_object 2]
+
+       if ![ld_assemble_flags $as $gasopt $srcdir/$subdir/$sname $oname] {
+           error "Error assembling trivial file $sname for sysroot-prefix tests framework"
+           return 0
+       }
+
+       if { [string length $libnamebase] != 0 &&
+            ![ar_simple_create $ar "" tmpdir/sysroot/tmp/ldtest-xyzzy/lib$libnamebase.a $oname] } {
+           error "Error creating archive $libnamebase for sysroot-prefix tests framework"
+           return 0
+       }
+    }
+
+    return 1
+}
+
+# Run a single linker test.
+proc single_sysroot_prefix_test { type xtestname finalscript ldopt errstr } {
+    global ld exec_output with_sysroot
+    set scriptname "tmpdir/libsysroottest.a"
+    set testname "sysroot-prefix $xtestname"
+
+    if { ($type & ($with_sysroot + 1)) == 0 } {
+       unsupported $testname
+       return
+    }
+
+    if [catch { set ofd [open $scriptname w] } x] {
+       perror "$x"
+       unresolved $testname
+       return
+    }
+
+    puts $ofd "$finalscript"
+    close $ofd
+    verbose -log "script: $finalscript"
+
+    set res [ld_simple_link $ld tmpdir/output "$ldopt tmpdir/main.o -Ltmpdir -lsysroottest"]
+    set ld_output "$exec_output"
+    set expect_success [expr [string length $errstr] == 0]
+
+    if { $res == $expect_success &&
+         ($expect_success || [regexp "$errstr" $ld_output]) } {
+       pass $testname
+       catch "exec rm -f $scriptname"
+    } {
+       fail $testname
+    }
+}
+
+# Run all interesting variants from an option-and-path combination.
+proc run_sysroot_prefix_test { type name templ p ldopt errstr } {
+    global base_dir
+    set qlist { { "quoted" "\"" } { "unquoted" {} } }
+
+    regsub -all "@p@" $templ $p templ
+    regsub -all "@cwd@" $templ "$base_dir/tmpdir" templ
+    regsub -all "@cwd@" $ldopt "$base_dir/tmpdir" ldopt
+    regsub -all "@cwd@" $name "<CWD>" name
+
+    foreach qitems $qlist {
+       regsub -all "@q@" $templ [lindex $qitems 1] finalscript
+       single_sysroot_prefix_test $type "$name, [lindex $qitems 0]" \
+               $finalscript $ldopt $errstr
+    }
+}
+
+# Run a list of option-and-path test-combinations.
+proc run_sysroot_prefix_tests { descr templ items } {
+    foreach item $items {
+       set type [lindex $item 0]
+       set name [lindex $item 1]
+       set p [lindex $item 2]
+       set ldopt [lindex $item 3]
+       set errstr [lindex $item 4]
+       run_sysroot_prefix_test $type "$descr $name" $templ "$p" "$ldopt" "$errstr"
+    }
+}
+
+if ![sysroot_prefix_test_setup] {
+    return
+}
+
+run_sysroot_prefix_tests "common" $template $sysroot_prefix_tests
index 292a873..ffdf805 100644 (file)
@@ -1669,6 +1669,24 @@ proc check_plugin_api_available { } {
     return $plugin_api_available_saved
 }
 
+# Returns true if the target ld supports sysroot.
+proc check_sysroot_available { } {
+    global ld_sysroot_available_saved
+    global ld
+    if {![info exists ld_sysroot_available_saved]} {
+       # Check if ld supports --sysroot *other* than empty
+       # (non-sysroot linkers don't emit errors for --sysroot="").
+       # The help-text by itself is no indication as it always lists --sysroot.
+       set status [remote_exec host $ld "--sysroot=ldxyzzy --help >/dev/null"]
+       if { [lindex $status 0] != 0 } {
+           set ld_sysroot_available_saved 0
+       } else {
+           set ld_sysroot_available_saved 1
+       }
+    }
+    return $ld_sysroot_available_saved
+}
+
 # Returns true if the target compiler supports LTO
 proc check_lto_available { } {
     global lto_available_saved