Skip to content

Commit ccb160d

Browse files
committed
Auto merge of #117115 - zetafunction:linking, r=bjorn3
Mark .rmeta files as /SAFESEH on x86 Windows. Chrome links .rlibs with /WHOLEARCHIVE or -Wl,--whole-archive to prevent the linker from discarding static initializers. This works well, except on Windows x86, where lld complains: error: /safeseh: lib.rmeta is not compatible with SEH The fix is simply to mark the .rmeta as SAFESEH aware. This is trivially true, since the metadata file does not contain any executable code.
2 parents 6d674af + 8fa800d commit ccb160d

File tree

7 files changed

+55
-33
lines changed

7 files changed

+55
-33
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+2-25
Original file line numberDiff line numberDiff line change
@@ -1889,37 +1889,14 @@ fn add_linked_symbol_object(
18891889
return;
18901890
};
18911891

1892-
// NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
1893-
// so add an empty section.
18941892
if file.format() == object::BinaryFormat::Coff {
1893+
// NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
1894+
// so add an empty section.
18951895
file.add_section(Vec::new(), ".text".into(), object::SectionKind::Text);
18961896

18971897
// We handle the name decoration of COFF targets in `symbol_export.rs`, so disable the
18981898
// default mangler in `object` crate.
18991899
file.set_mangling(object::write::Mangling::None);
1900-
1901-
// Add feature flags to the object file. On MSVC this is optional but LLD will complain if
1902-
// not present.
1903-
let mut feature = 0;
1904-
1905-
if file.architecture() == object::Architecture::I386 {
1906-
// Indicate that all SEH handlers are registered in .sxdata section.
1907-
// We don't have generate any code, so we don't need .sxdata section but LLD still
1908-
// expects us to set this bit (see #96498).
1909-
// Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
1910-
feature |= 1;
1911-
}
1912-
1913-
file.add_symbol(object::write::Symbol {
1914-
name: "@feat.00".into(),
1915-
value: feature,
1916-
size: 0,
1917-
kind: object::SymbolKind::Data,
1918-
scope: object::SymbolScope::Compilation,
1919-
weak: false,
1920-
section: object::write::SymbolSection::Absolute,
1921-
flags: object::SymbolFlags::None,
1922-
});
19231900
}
19241901

19251902
for (sym, kind) in symbols.iter() {

compiler/rustc_codegen_ssa/src/back/metadata.rs

+29
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,35 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
228228
if sess.target.is_like_osx {
229229
file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
230230
}
231+
if binary_format == BinaryFormat::Coff {
232+
// Disable the default mangler to avoid mangling the special "@feat.00" symbol name.
233+
let original_mangling = file.mangling();
234+
file.set_mangling(object::write::Mangling::None);
235+
236+
let mut feature = 0;
237+
238+
if file.architecture() == object::Architecture::I386 {
239+
// When linking with /SAFESEH on x86, lld requires that all linker inputs be marked as
240+
// safe exception handling compatible. Metadata files masquerade as regular COFF
241+
// objects and are treated as linker inputs, despite containing no actual code. Thus,
242+
// they still need to be marked as safe exception handling compatible. See #96498.
243+
// Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
244+
feature |= 1;
245+
}
246+
247+
file.add_symbol(object::write::Symbol {
248+
name: "@feat.00".into(),
249+
value: feature,
250+
size: 0,
251+
kind: object::SymbolKind::Data,
252+
scope: object::SymbolScope::Compilation,
253+
weak: false,
254+
section: object::write::SymbolSection::Absolute,
255+
flags: object::SymbolFlags::None,
256+
});
257+
258+
file.set_mangling(original_mangling);
259+
}
231260
let e_flags = match architecture {
232261
Architecture::Mips => {
233262
let arch = match sess.target.options.cpu.as_ref() {

tests/run-make/issue-96498/Makefile

-8
This file was deleted.
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# only-windows
2+
# needs-rust-lld
3+
4+
include ../tools.mk
5+
6+
all: foo bar
7+
8+
# Ensure that LLD can link when an .rlib contains a synthetic object
9+
# file referencing exported or used symbols.
10+
foo:
11+
$(RUSTC) -C linker=rust-lld foo.rs
12+
13+
# Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib.
14+
# Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware.
15+
bar: baz
16+
$(RUSTC) -C linker=rust-lld -C link-arg=/WHOLEARCHIVE:libbaz.rlib bar.rs
17+
18+
baz:
19+
$(RUSTC) baz.rs

tests/run-make/windows-safeseh/bar.rs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
fn main() {}

tests/run-make/windows-safeseh/baz.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#![crate_type = "rlib"]
2+
3+
#[no_mangle]
4+
extern "C" fn baz() {}
File renamed without changes.

0 commit comments

Comments
 (0)