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.
This commit is contained in:
commit
ccb160d343
@ -1889,37 +1889,14 @@ fn add_linked_symbol_object(
|
||||
return;
|
||||
};
|
||||
|
||||
// NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
|
||||
// so add an empty section.
|
||||
if file.format() == object::BinaryFormat::Coff {
|
||||
// NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
|
||||
// so add an empty section.
|
||||
file.add_section(Vec::new(), ".text".into(), object::SectionKind::Text);
|
||||
|
||||
// We handle the name decoration of COFF targets in `symbol_export.rs`, so disable the
|
||||
// default mangler in `object` crate.
|
||||
file.set_mangling(object::write::Mangling::None);
|
||||
|
||||
// Add feature flags to the object file. On MSVC this is optional but LLD will complain if
|
||||
// not present.
|
||||
let mut feature = 0;
|
||||
|
||||
if file.architecture() == object::Architecture::I386 {
|
||||
// Indicate that all SEH handlers are registered in .sxdata section.
|
||||
// We don't have generate any code, so we don't need .sxdata section but LLD still
|
||||
// expects us to set this bit (see #96498).
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
feature |= 1;
|
||||
}
|
||||
|
||||
file.add_symbol(object::write::Symbol {
|
||||
name: "@feat.00".into(),
|
||||
value: feature,
|
||||
size: 0,
|
||||
kind: object::SymbolKind::Data,
|
||||
scope: object::SymbolScope::Compilation,
|
||||
weak: false,
|
||||
section: object::write::SymbolSection::Absolute,
|
||||
flags: object::SymbolFlags::None,
|
||||
});
|
||||
}
|
||||
|
||||
for (sym, kind) in symbols.iter() {
|
||||
|
@ -228,6 +228,35 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
|
||||
if sess.target.is_like_osx {
|
||||
file.set_macho_build_version(macho_object_build_version_for_target(&sess.target))
|
||||
}
|
||||
if binary_format == BinaryFormat::Coff {
|
||||
// Disable the default mangler to avoid mangling the special "@feat.00" symbol name.
|
||||
let original_mangling = file.mangling();
|
||||
file.set_mangling(object::write::Mangling::None);
|
||||
|
||||
let mut feature = 0;
|
||||
|
||||
if file.architecture() == object::Architecture::I386 {
|
||||
// When linking with /SAFESEH on x86, lld requires that all linker inputs be marked as
|
||||
// safe exception handling compatible. Metadata files masquerade as regular COFF
|
||||
// objects and are treated as linker inputs, despite containing no actual code. Thus,
|
||||
// they still need to be marked as safe exception handling compatible. See #96498.
|
||||
// Reference: https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
|
||||
feature |= 1;
|
||||
}
|
||||
|
||||
file.add_symbol(object::write::Symbol {
|
||||
name: "@feat.00".into(),
|
||||
value: feature,
|
||||
size: 0,
|
||||
kind: object::SymbolKind::Data,
|
||||
scope: object::SymbolScope::Compilation,
|
||||
weak: false,
|
||||
section: object::write::SymbolSection::Absolute,
|
||||
flags: object::SymbolFlags::None,
|
||||
});
|
||||
|
||||
file.set_mangling(original_mangling);
|
||||
}
|
||||
let e_flags = match architecture {
|
||||
Architecture::Mips => {
|
||||
let arch = match sess.target.options.cpu.as_ref() {
|
||||
|
@ -1,8 +0,0 @@
|
||||
# only-windows
|
||||
# needs-rust-lld
|
||||
|
||||
include ../tools.mk
|
||||
|
||||
# Ensure that LLD can link
|
||||
all:
|
||||
$(RUSTC) -C linker=rust-lld foo.rs
|
19
tests/run-make/windows-safeseh/Makefile
Normal file
19
tests/run-make/windows-safeseh/Makefile
Normal file
@ -0,0 +1,19 @@
|
||||
# only-windows
|
||||
# needs-rust-lld
|
||||
|
||||
include ../tools.mk
|
||||
|
||||
all: foo bar
|
||||
|
||||
# Ensure that LLD can link when an .rlib contains a synthetic object
|
||||
# file referencing exported or used symbols.
|
||||
foo:
|
||||
$(RUSTC) -C linker=rust-lld foo.rs
|
||||
|
||||
# Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib.
|
||||
# Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware.
|
||||
bar: baz
|
||||
$(RUSTC) -C linker=rust-lld -C link-arg=/WHOLEARCHIVE:libbaz.rlib bar.rs
|
||||
|
||||
baz:
|
||||
$(RUSTC) baz.rs
|
1
tests/run-make/windows-safeseh/bar.rs
Normal file
1
tests/run-make/windows-safeseh/bar.rs
Normal file
@ -0,0 +1 @@
|
||||
fn main() {}
|
4
tests/run-make/windows-safeseh/baz.rs
Normal file
4
tests/run-make/windows-safeseh/baz.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn baz() {}
|
Loading…
Reference in New Issue
Block a user