From 5b31a16565220dd0ee8ecc272fb22a8034bc1b12 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 16 Jun 2025 09:20:57 +0000 Subject: [PATCH 1/2] Use the .drectve section for exporting symbols from dlls on Windows While it would be reasonable to expect the Windows linker to handle linker args in the .drectve section identical to cli arguments, as it turns out exporting weak symbols only works when the /EXPORT is in the .drectve section, not when it is a linker argument or when a .DEF file is used. --- compiler/rustc_codegen_ssa/src/back/link.rs | 52 +++++++++++++++++-- compiler/rustc_codegen_ssa/src/back/linker.rs | 48 ++--------------- tests/ui/linking/dll-weak-definition.rs | 20 +++++++ 3 files changed, 72 insertions(+), 48 deletions(-) create mode 100644 tests/ui/linking/dll-weak-definition.rs diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 2c3ee1bae09f8..78c6b39fe71a7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2189,9 +2189,11 @@ fn add_linked_symbol_object( cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, - symbols: &[(String, SymbolExportKind)], + crate_type: CrateType, + linked_symbols: &[(String, SymbolExportKind)], + exported_symbols: &[(String, SymbolExportKind)], ) { - if symbols.is_empty() { + if linked_symbols.is_empty() && exported_symbols.is_empty() { return; } @@ -2228,7 +2230,7 @@ fn add_linked_symbol_object( None }; - for (sym, kind) in symbols.iter() { + for (sym, kind) in linked_symbols.iter() { let symbol = file.add_symbol(object::write::Symbol { name: sym.clone().into(), value: 0, @@ -2286,6 +2288,41 @@ fn add_linked_symbol_object( } } + if sess.target.is_like_msvc { + // Symbol visibility takes care of this for executables typically + let should_filter_symbols = if crate_type == CrateType::Executable { + sess.opts.unstable_opts.export_executable_symbols + } else { + true + }; + if should_filter_symbols { + // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to + // export symbols from a dynamic library. When building a dynamic library, + // however, we're going to want some symbols exported, so this adds a + // `.drectve` section which lists all the symbols using /EXPORT arguments. + // + // The linker will read these arguments from the `.drectve` section and + // export all the symbols from the dynamic library. Note that this is not + // as simple as just exporting all the symbols in the current crate (as + // specified by `codegen.reachable`) but rather we also need to possibly + // export the symbols of upstream crates. Upstream rlibs may be linked + // statically to this dynamic library, in which case they may continue to + // transitively be used and hence need their symbols exported. + let drectve = exported_symbols + .into_iter() + .map(|(sym, kind)| match kind { + SymbolExportKind::Text | SymbolExportKind::Tls => format!(" /EXPORT:\"{sym}\""), + SymbolExportKind::Data => format!(" /EXPORT:\"{sym}\",DATA"), + }) + .collect::>() + .join(""); + + let section = + file.add_section(vec![], b".drectve".to_vec(), object::SectionKind::Linker); + 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 { @@ -2550,7 +2587,14 @@ fn linker_with_args( // Pre-link CRT objects. add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained_crt_objects); - add_linked_symbol_object(cmd, sess, tmpdir, &crate_info.linked_symbols[&crate_type]); + add_linked_symbol_object( + cmd, + sess, + tmpdir, + crate_type, + &crate_info.linked_symbols[&crate_type], + &export_symbols, + ); // Sanitizer libraries. add_sanitizer_libraries(sess, flavor, crate_type, cmd); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4041bfaa24cf0..0622fba408a12 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1126,53 +1126,13 @@ impl<'a> Linker for MsvcLinker<'a> { } } - // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to - // export symbols from a dynamic library. When building a dynamic library, - // however, we're going to want some symbols exported, so this function - // generates a DEF file which lists all the symbols. - // - // The linker will read this `*.def` file and export all the symbols from - // the dynamic library. Note that this is not as simple as just exporting - // all the symbols in the current crate (as specified by `codegen.reachable`) - // but rather we also need to possibly export the symbols of upstream - // crates. Upstream rlibs may be linked statically to this dynamic library, - // in which case they may continue to transitively be used and hence need - // their symbols exported. fn export_symbols( &mut self, - tmpdir: &Path, - crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], + _tmpdir: &Path, + _crate_type: CrateType, + _symbols: &[(String, SymbolExportKind)], ) { - // Symbol visibility takes care of this typically - if crate_type == CrateType::Executable { - let should_export_executable_symbols = - self.sess.opts.unstable_opts.export_executable_symbols; - if !should_export_executable_symbols { - return; - } - } - - let path = tmpdir.join("lib.def"); - let res = try { - let mut f = File::create_buffered(&path)?; - - // Start off with the standard module name header and then go - // straight to exports. - writeln!(f, "LIBRARY")?; - writeln!(f, "EXPORTS")?; - for (symbol, kind) in symbols { - let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; - debug!(" _{symbol}"); - writeln!(f, " {symbol}{kind_marker}")?; - } - }; - if let Err(error) = res { - self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); - } - let mut arg = OsString::from("/DEF:"); - arg.push(path); - self.link_arg(&arg); + // We already add /EXPORT arguments to the .drectve section of symbols.o. } fn windows_subsystem(&mut self, subsystem: WindowsSubsystemKind) { diff --git a/tests/ui/linking/dll-weak-definition.rs b/tests/ui/linking/dll-weak-definition.rs new file mode 100644 index 0000000000000..198a94ccee97e --- /dev/null +++ b/tests/ui/linking/dll-weak-definition.rs @@ -0,0 +1,20 @@ +// Regression test for MSVC link.exe failing to export weak definitions from dlls. +// See https://github.com/rust-lang/rust/pull/142568 + +//@ build-pass +//@ only-msvc +//@ revisions: link_exe lld +//@[lld] needs-rust-lld +//@[link_exe] compile-flags: -Zunstable-options -Clink-self-contained=-linker -Clinker-features=-lld +//@[lld] compile-flags: -Zunstable-options -Clink-self-contained=+linker -Clinker-features=+lld + +#![feature(linkage)] +#![crate_type = "cdylib"] + +#[linkage = "weak"] +#[no_mangle] +pub fn weak_function() {} + +#[linkage = "weak"] +#[no_mangle] +pub static WEAK_STATIC: u8 = 42; From 40515603f2110c98498801494f4f581d8626671b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=9D=E5=80=89=E6=B0=B4=E5=B8=8C?= Date: Tue, 23 Jun 2026 15:15:44 +0800 Subject: [PATCH 2/2] Fix MSVC drectve exports for decorated symbols --- compiler/rustc_codegen_ssa/src/back/link.rs | 83 ++++----- compiler/rustc_codegen_ssa/src/back/linker.rs | 159 +++++++++--------- .../src/back/symbol_export.rs | 5 +- compiler/rustc_codegen_ssa/src/lib.rs | 24 ++- typos.toml | 1 + 5 files changed, 145 insertions(+), 127 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 78c6b39fe71a7..ab8566399df18 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -62,7 +62,10 @@ use super::metadata::{MetadataPosition, create_wrapper_file}; use super::rpath::{self, RPathConfig}; use super::{apple, rmeta_link, versioned_llvm_target}; use crate::base::needs_allocator_shim_for_linking; -use crate::{CodegenLintLevelSpecs, CompiledModule, CompiledModules, CrateInfo, NativeLib, errors}; +use crate::{ + CodegenLintLevelSpecs, CompiledModule, CompiledModules, CrateInfo, NativeLib, SymbolExport, + errors, +}; pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) { if let Err(e) = fs::remove_file(path) { @@ -588,7 +591,7 @@ fn link_staticlib( crate_info .exported_symbols .get(&CrateType::StaticLib) - .map(|symbols| symbols.iter().map(|(s, _)| s.clone()).collect()) + .map(|symbols| symbols.iter().map(|symbol| symbol.name.clone()).collect()) } } else { None @@ -2191,9 +2194,13 @@ fn add_linked_symbol_object( tmpdir: &Path, crate_type: CrateType, linked_symbols: &[(String, SymbolExportKind)], - exported_symbols: &[(String, SymbolExportKind)], + exported_symbols: &[SymbolExport], ) { - if linked_symbols.is_empty() && exported_symbols.is_empty() { + let should_export_symbols = sess.target.is_like_msvc + && !exported_symbols.is_empty() + && (crate_type != CrateType::Executable + || sess.opts.unstable_opts.export_executable_symbols); + if linked_symbols.is_empty() && !should_export_symbols { return; } @@ -2288,39 +2295,35 @@ fn add_linked_symbol_object( } } - if sess.target.is_like_msvc { - // Symbol visibility takes care of this for executables typically - let should_filter_symbols = if crate_type == CrateType::Executable { - sess.opts.unstable_opts.export_executable_symbols - } else { - true - }; - if should_filter_symbols { - // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to - // export symbols from a dynamic library. When building a dynamic library, - // however, we're going to want some symbols exported, so this adds a - // `.drectve` section which lists all the symbols using /EXPORT arguments. - // - // The linker will read these arguments from the `.drectve` section and - // export all the symbols from the dynamic library. Note that this is not - // as simple as just exporting all the symbols in the current crate (as - // specified by `codegen.reachable`) but rather we also need to possibly - // export the symbols of upstream crates. Upstream rlibs may be linked - // statically to this dynamic library, in which case they may continue to - // transitively be used and hence need their symbols exported. - let drectve = exported_symbols - .into_iter() - .map(|(sym, kind)| match kind { - SymbolExportKind::Text | SymbolExportKind::Tls => format!(" /EXPORT:\"{sym}\""), - SymbolExportKind::Data => format!(" /EXPORT:\"{sym}\",DATA"), - }) - .collect::>() - .join(""); - - let section = - file.add_section(vec![], b".drectve".to_vec(), object::SectionKind::Linker); - file.append_section_data(section, drectve.as_bytes(), 1); + if should_export_symbols { + // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to + // export symbols from a dynamic library. When building a dynamic library, + // however, we're going to want some symbols exported, so this adds a + // `.drectve` section which lists all the symbols using /EXPORT arguments. + // + // The linker will read these arguments from the `.drectve` section and + // export all the symbols from the dynamic library. Note that this is not + // as simple as just exporting all the symbols in the current crate (as + // specified by `codegen.reachable`) but rather we also need to possibly + // export the symbols of upstream crates. Upstream rlibs may be linked + // statically to this dynamic library, in which case they may continue to + // transitively be used and hence need their symbols exported. + fn msvc_drectve_export(symbol: &SymbolExport) -> String { + let data = if symbol.kind == SymbolExportKind::Data { ",DATA" } else { "" }; + + if let Some(link_name) = symbol.link_name.as_deref() { + // The first name is the decorated symbol used by the import library, while + // EXPORTAS gives the public name written to the DLL export table. + format!(" /EXPORT:\"{link_name}\"{data},EXPORTAS,\"{}\"", symbol.name) + } else { + format!(" /EXPORT:\"{}\"{data}", symbol.name) + } } + + let drectve = exported_symbols.iter().map(msvc_drectve_export).collect::(); + + let section = file.add_section(vec![], b".drectve".to_vec(), object::SectionKind::Linker); + file.append_section_data(section, drectve.as_bytes(), 1); } let path = tmpdir.join("symbols.o"); @@ -2453,7 +2456,7 @@ fn add_rpath_args( fn add_c_staticlib_symbols( sess: &Session, lib: &NativeLib, - out: &mut Vec<(String, SymbolExportKind)>, + out: &mut Vec, ) -> io::Result<()> { let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess); @@ -2506,9 +2509,9 @@ fn add_c_staticlib_symbols( _ => continue, }; - // FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple. - // Need to be resolved. - out.push((name.to_string(), export_kind)); + // Names read from the object file are already linker-visible. + // Do not apply symbol decoration again here. + out.push(SymbolExport::new(name.to_string(), export_kind)); } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 0622fba408a12..9f981016c18af 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -15,7 +15,7 @@ use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ self, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{SymbolName, TyCtxt}; use rustc_session::Session; use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip}; use rustc_target::spec::{Arch, Cc, CfgAbi, LinkOutputKind, LinkerFlavor, Lld, Os}; @@ -25,7 +25,7 @@ use super::command::Command; use super::symbol_export; use crate::back::symbol_export::allocator_shim_symbols; use crate::base::needs_allocator_shim_for_linking; -use crate::errors; +use crate::{SymbolExport, errors}; #[cfg(test)] mod tests; @@ -338,12 +338,7 @@ pub(crate) trait Linker { fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]); fn no_crt_objects(&mut self); fn no_default_libraries(&mut self); - fn export_symbols( - &mut self, - tmpdir: &Path, - crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ); + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[SymbolExport]); fn windows_subsystem(&mut self, subsystem: WindowsSubsystemKind); fn linker_plugin_lto(&mut self); fn add_eh_frame_header(&mut self) {} @@ -794,12 +789,7 @@ impl<'a> Linker for GccLinker<'a> { } } - fn export_symbols( - &mut self, - tmpdir: &Path, - crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[SymbolExport]) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -826,9 +816,9 @@ impl<'a> Linker for GccLinker<'a> { // Write a plain, newline-separated list of symbols let res = try { let mut f = File::create_buffered(&path)?; - for (sym, _) in symbols { - debug!(" _{sym}"); - writeln!(f, "_{sym}")?; + for sym in symbols { + debug!(" _{}", sym.name); + writeln!(f, "_{}", sym.name)?; } }; if let Err(error) = res { @@ -842,12 +832,13 @@ impl<'a> Linker for GccLinker<'a> { // .def file similar to MSVC one but without LIBRARY section // because LD doesn't like when it's empty writeln!(f, "EXPORTS")?; - for (symbol, kind) in symbols { - let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" }; - debug!(" _{symbol}"); + for symbol in symbols { + let kind_marker = + if symbol.kind == SymbolExportKind::Data { " DATA" } else { "" }; + debug!(" _{}", symbol.name); // Quote the name in case it's reserved by linker in some way // (this accounts for names with dots in particular). - writeln!(f, " \"{symbol}\"{kind_marker}")?; + writeln!(f, " \"{}\"{kind_marker}", symbol.name)?; } }; if let Err(error) = res { @@ -856,16 +847,16 @@ impl<'a> Linker for GccLinker<'a> { self.link_arg(path); } else if self.sess.target.is_like_wasm { self.link_arg("--no-export-dynamic"); - for (sym, _) in symbols { - self.link_arg("--export").link_arg(sym); + for sym in symbols { + self.link_arg("--export").link_arg(&sym.name); } } else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris { let res = try { let mut f = File::create_buffered(&path)?; writeln!(f, "{{")?; - for (sym, _) in symbols { - debug!(sym); - writeln!(f, " {sym};")?; + for sym in symbols { + debug!("{}", sym.name); + writeln!(f, " {};", sym.name)?; } writeln!(f, "}};")?; }; @@ -880,9 +871,9 @@ impl<'a> Linker for GccLinker<'a> { writeln!(f, "{{")?; if !symbols.is_empty() { writeln!(f, " global:")?; - for (sym, _) in symbols { - debug!(" {sym};"); - writeln!(f, " {sym};")?; + for sym in symbols { + debug!(" {};", sym.name); + writeln!(f, " {};", sym.name)?; } } writeln!(f, "\n local:\n *;\n}};")?; @@ -1130,7 +1121,7 @@ impl<'a> Linker for MsvcLinker<'a> { &mut self, _tmpdir: &Path, _crate_type: CrateType, - _symbols: &[(String, SymbolExportKind)], + _symbols: &[SymbolExport], ) { // We already add /EXPORT arguments to the .drectve section of symbols.o. } @@ -1273,19 +1264,14 @@ impl<'a> Linker for EmLinker<'a> { self.cc_arg("-nodefaultlibs"); } - fn export_symbols( - &mut self, - _tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[SymbolExport]) { debug!("EXPORTED SYMBOLS:"); self.cc_arg("-s"); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( - &symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::>(), + &symbols.iter().map(|sym| "_".to_owned() + &sym.name).collect::>(), ) .unwrap(); debug!("{encoded}"); @@ -1413,14 +1399,9 @@ impl<'a> Linker for WasmLd<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols( - &mut self, - _tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { - for (sym, _) in symbols { - self.link_args(&["--export", sym]); + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[SymbolExport]) { + for sym in symbols { + self.link_args(&["--export", &sym.name]); } } @@ -1541,7 +1522,7 @@ impl<'a> Linker for L4Bender<'a> { self.cc_arg("-nostdlib"); } - fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) { + fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[SymbolExport]) { // ToDo, not implemented, copy from GCC self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented); } @@ -1695,19 +1676,14 @@ impl<'a> Linker for AixLinker<'a> { fn no_default_libraries(&mut self) {} - fn export_symbols( - &mut self, - tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[SymbolExport]) { let path = tmpdir.join("list.exp"); let res = try { let mut f = File::create_buffered(&path)?; // FIXME: use llvm-nm to generate export list. - for (symbol, _) in symbols { - debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; + for symbol in symbols { + debug!(" _{}", symbol.name); + writeln!(f, " {}", symbol.name)?; } }; if let Err(e) = res { @@ -1752,15 +1728,36 @@ fn for_each_exported_symbols_include_dep<'tcx>( } } -pub(crate) fn exported_symbols( +fn symbol_export_from_exported_symbol<'tcx>( + tcx: TyCtxt<'tcx>, + symbol: ExportedSymbol<'tcx>, + kind: SymbolExportKind, + cnum: CrateNum, +) -> SymbolExport { + let name = symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum); + let link_name = + symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, kind, cnum); + SymbolExport::with_link_name(name, kind, link_name) +} + +fn symbol_export_from_raw_name( tcx: TyCtxt<'_>, - crate_type: CrateType, -) -> Vec<(String, SymbolExportKind)> { + name: String, + kind: SymbolExportKind, +) -> SymbolExport { + let symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &name)); + let link_name = + symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, kind, LOCAL_CRATE); + SymbolExport::with_link_name(name, kind, link_name) +} + +pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec { if let Some(ref exports) = tcx.sess.target.override_export_symbols { return exports .iter() .map(|name| { - ( + symbol_export_from_raw_name( + tcx, name.to_string(), // FIXME use the correct export kind for this symbol. override_export_symbols // can't directly specify the SymbolExportKind as it is defined in rustc_middle @@ -1785,7 +1782,11 @@ pub(crate) fn exported_symbols( && !tcx.sess.target.is_like_wasm { let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx); - symbols.push((metadata_symbol_name, SymbolExportKind::Data)); + symbols.push(symbol_export_from_raw_name( + tcx, + metadata_symbol_name, + SymbolExportKind::Data, + )); } symbols @@ -1794,7 +1795,7 @@ pub(crate) fn exported_symbols( fn exported_symbols_for_non_proc_macro( tcx: TyCtxt<'_>, crate_type: CrateType, -) -> Vec<(String, SymbolExportKind)> { +) -> Vec { let mut symbols = Vec::new(); let export_threshold = symbol_export::crates_export_threshold(&[crate_type]); for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| { @@ -1802,10 +1803,7 @@ fn exported_symbols_for_non_proc_macro( // from any dylib. The latter doesn't work anyway as we use hidden visibility for // compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning. if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) { - symbols.push(( - symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum), - info.kind, - )); + symbols.push(symbol_export_from_exported_symbol(tcx, symbol, info.kind, cnum)); symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum); } }); @@ -1815,13 +1813,16 @@ fn exported_symbols_for_non_proc_macro( && needs_allocator_shim_for_linking(tcx.dependency_formats(()), crate_type) && let Some(kind) = tcx.allocator_kind(()) { - symbols.extend(allocator_shim_symbols(tcx, kind)); + symbols.extend( + allocator_shim_symbols(tcx, kind) + .map(|(name, kind)| symbol_export_from_raw_name(tcx, name, kind)), + ); } symbols } -fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> { +fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec { // `exported_symbols` will be empty when !should_codegen. if !tcx.sess.opts.output_types.should_codegen() { return Vec::new(); @@ -1830,7 +1831,7 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, Symbol let stable_crate_id = tcx.stable_crate_id(LOCAL_CRATE); let proc_macro_decls_name = rustc_session::generate_proc_macro_decls_symbol(stable_crate_id); - vec![(proc_macro_decls_name, SymbolExportKind::Data)] + vec![symbol_export_from_raw_name(tcx, proc_macro_decls_name, SymbolExportKind::Data)] } pub(crate) fn linked_symbols( @@ -1944,16 +1945,11 @@ impl<'a> Linker for LlbcLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols( - &mut self, - _tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[SymbolExport]) { match _crate_type { CrateType::Cdylib => { - for (sym, _) in symbols { - self.link_args(&["--export-symbol", sym]); + for sym in symbols { + self.link_args(&["--export-symbol", &sym.name]); } } _ => (), @@ -2024,17 +2020,12 @@ impl<'a> Linker for BpfLinker<'a> { fn ehcont_guard(&mut self) {} - fn export_symbols( - &mut self, - tmpdir: &Path, - _crate_type: CrateType, - symbols: &[(String, SymbolExportKind)], - ) { + fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[SymbolExport]) { let path = tmpdir.join("symbols"); let res = try { let mut f = File::create_buffered(&path)?; - for (sym, _) in symbols { - writeln!(f, "{sym}")?; + for sym in symbols { + writeln!(f, "{}", sym.name)?; } }; if let Err(error) = res { diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 014fd5cf3a0e5..997ca2b6080ce 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -19,6 +19,7 @@ use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{Arch, Os, TlsModel}; use tracing::debug; +use crate::SymbolExport; use crate::back::symbol_export; use crate::base::allocator_shim_contents; @@ -713,7 +714,7 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>( /// Add it to the symbols list for all kernel functions, so that it is exported in the linked /// object. pub(crate) fn extend_exported_symbols<'tcx>( - symbols: &mut Vec<(String, SymbolExportKind)>, + symbols: &mut Vec, tcx: TyCtxt<'tcx>, symbol: ExportedSymbol<'tcx>, instantiating_crate: CrateNum, @@ -729,7 +730,7 @@ pub(crate) fn extend_exported_symbols<'tcx>( // Add the symbol for the kernel descriptor (with .kd suffix) // Per https://llvm.org/docs/AMDGPUUsage.html#symbols these will always be `STT_OBJECT` so // export as data. - symbols.push((format!("{undecorated}.kd"), SymbolExportKind::Data)); + symbols.push(SymbolExport::new(format!("{undecorated}.kd"), SymbolExportKind::Data)); } fn maybe_emutls_symbol_name<'tcx>( diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 10ae8a9ee0b38..f3f19f9e90d83 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -233,6 +233,28 @@ impl From<&cstore::NativeLib> for NativeLib { } } +/// A symbol to make visible from a linked artifact. +#[derive(Clone, Debug, Encodable, Decodable)] +pub struct SymbolExport { + /// Name to make visible from the linked artifact. + pub name: String, + /// Kind of symbol, used for target-specific export directives and name decoration. + pub kind: SymbolExportKind, + /// Name of the symbol as seen by the linker, when it differs from `name`. + pub link_name: Option, +} + +impl SymbolExport { + pub fn new(name: String, kind: SymbolExportKind) -> SymbolExport { + SymbolExport { name, kind, link_name: None } + } + + pub fn with_link_name(name: String, kind: SymbolExportKind, link_name: String) -> SymbolExport { + let link_name = if link_name == name { None } else { Some(link_name) }; + SymbolExport { name, kind, link_name } + } +} + /// Misc info we load from metadata to persist beyond the tcx. /// /// Note: though `CrateNum` is only meaningful within the same tcx, information within `CrateInfo` @@ -247,7 +269,7 @@ pub struct CrateInfo { pub target_cpu: String, pub target_features: Vec, pub crate_types: Vec, - pub exported_symbols: UnordMap>, + pub exported_symbols: UnordMap>, pub linked_symbols: FxIndexMap>, pub local_crate_name: Symbol, pub compiler_builtins: Option, diff --git a/typos.toml b/typos.toml index f680f5b0e8abf..1e3d5c5e89d09 100644 --- a/typos.toml +++ b/typos.toml @@ -21,6 +21,7 @@ extend-exclude = [ # right now. Entries should look like `mipsel = "mipsel"`. # # tidy-alphabetical-start +EXPORTAS = "EXPORTAS" # MSVC linker keyword used with /EXPORT directives anser = "anser" # an ANSI parsing package used by rust-analyzer arange = "arange" # short for A-range childs = "childs"