]> git.lizzy.rs Git - rust.git/commitdiff
linker: Add a linker rerun hack for gcc versions not supporting -static-pie
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 28 May 2020 19:12:31 +0000 (22:12 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 28 May 2020 20:38:59 +0000 (23:38 +0300)
src/librustc_codegen_ssa/back/link.rs
src/librustc_target/spec/tests/tests_impl.rs

index 9a7c4907754b04b00c688fb965e20430d28f7d33..b322e9a8fef1cea2d62c24cbf6eb49509f4b38a7 100644 (file)
@@ -12,7 +12,7 @@
 /// need out of the shared crate context before we get rid of it.
 use rustc_session::{filesearch, Session};
 use rustc_span::symbol::Symbol;
-use rustc_target::spec::crt_objects::CrtObjectsFallback;
+use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
 use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
 use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel};
 
 use cc::windows_registry;
 use tempfile::{Builder as TempFileBuilder, TempDir};
 
-use std::ascii;
-use std::char;
-use std::env;
 use std::ffi::OsString;
-use std::fmt;
-use std::fs;
-use std::io;
 use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
-use std::str;
+use std::{ascii, char, env, fmt, fs, io, mem, str};
 
 pub fn remove(sess: &Session, path: &Path) {
     if let Err(e) = fs::remove_file(path) {
@@ -543,6 +537,61 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
             continue;
         }
 
+        // Detect '-static-pie' used with an older version of gcc or clang not supporting it.
+        // Fallback from '-static-pie' to '-static' in that case.
+        if sess.target.target.options.linker_is_gnu
+            && flavor != LinkerFlavor::Ld
+            && (out.contains("unrecognized command line option")
+                || out.contains("unknown argument"))
+            && (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
+            && cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
+        {
+            info!("linker output: {:?}", out);
+            warn!(
+                "Linker does not support -static-pie command line option. Retrying with -static instead."
+            );
+            // Mirror `add_(pre,post)_link_objects` to replace CRT objects.
+            let fallback = crt_objects_fallback(sess, crate_type);
+            let opts = &sess.target.target.options;
+            let pre_objects =
+                if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
+            let post_objects =
+                if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
+            let get_objects = |objects: &CrtObjects, kind| {
+                objects
+                    .get(&kind)
+                    .iter()
+                    .copied()
+                    .flatten()
+                    .map(|obj| get_object_file_path(sess, obj).into_os_string())
+                    .collect::<Vec<_>>()
+            };
+            let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe);
+            let post_objects_static_pie = get_objects(post_objects, LinkOutputKind::StaticPicExe);
+            let mut pre_objects_static = get_objects(pre_objects, LinkOutputKind::StaticNoPicExe);
+            let mut post_objects_static = get_objects(post_objects, LinkOutputKind::StaticNoPicExe);
+            // Assume that we know insertion positions for the replacement arguments from replaced
+            // arguments, which is true for all supported targets.
+            assert!(pre_objects_static.is_empty() || !pre_objects_static_pie.is_empty());
+            assert!(post_objects_static.is_empty() || !post_objects_static_pie.is_empty());
+            for arg in cmd.take_args() {
+                if arg.to_string_lossy() == "-static-pie" {
+                    // Replace the output kind.
+                    cmd.arg("-static");
+                } else if pre_objects_static_pie.contains(&arg) {
+                    // Replace the pre-link objects (replace the first and remove the rest).
+                    cmd.args(mem::take(&mut pre_objects_static));
+                } else if post_objects_static_pie.contains(&arg) {
+                    // Replace the post-link objects (replace the first and remove the rest).
+                    cmd.args(mem::take(&mut post_objects_static));
+                } else {
+                    cmd.arg(arg);
+                }
+            }
+            info!("{:?}", &cmd);
+            continue;
+        }
+
         // Here's a terribly awful hack that really shouldn't be present in any
         // compiler. Here an environment variable is supported to automatically
         // retry the linker invocation if the linker looks like it segfaulted.
index 4cf186bdd7c1a718e20fff9fe9b4648e99c4d443..fb3f912ffde1ad500d76bcfc2c95581e8a30b384 100644 (file)
@@ -39,5 +39,10 @@ fn check_consistency(&self) {
                 assert_eq!(self.options.lld_flavor, LldFlavor::Link);
             }
         }
+        assert!(
+            (self.options.pre_link_objects_fallback.is_empty()
+                && self.options.post_link_objects_fallback.is_empty())
+                || self.options.crt_objects_fallback.is_some()
+        );
     }
 }