Skip to content

Commit

Permalink
Rollup merge of rust-lang#72708 - petrochenkov:linkhack, r=cuviper
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
RalfJung authored Jun 6, 2020
2 parents 1088317 + 071f042 commit 78e7b45
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 8 deletions.
65 changes: 57 additions & 8 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_session::utils::NativeLibKind;
/// 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};

Expand All @@ -25,16 +25,10 @@ use crate::{looks_like_rust_object_file, CodegenResults, CrateInfo, METADATA_FIL
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) {
Expand Down Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions src/librustc_target/spec/tests/tests_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,10 @@ impl Target {
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()
);
}
}

0 comments on commit 78e7b45

Please sign in to comment.