about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src/back
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-12-01 14:30:07 +0100
committerGitHub <noreply@github.com>2024-12-01 14:30:07 +0100
commitae6a7dba2a58247ac7c41730ff95f05045b87cfd (patch)
tree5c66939ed50d714e4db139c51b5f85267edeae74 /compiler/rustc_codegen_ssa/src/back
parent6c76ed5503966c39381fac64eb905ac45e346695 (diff)
parent6bbf832cf266e48c1e8773e5d64a7e90bd866c7b (diff)
downloadrust-ae6a7dba2a58247ac7c41730ff95f05045b87cfd.tar.gz
rust-ae6a7dba2a58247ac7c41730ff95f05045b87cfd.zip
Rollup merge of #132974 - madsmtm:linker-arguments-with-commas, r=petrochenkov
Properly pass linker arguments that contain commas

When linking with the system C compiler, we sometimes want to forward certain arguments unchanged to the linker. This can be done with `-Wl,arg1,arg2` or `-Xlinker arg1 -Xlinker arg2`. `-Wl` is used when possible, since it is more compact, but it does not support commas in the argument itself - in those cases, we need to use `-Xlinker`, and that is what this PR implements.

This also fixes using sanitizers on macOS with `-Clinker-flavor=ld`, as those were previously manually using `-Wl`/`-Xlinker` (probably since the support wasn't present in the `link_args` function).

Note that there has been [a previous PR for this](https://github.com/rust-lang/rust/pull/38798), but it only implemented this in certain cases when passing `-rpath`.

r? compiler
Diffstat (limited to 'compiler/rustc_codegen_ssa/src/back')
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs50
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker/tests.rs32
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath.rs34
-rw-r--r--compiler/rustc_codegen_ssa/src/back/rpath/tests.rs23
5 files changed, 82 insertions, 61 deletions
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 651485a1876..ad81ff272c6 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1386,7 +1386,7 @@ fn link_sanitizer_runtime(
         let filename = format!("rustc{channel}_rt.{name}");
         let path = find_sanitizer_runtime(sess, &filename);
         let rpath = path.to_str().expect("non-utf8 component in path");
-        linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]);
+        linker.link_args(&["-rpath", rpath]);
         linker.link_dylib_by_name(&filename, false, true);
     } else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
         // MSVC provides the `/INFERASANLIBS` argument to automatically find the
@@ -2210,7 +2210,7 @@ fn add_rpath_args(
             is_like_osx: sess.target.is_like_osx,
             linker_is_gnu: sess.target.linker_flavor.is_gnu(),
         };
-        cmd.cc_args(&rpath::get_rpath_flags(&rpath_config));
+        cmd.link_args(&rpath::get_rpath_linker_args(&rpath_config));
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 6ee599c9964..05dfbd40a0a 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -24,6 +24,9 @@ use super::command::Command;
 use super::symbol_export;
 use crate::errors;
 
+#[cfg(test)]
+mod tests;
+
 /// Disables non-English messages from localized linkers.
 /// Such messages may cause issues with text encoding on Windows (#35785)
 /// and prevent inspection of linker output in case of errors, which we occasionally do.
@@ -178,23 +181,42 @@ fn verbatim_args<L: Linker + ?Sized>(
     }
     l
 }
+/// Add underlying linker arguments to C compiler command, by wrapping them in
+/// `-Wl` or `-Xlinker`.
+fn convert_link_args_to_cc_args(cmd: &mut Command, args: impl IntoIterator<Item: AsRef<OsStr>>) {
+    let mut combined_arg = OsString::from("-Wl");
+    for arg in args {
+        // If the argument itself contains a comma, we need to emit it
+        // as `-Xlinker`, otherwise we can use `-Wl`.
+        if arg.as_ref().as_encoded_bytes().contains(&b',') {
+            // Emit current `-Wl` argument, if any has been built.
+            if combined_arg != OsStr::new("-Wl") {
+                cmd.arg(combined_arg);
+                // Begin next `-Wl` argument.
+                combined_arg = OsString::from("-Wl");
+            }
+
+            // Emit `-Xlinker` argument.
+            cmd.arg("-Xlinker");
+            cmd.arg(arg);
+        } else {
+            // Append to `-Wl` argument.
+            combined_arg.push(",");
+            combined_arg.push(arg);
+        }
+    }
+    // Emit final `-Wl` argument.
+    if combined_arg != OsStr::new("-Wl") {
+        cmd.arg(combined_arg);
+    }
+}
 /// Arguments for the underlying linker.
 /// Add options to pass them through cc wrapper if `Linker` is a cc wrapper.
-fn link_args<L: Linker + ?Sized>(
-    l: &mut L,
-    args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>,
-) -> &mut L {
-    let args = args.into_iter();
+fn link_args<L: Linker + ?Sized>(l: &mut L, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut L {
     if !l.is_cc() {
         verbatim_args(l, args);
-    } else if args.len() != 0 {
-        // FIXME: Support arguments with commas, see `rpaths_to_flags` for the example.
-        let mut combined_arg = OsString::from("-Wl");
-        for arg in args {
-            combined_arg.push(",");
-            combined_arg.push(arg);
-        }
-        l.cmd().arg(combined_arg);
+    } else {
+        convert_link_args_to_cc_args(l.cmd(), args);
     }
     l
 }
@@ -224,7 +246,7 @@ macro_rules! generate_arg_methods {
                 verbatim_args(self, iter::once(arg))
             }
             #[allow(unused)]
-            pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>, IntoIter: ExactSizeIterator>) -> &mut Self {
+            pub(crate) fn link_args(&mut self, args: impl IntoIterator<Item: AsRef<OsStr>>) -> &mut Self {
                 link_args(self, args)
             }
             #[allow(unused)]
diff --git a/compiler/rustc_codegen_ssa/src/back/linker/tests.rs b/compiler/rustc_codegen_ssa/src/back/linker/tests.rs
new file mode 100644
index 00000000000..bf3e8c90200
--- /dev/null
+++ b/compiler/rustc_codegen_ssa/src/back/linker/tests.rs
@@ -0,0 +1,32 @@
+use super::*;
+
+#[test]
+fn test_rpaths_to_args() {
+    let mut cmd = Command::new("foo");
+    convert_link_args_to_cc_args(&mut cmd, &["-rpath", "path1", "-rpath", "path2"]);
+    assert_eq!(cmd.get_args(), [OsStr::new("-Wl,-rpath,path1,-rpath,path2")]);
+}
+
+#[test]
+fn test_xlinker() {
+    let mut cmd = Command::new("foo");
+    convert_link_args_to_cc_args(&mut cmd, &[
+        "arg1",
+        "arg2",
+        "arg3,with,comma",
+        "arg4,with,comma",
+        "arg5",
+        "arg6,with,comma",
+    ]);
+
+    assert_eq!(cmd.get_args(), [
+        OsStr::new("-Wl,arg1,arg2"),
+        OsStr::new("-Xlinker"),
+        OsStr::new("arg3,with,comma"),
+        OsStr::new("-Xlinker"),
+        OsStr::new("arg4,with,comma"),
+        OsStr::new("-Wl,arg5"),
+        OsStr::new("-Xlinker"),
+        OsStr::new("arg6,with,comma"),
+    ]);
+}
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs
index 56a808df6b0..d633cc98ac8 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs
@@ -13,39 +13,27 @@ pub(super) struct RPathConfig<'a> {
     pub linker_is_gnu: bool,
 }
 
-pub(super) fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec<OsString> {
+pub(super) fn get_rpath_linker_args(config: &RPathConfig<'_>) -> Vec<OsString> {
     debug!("preparing the RPATH!");
 
     let rpaths = get_rpaths(config);
-    let mut flags = rpaths_to_flags(rpaths);
+    let mut args = Vec::with_capacity(rpaths.len() * 2); // the minimum needed capacity
+
+    for rpath in rpaths {
+        args.push("-rpath".into());
+        args.push(rpath);
+    }
 
     if config.linker_is_gnu {
         // Use DT_RUNPATH instead of DT_RPATH if available
-        flags.push("-Wl,--enable-new-dtags".into());
+        args.push("--enable-new-dtags".into());
 
         // Set DF_ORIGIN for substitute $ORIGIN
-        flags.push("-Wl,-z,origin".into());
-    }
-
-    flags
-}
-
-fn rpaths_to_flags(rpaths: Vec<OsString>) -> Vec<OsString> {
-    let mut ret = Vec::with_capacity(rpaths.len()); // the minimum needed capacity
-
-    for rpath in rpaths {
-        if rpath.to_string_lossy().contains(',') {
-            ret.push("-Wl,-rpath".into());
-            ret.push("-Xlinker".into());
-            ret.push(rpath);
-        } else {
-            let mut single_arg = OsString::from("-Wl,-rpath,");
-            single_arg.push(rpath);
-            ret.push(single_arg);
-        }
+        args.push("-z".into());
+        args.push("origin".into());
     }
 
-    ret
+    args
 }
 
 fn get_rpaths(config: &RPathConfig<'_>) -> Vec<OsString> {
diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
index 39034842d10..f1a30105c59 100644
--- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
+++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs
@@ -1,13 +1,4 @@
-use std::ffi::OsString;
-use std::path::{Path, PathBuf};
-
-use super::{RPathConfig, get_rpath_relative_to_output, minimize_rpaths, rpaths_to_flags};
-
-#[test]
-fn test_rpaths_to_flags() {
-    let flags = rpaths_to_flags(vec!["path1".into(), "path2".into()]);
-    assert_eq!(flags, ["-Wl,-rpath,path1", "-Wl,-rpath,path2"]);
-}
+use super::*;
 
 #[test]
 fn test_minimize1() {
@@ -69,15 +60,3 @@ fn test_rpath_relative_issue_119571() {
     // Should not panic when lib only contains filename.
     let _ = get_rpath_relative_to_output(config, Path::new("libstd.so"));
 }
-
-#[test]
-fn test_xlinker() {
-    let args = rpaths_to_flags(vec!["a/normal/path".into(), "a,comma,path".into()]);
-
-    assert_eq!(args, vec![
-        OsString::from("-Wl,-rpath,a/normal/path"),
-        OsString::from("-Wl,-rpath"),
-        OsString::from("-Xlinker"),
-        OsString::from("a,comma,path")
-    ]);
-}