Skip to content

Commit 66bb33f

Browse files
authored
Merge pull request #242 from zanieb/zb/i686-win
Fix linking on i686 MSVC when using bare linkers
2 parents 275d7d1 + 9c77687 commit 66bb33f

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

cargo-auditable/src/object_file.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,44 @@ fn create_object_file(
181181
abi_version,
182182
e_flags,
183183
};
184+
185+
// Add the COFF `@feat.00` symbol used to communicate linker feature flags.
186+
//
187+
// When linking with /SAFESEH on x86, lld requires that all linker inputs be marked as safe
188+
// exception handling compatible. Our metadata objects masquerade as regular COFF objects and
189+
// are treated as linker inputs, so they need the flag too.
190+
//
191+
// This implementation mirrors the rustc's metadata object generation:
192+
// <https://github.com/rust-lang/rust/blob/b90dc1e597db0bbc0cab0eccb39747b1a9d7e607/compiler/rustc_codegen_ssa/src/back/metadata.rs#L224-L252>
193+
//
194+
// See also:
195+
//
196+
// - <https://github.com/rust-lang/rust/issues/96498>
197+
// - <https://learn.microsoft.com/en-us/windows/win32/debug/pe-format>
198+
if binary_format == BinaryFormat::Coff {
199+
// Disable mangling so the "@feat.00" symbol name is written verbatim.
200+
// CoffI386 mangling adds a `_` prefix which would break this special symbol.
201+
let original_mangling = file.mangling();
202+
file.set_mangling(write::Mangling::None);
203+
204+
let mut feature: u64 = 0;
205+
if architecture == Architecture::I386 {
206+
feature |= 1; // IMAGE_FILE_SAFE_EXCEPTION_HANDLER
207+
}
208+
file.add_symbol(Symbol {
209+
name: b"@feat.00".to_vec(),
210+
value: feature,
211+
size: 0,
212+
kind: SymbolKind::Data,
213+
scope: SymbolScope::Compilation,
214+
weak: false,
215+
section: SymbolSection::Absolute,
216+
flags: SymbolFlags::None,
217+
});
218+
219+
file.set_mangling(original_mangling);
220+
}
221+
184222
Some(file)
185223
}
186224

@@ -344,6 +382,65 @@ windows
344382
assert_eq!(result.architecture(), Architecture::I386);
345383
}
346384

385+
/// Verify that i686 COFF metadata objects contain an absolute `@feat.00` symbol with
386+
/// `IMAGE_FILE_SAFE_EXCEPTION_HANDLER` (bit 0) set.
387+
///
388+
/// See <https://github.com/rust-lang/rust/issues/96498>
389+
#[test]
390+
fn test_create_metadata_file_windows_msvc_i686_has_feat00() {
391+
let rustc_output = br#"debug_assertions
392+
target_arch="x86"
393+
target_endian="little"
394+
target_env="msvc"
395+
target_family="windows"
396+
target_feature="fxsr"
397+
target_feature="sse"
398+
target_feature="sse2"
399+
target_os="windows"
400+
target_pointer_width="32"
401+
target_vendor="pc"
402+
windows
403+
"#;
404+
let target_triple = "i686-pc-windows-msvc";
405+
let target_info = parse_rustc_target_info(rustc_output);
406+
let contents = b"test audit data";
407+
let result = create_metadata_file(
408+
&target_info,
409+
target_triple,
410+
contents,
411+
"AUDITABLE_VERSION_INFO",
412+
)
413+
.expect("should produce an object file for i686-pc-windows-msvc");
414+
415+
// Parse the COFF symbol table and verify `@feat.00` has value bit0=1 and absolute section.
416+
let symtab_ptr = u32::from_le_bytes(result[8..12].try_into().unwrap()) as usize;
417+
let sym_count = u32::from_le_bytes(result[12..16].try_into().unwrap()) as usize;
418+
let symbol_size = 18;
419+
420+
let feat = (0..sym_count).find_map(|i| {
421+
let start = symtab_ptr + i * symbol_size;
422+
let end = start + symbol_size;
423+
let entry = result.get(start..end)?;
424+
if &entry[0..8] != b"@feat.00" {
425+
return None;
426+
}
427+
let value = u32::from_le_bytes(entry[8..12].try_into().unwrap());
428+
let section_number = i16::from_le_bytes(entry[12..14].try_into().unwrap());
429+
Some((value, section_number))
430+
});
431+
432+
let (value, section_number) = feat.expect("COFF object for i686 must contain @feat.00");
433+
assert_eq!(
434+
value & 1,
435+
1,
436+
"@feat.00 must set IMAGE_FILE_SAFE_EXCEPTION_HANDLER on i686"
437+
);
438+
assert_eq!(
439+
section_number, -1,
440+
"@feat.00 must be an absolute COFF symbol (section number -1)"
441+
);
442+
}
443+
347444
#[test]
348445
fn test_create_object_file_windows_gnu() {
349446
let rustc_output = br#"debug_assertions

0 commit comments

Comments
 (0)