From e6aa2010ef1cf5bc1fc772b644a4b9422501eac9 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/3] 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 | 42 +++++++++++++++++-- compiler/rustc_codegen_ssa/src/back/linker.rs | 21 ++-------- 2 files changed, 43 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8c52ed6ed1234..44bfc746a741f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1976,9 +1976,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], ) { - if symbols.is_empty() { + if linked_symbols.is_empty() && exported_symbols.is_empty() { return; } @@ -2015,7 +2017,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, @@ -2073,6 +2075,38 @@ 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| format!(" /EXPORT:\"{sym}\"")) + .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 { @@ -2247,7 +2281,9 @@ fn linker_with_args( cmd, sess, tmpdir, + crate_type, &codegen_results.crate_info.linked_symbols[&crate_type], + &codegen_results.crate_info.exported_symbols[&crate_type], ); // Sanitizer libraries. diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 8fc83908efbcc..f0ebc2a6cc87d 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1086,19 +1086,10 @@ 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]) { + fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, _symbols: &[String]) { + // We already add /EXPORT arguments to the .drectve section of symbols.o. We generate + // a .DEF file here anyway as it might prevent auto-export of some symbols. + // Symbol visibility takes care of this typically if crate_type == CrateType::Executable { let should_export_executable_symbols = @@ -1116,10 +1107,6 @@ impl<'a> Linker for MsvcLinker<'a> { // straight to exports. writeln!(f, "LIBRARY")?; writeln!(f, "EXPORTS")?; - for symbol in symbols { - debug!(" _{symbol}"); - writeln!(f, " {symbol}")?; - } }; if let Err(error) = res { self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); From ca57c8dc6fe0673729e9576200768d256691854e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 11 Jun 2025 12:00:16 +0200 Subject: [PATCH 2/3] add aliasses to llvm --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 8 ++++++++ compiler/rustc_codegen_llvm/src/llvm/mod.rs | 16 +++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 91ada856d5977..6da030d0efed5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2670,4 +2670,12 @@ unsafe extern "C" { pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value); pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value); + + pub(crate) fn LLVMAddAlias2( + M: &Module, + ValueTy: &Type, + AddressSpace: c_uint, + Aliasee: &Value, + Name: *const c_char, + ); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 661174a80dfbd..13c0c4429a183 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -7,7 +7,7 @@ use std::str::FromStr; use std::string::FromUtf8Error; use libc::c_uint; -use rustc_abi::{Align, Size, WrappingRange}; +use rustc_abi::{AddressSpace, Align, Size, WrappingRange}; use rustc_llvm::RustString; pub(crate) use self::CallConv::*; @@ -350,6 +350,20 @@ impl Intrinsic { } } +/// Safe wrapper for `LLVMAddAlias2` +pub(crate) fn add_alias( + module: &Module, + ty: &Type, + address_space: AddressSpace, + aliasee: &Value, + name: &[u8], +) { + unsafe { + let data = name.as_c_char_ptr(); + LLVMAddAlias2(value, data, address_space, aliasee, name.len()); + } +} + /// Safe wrapper for `LLVMSetValueName2` from a byte slice pub(crate) fn set_value_name(value: &Value, name: &[u8]) { unsafe { From d4526ac3090e271b55c3d040bb84ef9a8d9bff3a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 16 Jun 2025 09:06:30 +0000 Subject: [PATCH 3/3] [WIP] Use weak aliases for the allocator shim --- compiler/rustc_codegen_gcc/src/mono_item.rs | 2 + compiler/rustc_codegen_llvm/src/allocator.rs | 36 +------------- compiler/rustc_codegen_llvm/src/lib.rs | 4 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 6 +-- compiler/rustc_codegen_llvm/src/llvm/mod.rs | 13 ++--- compiler/rustc_codegen_llvm/src/mono_item.rs | 47 +++++++++++++++++++ .../rustc_codegen_ssa/src/traits/declare.rs | 6 ++- library/alloc/src/alloc.rs | 18 +------ 8 files changed, 67 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs index 539e3ac850763..059c335435fac 100644 --- a/compiler/rustc_codegen_gcc/src/mono_item.rs +++ b/compiler/rustc_codegen_gcc/src/mono_item.rs @@ -76,4 +76,6 @@ impl<'gcc, 'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.functions.borrow_mut().insert(symbol_name.to_string(), decl); self.function_instances.borrow_mut().insert(instance, decl); } + + fn weak_alias(&self, _aliasee: Self::Function, _aliasee_name: &str, _name: &str) {} } diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index 4a78e69497994..1d044c688cec8 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -1,7 +1,6 @@ use libc::c_uint; use rustc_ast::expand::allocator::{ - ALLOCATOR_METHODS, AllocatorKind, AllocatorTy, NO_ALLOC_SHIM_IS_UNSTABLE, - alloc_error_handler_name, default_fn_name, global_fn_name, + AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, alloc_error_handler_name, }; use rustc_codegen_ssa::traits::BaseTypeCodegenMethods as _; use rustc_middle::bug; @@ -18,7 +17,6 @@ pub(crate) unsafe fn codegen( tcx: TyCtxt<'_>, cx: SimpleCx<'_>, module_name: &str, - kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) { let usize = match tcx.sess.target.pointer_width { @@ -28,38 +26,6 @@ pub(crate) unsafe fn codegen( tws => bug!("Unsupported target word size for int: {}", tws), }; let i8 = cx.type_i8(); - let i8p = cx.type_ptr(); - - if kind == AllocatorKind::Default { - for method in ALLOCATOR_METHODS { - let mut args = Vec::with_capacity(method.inputs.len()); - for input in method.inputs.iter() { - match input.ty { - AllocatorTy::Layout => { - args.push(usize); // size - args.push(usize); // align - } - AllocatorTy::Ptr => args.push(i8p), - AllocatorTy::Usize => args.push(usize), - - AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"), - } - } - let output = match method.output { - AllocatorTy::ResultPtr => Some(i8p), - AllocatorTy::Unit => None, - - AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => { - panic!("invalid allocator output") - } - }; - - let from_name = mangle_internal_symbol(tcx, &global_fn_name(method.name)); - let to_name = mangle_internal_symbol(tcx, &default_fn_name(method.name)); - - create_wrapper_function(tcx, &cx, &from_name, &to_name, &args, output, false); - } - } // rust alloc error handler create_wrapper_function( diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index cdfffbe47bfa5..7fc57de47946a 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -108,14 +108,14 @@ impl ExtraBackendMethods for LlvmCodegenBackend { &self, tcx: TyCtxt<'tcx>, module_name: &str, - kind: AllocatorKind, + _kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind, ) -> ModuleLlvm { let module_llvm = ModuleLlvm::new_metadata(tcx, module_name); let cx = SimpleCx::new(module_llvm.llmod(), &module_llvm.llcx, tcx.data_layout.pointer_size); unsafe { - allocator::codegen(tcx, cx, module_name, kind, alloc_error_handler_kind); + allocator::codegen(tcx, cx, module_name, alloc_error_handler_kind); } module_llvm } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 6da030d0efed5..d9784b28d2286 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2671,11 +2671,11 @@ unsafe extern "C" { pub(crate) fn LLVMRustSetNoSanitizeAddress(Global: &Value); pub(crate) fn LLVMRustSetNoSanitizeHWAddress(Global: &Value); - pub(crate) fn LLVMAddAlias2( - M: &Module, + pub(crate) fn LLVMAddAlias2<'ll>( + M: &'ll Module, ValueTy: &Type, AddressSpace: c_uint, Aliasee: &Value, Name: *const c_char, - ); + ) -> &'ll Value; } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 13c0c4429a183..6dc11cae73201 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -351,17 +351,14 @@ impl Intrinsic { } /// Safe wrapper for `LLVMAddAlias2` -pub(crate) fn add_alias( - module: &Module, +pub(crate) fn add_alias<'ll>( + module: &'ll Module, ty: &Type, address_space: AddressSpace, aliasee: &Value, - name: &[u8], -) { - unsafe { - let data = name.as_c_char_ptr(); - LLVMAddAlias2(value, data, address_space, aliasee, name.len()); - } + name: &CStr, +) -> &'ll Value { + unsafe { LLVMAddAlias2(module, ty, address_space.0, aliasee, name.as_ptr()) } } /// Safe wrapper for `LLVMSetValueName2` from a byte slice diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 3f38e1e191bf2..8bebeb3af0b28 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -1,3 +1,6 @@ +use std::ffi::CString; + +use rustc_abi::AddressSpace; use rustc_codegen_ssa::traits::*; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; @@ -6,6 +9,7 @@ use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; use rustc_session::config::CrateType; +use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::RelocModel; use tracing::debug; @@ -77,8 +81,51 @@ impl<'tcx> PreDefineCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { self.assume_dso_local(lldecl, false); + let symbol_name = self.tcx.symbol_name(instance); + if symbol_name.name.contains("__rdl_alloc") { + self.weak_alias( + lldecl, + symbol_name.name, + &mangle_internal_symbol(self.tcx, "__rust_alloc"), + ); + } + if symbol_name.name.contains("__rdl_dealloc") { + self.weak_alias( + lldecl, + symbol_name.name, + &mangle_internal_symbol(self.tcx, "__rust_dealloc"), + ); + } + if symbol_name.name.contains("__rdl_realloc") { + self.weak_alias( + lldecl, + symbol_name.name, + &mangle_internal_symbol(self.tcx, "__rust_realloc"), + ); + } + if symbol_name.name.contains("__rdl_alloc_zeroed") { + self.weak_alias( + lldecl, + symbol_name.name, + &mangle_internal_symbol(self.tcx, "__rust_alloc_zeroed"), + ); + } + self.instances.borrow_mut().insert(instance, lldecl); } + + fn weak_alias(&self, aliasee: Self::Function, _aliasee_name: &str, name: &str) { + let ty = self.get_type_of_global(aliasee); + let alias = llvm::add_alias( + self.llmod, + ty, + AddressSpace::DATA, + aliasee, + &CString::new(name).unwrap(), + ); + + llvm::set_linkage(alias, llvm::Linkage::WeakAnyLinkage); + } } impl CodegenCx<'_, '_> { diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs index 9f735546558b0..675ff04a02374 100644 --- a/compiler/rustc_codegen_ssa/src/traits/declare.rs +++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs @@ -2,7 +2,9 @@ use rustc_hir::def_id::DefId; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::Instance; -pub trait PreDefineCodegenMethods<'tcx> { +use crate::traits::BackendTypes; + +pub trait PreDefineCodegenMethods<'tcx>: BackendTypes { fn predefine_static( &mut self, def_id: DefId, @@ -17,4 +19,6 @@ pub trait PreDefineCodegenMethods<'tcx> { visibility: Visibility, symbol_name: &str, ); + + fn weak_alias(&self, aliasee: Self::Function, aliasee_name: &str, name: &str); } diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index e1cc4ba25c4ea..f6d91f018d947 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -31,8 +31,6 @@ unsafe extern "Rust" { #[rustc_std_internal_symbol] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; - #[rustc_std_internal_symbol] - static __rust_no_alloc_shim_is_unstable: u8; } /// The global memory allocator. @@ -85,13 +83,7 @@ pub struct Global; #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn alloc(layout: Layout) -> *mut u8 { - unsafe { - // Make sure we don't accidentally allow omitting the allocator shim in - // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); - - __rust_alloc(layout.size(), layout.align()) - } + unsafe { __rust_alloc(layout.size(), layout.align()) } } /// Deallocates memory with the global allocator. @@ -168,13 +160,7 @@ pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 #[inline] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { - unsafe { - // Make sure we don't accidentally allow omitting the allocator shim in - // stable code until it is actually stabilized. - core::ptr::read_volatile(&__rust_no_alloc_shim_is_unstable); - - __rust_alloc_zeroed(layout.size(), layout.align()) - } + unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) } } impl Global {