Skip to content

Commit 78e7b45

Browse files
authored
Rollup merge of rust-lang#72708 - petrochenkov:linkhack, r=cuviper
linker: Add a linker rerun hack for gcc versions not supporting -static-pie Which mirrors the existing `-no-pie` linker rerun hack, but the logic is a bit more elaborated in this case. If the linker (gcc or clang) errors on `-static-pie` we rerun in with `-static` instead. We must also replace CRT objects corresponding to `-static-pie` with ones corresponding to `-static` in this case. (One sanity check for CRT objects in target specs is also added as a drive-by fix.) To do in the future: refactor all linker rerun hacks into separate functions and share more code with `add_(pre,post)_link_objects`. This PR accompanies rust-lang#71804 and unblocks rust-lang#70740.
2 parents 1088317 + 071f042 commit 78e7b45

File tree

2 files changed

+62
-8
lines changed

2 files changed

+62
-8
lines changed

src/librustc_codegen_ssa/back/link.rs

+57-8
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustc_session::utils::NativeLibKind;
1212
/// need out of the shared crate context before we get rid of it.
1313
use rustc_session::{filesearch, Session};
1414
use rustc_span::symbol::Symbol;
15-
use rustc_target::spec::crt_objects::CrtObjectsFallback;
15+
use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
1616
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
1717
use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel};
1818

@@ -25,16 +25,10 @@ use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FIL
2525
use cc::windows_registry;
2626
use tempfile::{Builder as TempFileBuilder, TempDir};
2727

28-
use std::ascii;
29-
use std::char;
30-
use std::env;
3128
use std::ffi::OsString;
32-
use std::fmt;
33-
use std::fs;
34-
use std::io;
3529
use std::path::{Path, PathBuf};
3630
use std::process::{ExitStatus, Output, Stdio};
37-
use std::str;
31+
use std::{ascii, char, env, fmt, fs, io, mem, str};
3832

3933
pub fn remove(sess: &Session, path: &Path) {
4034
if let Err(e) = fs::remove_file(path) {
@@ -543,6 +537,61 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
543537
continue;
544538
}
545539

540+
// Detect '-static-pie' used with an older version of gcc or clang not supporting it.
541+
// Fallback from '-static-pie' to '-static' in that case.
542+
if sess.target.target.options.linker_is_gnu
543+
&& flavor != LinkerFlavor::Ld
544+
&& (out.contains("unrecognized command line option")
545+
|| out.contains("unknown argument"))
546+
&& (out.contains("-static-pie") || out.contains("--no-dynamic-linker"))
547+
&& cmd.get_args().iter().any(|e| e.to_string_lossy() == "-static-pie")
548+
{
549+
info!("linker output: {:?}", out);
550+
warn!(
551+
"Linker does not support -static-pie command line option. Retrying with -static instead."
552+
);
553+
// Mirror `add_(pre,post)_link_objects` to replace CRT objects.
554+
let fallback = crt_objects_fallback(sess, crate_type);
555+
let opts = &sess.target.target.options;
556+
let pre_objects =
557+
if fallback { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects };
558+
let post_objects =
559+
if fallback { &opts.post_link_objects_fallback } else { &opts.post_link_objects };
560+
let get_objects = |objects: &CrtObjects, kind| {
561+
objects
562+
.get(&kind)
563+
.iter()
564+
.copied()
565+
.flatten()
566+
.map(|obj| get_object_file_path(sess, obj).into_os_string())
567+
.collect::<Vec<_>>()
568+
};
569+
let pre_objects_static_pie = get_objects(pre_objects, LinkOutputKind::StaticPicExe);
570+
let post_objects_static_pie = get_objects(post_objects, LinkOutputKind::StaticPicExe);
571+
let mut pre_objects_static = get_objects(pre_objects, LinkOutputKind::StaticNoPicExe);
572+
let mut post_objects_static = get_objects(post_objects, LinkOutputKind::StaticNoPicExe);
573+
// Assume that we know insertion positions for the replacement arguments from replaced
574+
// arguments, which is true for all supported targets.
575+
assert!(pre_objects_static.is_empty() || !pre_objects_static_pie.is_empty());
576+
assert!(post_objects_static.is_empty() || !post_objects_static_pie.is_empty());
577+
for arg in cmd.take_args() {
578+
if arg.to_string_lossy() == "-static-pie" {
579+
// Replace the output kind.
580+
cmd.arg("-static");
581+
} else if pre_objects_static_pie.contains(&arg) {
582+
// Replace the pre-link objects (replace the first and remove the rest).
583+
cmd.args(mem::take(&mut pre_objects_static));
584+
} else if post_objects_static_pie.contains(&arg) {
585+
// Replace the post-link objects (replace the first and remove the rest).
586+
cmd.args(mem::take(&mut post_objects_static));
587+
} else {
588+
cmd.arg(arg);
589+
}
590+
}
591+
info!("{:?}", &cmd);
592+
continue;
593+
}
594+
546595
// Here's a terribly awful hack that really shouldn't be present in any
547596
// compiler. Here an environment variable is supported to automatically
548597
// retry the linker invocation if the linker looks like it segfaulted.

src/librustc_target/spec/tests/tests_impl.rs

+5
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,10 @@ impl Target {
3838
assert_eq!(self.options.lld_flavor, LldFlavor::Link);
3939
}
4040
}
41+
assert!(
42+
(self.options.pre_link_objects_fallback.is_empty()
43+
&& self.options.post_link_objects_fallback.is_empty())
44+
|| self.options.crt_objects_fallback.is_some()
45+
);
4146
}
4247
}

0 commit comments

Comments
 (0)