From 4f9acb268704a1c7f78c8c55da0d7614eac57ade Mon Sep 17 00:00:00 2001 From: Gary Guo <gary@garyguo.net> Date: Tue, 26 Apr 2022 18:01:10 +0100 Subject: [PATCH 1/2] Use decorated names for linked_symbols on Windows --- compiler/rustc_codegen_ssa/src/back/link.rs | 4 ++ compiler/rustc_codegen_ssa/src/back/linker.rs | 2 +- .../src/back/symbol_export.rs | 72 ++++++++++++++++++- compiler/rustc_codegen_ssa/src/lib.rs | 1 + src/test/ui/symbol-names/x86-stdcall.rs | 13 ++++ 5 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/symbol-names/x86-stdcall.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 743f6c0e5703d..54a69fcf68110 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1696,6 +1696,10 @@ fn add_linked_symbol_object( // so add an empty section. if file.format() == object::BinaryFormat::Coff { 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); } for (sym, kind) in symbols.iter() { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 6e13e0d0e43b1..0805df5dad6bf 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1576,7 +1576,7 @@ pub(crate) fn linked_symbols( for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { if info.level.is_below_threshold(export_threshold) || info.used { symbols.push(( - symbol_export::symbol_name_for_instance_in_crate(tcx, symbol, cnum), + symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum), info.kind, )); } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 3a416c8a2b54b..f651814be7ea6 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -12,7 +12,7 @@ use rustc_middle::middle::exported_symbols::{ use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; -use rustc_middle::ty::{SymbolName, TyCtxt}; +use rustc_middle::ty::{self, SymbolName, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::SanitizerSet; @@ -493,6 +493,76 @@ pub fn symbol_name_for_instance_in_crate<'tcx>( } } +/// This is the symbol name of the given instance as seen by the linker. +/// +/// On 32-bit Windows symbols are decorated according to their calling conventions. +pub fn linking_symbol_name_for_instance_in_crate<'tcx>( + tcx: TyCtxt<'tcx>, + symbol: ExportedSymbol<'tcx>, + instantiating_crate: CrateNum, +) -> String { + use rustc_target::abi::call::Conv; + + let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate); + + let target = &tcx.sess.target; + if !target.is_like_windows { + // Mach-O has a global "_" suffix and `object` crate will handle it. + // ELF does not have any symbol decorations. + return undecorated; + } + + let x86 = match &target.arch[..] { + "x86" => true, + "x86_64" => false, + // Only x86/64 use symbol decorations. + _ => return undecorated, + }; + + let instance = match symbol { + ExportedSymbol::NonGeneric(def_id) | ExportedSymbol::Generic(def_id, _) + if tcx.is_static(def_id) => + { + None + } + ExportedSymbol::NonGeneric(def_id) => Some(Instance::mono(tcx, def_id)), + ExportedSymbol::Generic(def_id, substs) => Some(Instance::new(def_id, substs)), + // DropGlue always use the Rust calling convention and thus follow the target's default + // symbol decoration scheme. + ExportedSymbol::DropGlue(..) => None, + // NoDefId always follow the target's default symbol decoration scheme. + ExportedSymbol::NoDefId(..) => None, + }; + + let (conv, args) = instance + .map(|i| { + tcx.fn_abi_of_instance(ty::ParamEnv::reveal_all().and((i, ty::List::empty()))) + .unwrap_or_else(|_| bug!("fn_abi_of_instance({i:?}) failed")) + }) + .map(|fnabi| (fnabi.conv, &fnabi.args[..])) + .unwrap_or((Conv::Rust, &[])); + + // Decorate symbols with prefices, suffices and total number of bytes of arguments. + // Reference: https://docs.microsoft.com/en-us/cpp/build/reference/decorated-names?view=msvc-170 + let (prefix, suffix) = match conv { + Conv::X86Fastcall => ("@", "@"), + Conv::X86Stdcall => ("_", "@"), + Conv::X86VectorCall => ("", "@@"), + _ => { + if x86 { + undecorated.insert(0, '_'); + } + return undecorated; + } + }; + + let args_in_bytes: u64 = args + .iter() + .map(|abi| abi.layout.size.bytes().next_multiple_of(target.pointer_width as u64 / 8)) + .sum(); + format!("{prefix}{undecorated}{suffix}{args_in_bytes}") +} + fn wasm_import_module_map(tcx: TyCtxt<'_>, cnum: CrateNum) -> FxHashMap<DefId, String> { // Build up a map from DefId to a `NativeLib` structure, where // `NativeLib` internally contains information about diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index d430800220930..05d32972dab17 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -7,6 +7,7 @@ #![feature(nll)] #![feature(associated_type_bounds)] #![feature(strict_provenance)] +#![feature(int_roundings)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] diff --git a/src/test/ui/symbol-names/x86-stdcall.rs b/src/test/ui/symbol-names/x86-stdcall.rs new file mode 100644 index 0000000000000..9948488c0e950 --- /dev/null +++ b/src/test/ui/symbol-names/x86-stdcall.rs @@ -0,0 +1,13 @@ +// build-pass +// only-x86-windows +#![crate_type = "cdylib"] +#![feature(abi_vectorcall)] + +#[no_mangle] +extern "stdcall" fn foo(_: bool) {} + +#[no_mangle] +extern "fastcall" fn bar(_: u8) {} + +#[no_mangle] +extern "vectorcall" fn baz(_: u16) {} From 0fce0db96f5d7f3b42d25412d3989014551852ac Mon Sep 17 00:00:00 2001 From: Gary Guo <gary@garyguo.net> Date: Thu, 28 Apr 2022 16:22:40 +0100 Subject: [PATCH 2/2] Add `@feat.00` symbol to symbols.o for COFF --- compiler/rustc_codegen_ssa/src/back/link.rs | 23 +++++++++++++++++++++ src/test/run-make/issue-96498/Makefile | 8 +++++++ src/test/run-make/issue-96498/foo.rs | 4 ++++ 3 files changed, 35 insertions(+) create mode 100644 src/test/run-make/issue-96498/Makefile create mode 100644 src/test/run-make/issue-96498/foo.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 54a69fcf68110..886ca9681e2b2 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1700,6 +1700,29 @@ fn add_linked_symbol_object( // 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() { diff --git a/src/test/run-make/issue-96498/Makefile b/src/test/run-make/issue-96498/Makefile new file mode 100644 index 0000000000000..eae6400aee43a --- /dev/null +++ b/src/test/run-make/issue-96498/Makefile @@ -0,0 +1,8 @@ +# only-windows +# needs-rust-lld + +-include ../../run-make-fulldeps/tools.mk + +# Ensure that LLD can link +all: + $(RUSTC) -C linker=rust-lld foo.rs diff --git a/src/test/run-make/issue-96498/foo.rs b/src/test/run-make/issue-96498/foo.rs new file mode 100644 index 0000000000000..93ac3641b098c --- /dev/null +++ b/src/test/run-make/issue-96498/foo.rs @@ -0,0 +1,4 @@ +#![crate_type = "cdylib"] + +#[no_mangle] +extern "C" fn foo() {}