Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 41 additions & 13 deletions compiler/rustc_codegen_ssa/src/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ pub fn link_binary(
&crate_info,
&metadata,
path.as_ref(),
outputs,
codegen_backend,
);
}
Expand Down Expand Up @@ -1239,6 +1240,7 @@ fn link_natively(
crate_info: &CrateInfo,
metadata: &EncodedMetadata,
tmpdir: &Path,
outputs: &OutputFilenames,
codegen_backend: &'static str,
) {
info!("preparing {:?} to {:?}", crate_type, out_filename);
Expand All @@ -1254,6 +1256,29 @@ fn link_natively(
should_archive.then(|| tmpdir.join(out_filename.file_name().unwrap()).with_extension("so"));
let temp_filename = archive_member.as_deref().unwrap_or(out_filename);

// Follow the same naming convention as regular codegen objects.
let metadata_object = outputs.temp_path_for_cgu(OutputType::Object, "rustc_link_metadata");
let symbols_object = outputs.temp_path_for_cgu(OutputType::Object, "rustc_link_symbols");

// Clean up the generated linker inputs even if linking fails.
let _cleanup = rustc_data_structures::defer(|| {
if !sess.opts.cg.save_temps {
if matches!(crate_type, CrateType::Dylib | CrateType::ProcMacro) {
ensure_removed(sess.dcx(), &metadata_object);
}

let needs_symbols = !crate_info.linked_symbols[&crate_type].is_empty()
|| (sess.target.is_like_msvc
&& !crate_info.exported_symbols[&crate_type].is_empty()
&& (crate_type != CrateType::Executable
|| sess.opts.unstable_opts.export_executable_symbols));

if needs_symbols {
ensure_removed(sess.dcx(), &symbols_object);
}
}
});

let (mut cmd, jobserver_tokens) = linker_with_args(
&linker_path,
flavor,
Expand All @@ -1262,6 +1287,8 @@ fn link_natively(
rmeta_link_cache,
crate_type,
tmpdir,
&metadata_object,
&symbols_object,
temp_filename,
compiled_modules,
crate_info,
Expand Down Expand Up @@ -2537,7 +2564,7 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
fn add_linked_symbol_object(
cmd: &mut dyn Linker,
sess: &Session,
tmpdir: &Path,
symbols_path: &Path,
crate_type: CrateType,
linked_symbols: &[(String, SymbolExportKind)],
exported_symbols: &[SymbolExport],
Expand Down Expand Up @@ -2672,12 +2699,10 @@ fn add_linked_symbol_object(
file.append_section_data(section, drectve.as_bytes(), 1);
}

let path = tmpdir.join("symbols.o");
let result = std::fs::write(&path, file.write().unwrap());
if let Err(error) = result {
sess.dcx().emit_fatal(diagnostics::FailedToWrite { path, error });
}
cmd.add_object(&path);
fs::write(symbols_path, file.write().unwrap()).unwrap_or_else(|e| {
sess.dcx().fatal(format!("failed to write {}: {e}", symbols_path.display()))
});
cmd.add_object(symbols_path);
}

/// Add object files containing code from the current crate.
Expand Down Expand Up @@ -2717,7 +2742,7 @@ fn add_local_crate_metadata_objects(
sess: &Session,
archive_builder_builder: &dyn ArchiveBuilderBuilder,
crate_type: CrateType,
tmpdir: &Path,
metadata_path: &Path,
crate_info: &CrateInfo,
metadata: &EncodedMetadata,
) {
Expand All @@ -2730,9 +2755,10 @@ fn add_local_crate_metadata_objects(
&metadata,
&crate_info.metadata_symbol,
);
let obj = emit_wrapper_file(sess, &data, tmpdir, "rmeta.o");

cmd.add_object(&obj);
fs::write(metadata_path, data).unwrap_or_else(|e| {
sess.dcx().fatal(format!("failed to write {}: {e}", metadata_path.display()))
});
cmd.add_object(metadata_path);
}
}

Expand Down Expand Up @@ -2915,6 +2941,8 @@ fn linker_with_args(
rmeta_link_cache: &mut RmetaLinkCache,
crate_type: CrateType,
tmpdir: &Path,
metadata_object: &Path,
symbols_object: &Path,
out_filename: &Path,
compiled_modules: &CompiledModules,
crate_info: &CrateInfo,
Expand Down Expand Up @@ -2975,7 +3003,7 @@ fn linker_with_args(
add_linked_symbol_object(
cmd,
sess,
tmpdir,
symbols_object,
crate_type,
&crate_info.linked_symbols[&crate_type],
&export_symbols,
Expand Down Expand Up @@ -3017,7 +3045,7 @@ fn linker_with_args(
sess,
archive_builder_builder,
crate_type,
tmpdir,
metadata_object,
crate_info,
metadata,
);
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_codegen_ssa/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -597,13 +597,6 @@ pub(crate) struct LinkScriptWriteFailure {
pub error: Error,
}

#[derive(Diagnostic)]
#[diag("failed to write {$path}: {$error}")]
pub(crate) struct FailedToWrite {
pub path: PathBuf,
pub error: Error,
}

#[derive(Diagnostic)]
#[diag("unable to write debugger visualizer file `{$path}`: {$error}")]
pub(crate) struct UnableToWriteDebuggerVisualizer {
Expand Down
3 changes: 3 additions & 0 deletions tests/run-make/linker-map-determinism/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub fn answer() -> u32 {
42
}
86 changes: 86 additions & 0 deletions tests/run-make/linker-map-determinism/rmake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Repeated dylib links must produce identical linker maps.
//
// Regression test for #142989: rustc used to pass a metadata object
// from a randomly named temporary directory to the linker, leaking
// that directory name into the map file.
//
//@ only-linux
//@ ignore-cross-compile
//@ ignore-backends: gcc

use std::fs;

use run_make_support::rustc;

fn main() {
let build = |map: &str| -> Vec<u8> {
let map_arg = format!("-Wl,-Map={map}");

rustc().input("lib.rs").crate_type("dylib").output("libfoo.so").link_arg(&map_arg).run();

fs::read("libfoo.so").unwrap()
};

let first_binary = build("first.map");
let second_binary = build("second.map");

// GNU ld records paths to both metadata and linked-symbol objects.
// Neither pathname should vary between otherwise identical builds.
assert!(
fs::read("first.map").unwrap() == fs::read("second.map").unwrap(),
"complete linker maps differ between identical builds"
);

let metadata_input = |map: &str| -> String {
let map = fs::read_to_string(map).unwrap();
map.lines()
.find(|line| line.trim_start().starts_with(".rustc ") && line.contains(".o"))
.expect("metadata object missing from linker map")
.to_owned()
};

assert_eq!(
metadata_input("first.map"),
metadata_input("second.map"),
"metadata object path differs between identical builds"
);

// Both synthetic linker inputs must use regular object filenames.
let metadata = "libfoo.rustc_link_metadata.rcgu.o";
let symbols = "libfoo.rustc_link_symbols.rcgu.o";

for map in ["first.map", "second.map"] {
let contents = fs::read_to_string(map).unwrap();
assert!(contents.contains(metadata), "metadata object missing from {map}");
assert!(contents.contains(symbols), "symbols object missing from {map}");
}

assert_eq!(first_binary, second_binary, "linked dylibs differ between identical builds");

// Normal linking removes synthetic objects.
assert!(!fs::exists(metadata).unwrap());
assert!(!fs::exists(symbols).unwrap());

// -C save-temps retains them.
rustc().input("lib.rs").crate_type("dylib").output("libfoo.so").arg("-Csave-temps").run();

assert!(fs::exists(metadata).unwrap());
assert!(fs::exists(symbols).unwrap());

// A subsequent normal build removes them again.
rustc().input("lib.rs").crate_type("dylib").output("libfoo.so").run();

assert!(!fs::exists(metadata).unwrap());
assert!(!fs::exists(symbols).unwrap());

// A linker failure must also clean up the generated objects.
rustc()
.input("lib.rs")
.crate_type("dylib")
.output("libfoo.so")
.arg("-Clink-arg=-Wl,--invalid-linker-map-test-option")
.run_fail();

assert!(!fs::exists(metadata).unwrap());
assert!(!fs::exists(symbols).unwrap());
}
1 change: 0 additions & 1 deletion tests/run-make/linker-warning/rmake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ fn main() {
"/build-root",
)
.normalize("libpanic_abort", "libpanic_unwind")
.normalize(r#""[^"]*\/symbols.o""#, "\"/symbols.o\"")
.normalize(r#""[^"]*\/raw-dylibs""#, "\"/raw-dylibs\"")
.normalize("\"-fno-lto\" ", "")
.run();
Expand Down
2 changes: 1 addition & 1 deletion tests/run-make/linker-warning/short-error.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
error: linking with `./fake-linker` failed: exit status: 1
|
= note: "./fake-linker" "-m64" "/symbols.o" "<2 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/build-root/test/run-make/linker-warning/rmake_out/{libfoo,libbar}.rlib" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error"
= note: "./fake-linker" "-m64" "<3 object files omitted>" "-Wl,--as-needed" "-Wl,-Bstatic" "/build-root/test/run-make/linker-warning/rmake_out/{libfoo,libbar}.rlib" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib/{libstd-*,libpanic_unwind-*,libobject-*,libmemchr-*,libaddr2line-*,libgimli-*,libcfg_if-*,librustc_demangle-*,libstd_detect-*,libhashbrown-*,librustc_std_workspace_alloc-*,libminiz_oxide-*,libadler2-*,libunwind-*,liblibc-*,librustc_std_workspace_core-*,liballoc-*,libcore-*,libcompiler_builtins-*}.rlib" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-L" "/raw-dylibs" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/build-root/test/run-make/linker-warning/rmake_out" "-L" "<sysroot>/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error"
= note: some arguments are omitted. use `--verbose` to show all linker arguments
= note: error: baz

Expand Down