From 3decd9b284a6d5bad2b549ec9ead25a3cec93d80 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sun, 2 Nov 2025 21:19:29 +0100 Subject: [PATCH 1/3] Mangle personality symbol Previously, std-internal symbols (like `__rust_alloc` or `rust_panic`) were changed to now be mangled via a v0 scheme with the compiler version hash (`_RNvCs4CIB29Id3dw_7___rustc10rust_panic`) to make it possible to have multiple staticlibs (as long as they have different version hashes) in the same program without symbol conflicts. But the personality function remained unmangled, because LLVM hardcodes that name. I made a change in LLVM that makes LLVM now check the suffix instead of an exact match, so we can mangle the personality function with this scheme. This removes the last completely unmangled symbol from Rust staticlibs! (though the mangling is still quite weak, so it's still not as nice as it would ideally be). Before, on a trivial staticlib: ``` readelf -s liblib.a | rg GLOBAL | rg -v " UND | HIDDEN " | rg -v ' _ZN' 8: 0000000000000000 5 FUNC GLOBAL DEFAULT 3 _RNvCseCSg29WUqSe_7___rustc12___rust_alloc 10: 0000000000000000 5 FUNC GLOBAL DEFAULT 5 _RNvCseCSg29WUqSe_7___rustc14___rust_dealloc 12: 0000000000000000 5 FUNC GLOBAL DEFAULT 7 _RNvCseCSg29WUqSe_7___rustc14___rust_realloc 14: 0000000000000000 5 FUNC GLOBAL DEFAULT 9 _RNvCseCSg29WUqSe_7___rustc19___rust_alloc_zeroed 16: 0000000000000000 3 FUNC GLOBAL DEFAULT 11 _RNvCseCSg29WUqSe_7___rustc42___rust_alloc_error_handler_should_panic_v2 17: 0000000000000000 1 FUNC GLOBAL DEFAULT 12 _RNvCseCSg29WUqSe_7___rustc35___rust_no_alloc_shim_is_unstable_v2 3383: 0000000000000000 111 FUNC GLOBAL DEFAULT 5 _RNvCseCSg29WUqSe_7___rustc10rust_panic 3387: 0000000000000000 93 FUNC GLOBAL DEFAULT 7 _RNvCseCSg29WUqSe_7___rustc11___rdl_alloc 3390: 0000000000000000 10 FUNC GLOBAL DEFAULT 9 _RNvCseCSg29WUqSe_7___rustc12___rust_abort 3391: 0000000000000000 6 FUNC GLOBAL DEFAULT 11 _RNvCseCSg29WUqSe_7___rustc13___rdl_dealloc 3393: 0000000000000000 167 FUNC GLOBAL DEFAULT 13 _RNvCseCSg29WUqSe_7___rustc13___rdl_realloc 3396: 0000000000000000 203 FUNC GLOBAL DEFAULT 15 _RNvCseCSg29WUqSe_7___rustc17___rust_drop_panic 3399: 0000000000000000 29 FUNC GLOBAL DEFAULT 18 _RNvCseCSg29WUqSe_7___rustc17rust_begin_unwind 3401: 0000000000000000 140 FUNC GLOBAL DEFAULT 20 _RNvCseCSg29WUqSe_7___rustc18___rdl_alloc_zeroed 3404: 0000000000000000 203 FUNC GLOBAL DEFAULT 22 _RNvCseCSg29WUqSe_7___rustc24___rust_foreign_exception 3405: 0000000000000000 19 FUNC GLOBAL DEFAULT 25 _RNvCseCSg29WUqSe_7___rustc26___rust_alloc_error_handler 4410: 0000000000000000 1471 FUNC GLOBAL DEFAULT 2752 rust_eh_personality 25: 0000000000000000 161 FUNC GLOBAL DEFAULT 5 _RNvCseCSg29WUqSe_7___rustc18___rust_start_panic 32: 0000000000000000 82 FUNC GLOBAL DEFAULT 8 _RNvCseCSg29WUqSe_7___rustc20___rust_panic_cleanup 249: 0000000000000000 182 FUNC GLOBAL DEFAULT 5 _RNvCseCSg29WUqSe_7___rustc25___rdl_alloc_error_handler 3: 0000000000000000 57 FUNC GLOBAL DEFAULT 3 _RNvCseCSg29WUqSe_7___rustc17___rust_probestack ``` After: ``` 8: 0000000000000000 5 FUNC GLOBAL DEFAULT 3 _RNvCs4CIB29Id3dw_7___rustc12___rust_alloc 10: 0000000000000000 5 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc14___rust_dealloc 12: 0000000000000000 5 FUNC GLOBAL DEFAULT 7 _RNvCs4CIB29Id3dw_7___rustc14___rust_realloc 14: 0000000000000000 5 FUNC GLOBAL DEFAULT 9 _RNvCs4CIB29Id3dw_7___rustc19___rust_alloc_zeroed 16: 0000000000000000 3 FUNC GLOBAL DEFAULT 11 _RNvCs4CIB29Id3dw_7___rustc42___rust_alloc_error_handler_should_panic_v2 17: 0000000000000000 1 FUNC GLOBAL DEFAULT 12 _RNvCs4CIB29Id3dw_7___rustc35___rust_no_alloc_shim_is_unstable_v2 422: 0000000000000000 19 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc26___rust_alloc_error_handler 429: 0000000000000000 308 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc19rust_eh_personality 349: 0000000000000000 10 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc12___rust_abort 164: 0000000000000000 93 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc11___rdl_alloc 167: 0000000000000000 11 FUNC GLOBAL DEFAULT 7 _RNvCs4CIB29Id3dw_7___rustc13___rdl_dealloc 169: 0000000000000000 167 FUNC GLOBAL DEFAULT 9 _RNvCs4CIB29Id3dw_7___rustc13___rdl_realloc 172: 0000000000000000 140 FUNC GLOBAL DEFAULT 11 _RNvCs4CIB29Id3dw_7___rustc18___rdl_alloc_zeroed 688: 0000000000000000 106 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc10rust_panic 693: 0000000000000000 207 FUNC GLOBAL DEFAULT 7 _RNvCs4CIB29Id3dw_7___rustc17___rust_drop_panic 696: 0000000000000000 29 FUNC GLOBAL DEFAULT 10 _RNvCs4CIB29Id3dw_7___rustc17rust_begin_unwind 698: 0000000000000000 207 FUNC GLOBAL DEFAULT 12 _RNvCs4CIB29Id3dw_7___rustc24___rust_foreign_exception 26: 0000000000000000 161 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc18___rust_start_panic 33: 0000000000000000 82 FUNC GLOBAL DEFAULT 8 _RNvCs4CIB29Id3dw_7___rustc20___rust_panic_cleanup 88: 0000000000000000 182 FUNC GLOBAL DEFAULT 5 _RNvCs4CIB29Id3dw_7___rustc25___rdl_alloc_error_handler 3: 0000000000000000 57 FUNC GLOBAL DEFAULT 3 _RNvCs4CIB29Id3dw_7___rustc17___rust_probestack ``` --- .../src/debuginfo/unwind.rs | 4 +- .../rustc_codegen_cranelift/src/driver/aot.rs | 2 +- .../src/unwind_module.rs | 5 +- compiler/rustc_codegen_gcc/src/context.rs | 4 +- compiler/rustc_codegen_gcc/src/declare.rs | 2 +- compiler/rustc_codegen_gcc/src/lib.rs | 15 +++++- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 +- compiler/rustc_codegen_llvm/src/context.rs | 9 +++- compiler/rustc_codegen_llvm/src/lib.rs | 5 ++ compiler/rustc_codegen_ssa/src/back/write.rs | 2 + .../rustc_codegen_ssa/src/traits/backend.rs | 6 +++ compiler/rustc_interface/src/interface.rs | 2 + compiler/rustc_session/src/session.rs | 5 ++ compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_symbol_mangling/src/v0.rs | 9 +++- src/tools/compiletest/src/runtest/run_make.rs | 4 ++ .../src/external_deps/llvm.rs | 13 +++++ src/tools/run-make-support/src/lib.rs | 2 +- tests/codegen-llvm/gdb_debug_script_load.rs | 2 +- tests/run-make/no-alloc-shim/foo.rs | 4 +- tests/run-make/repr128-dwarf/rmake.rs | 2 +- tests/run-make/symbols-all-mangled/rmake.rs | 54 ++++++++++--------- .../raw-dylib/elf/glibc-x86_64.rs | 4 +- 23 files changed, 113 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 4b0260a8abc74..094fd0f0d1abe 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -25,7 +25,7 @@ pub(crate) struct UnwindContext { } impl UnwindContext { - pub(crate) fn new(module: &mut dyn Module, pic_eh_frame: bool) -> Self { + pub(crate) fn new(module: &mut dyn Module, tcx: TyCtxt<'_>, pic_eh_frame: bool) -> Self { let endian = match module.isa().endianness() { Endianness::Little => RunTimeEndian::Little, Endianness::Big => RunTimeEndian::Big, @@ -70,7 +70,7 @@ impl UnwindContext { // FIXME use eh_personality lang item instead let personality = module .declare_function( - "rust_eh_personality", + &rustc_symbol_mangling::eh_personality_symbol(tcx), Linkage::Import, &Signature { params: vec![ diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index d6c25cf524a5c..f21d0df8461f6 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -62,7 +62,7 @@ fn make_module(tcx: TyCtxt<'_>, cgu_name: &str) -> AotModule { tcx.sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections), ); - let module = UnwindModule::new(ObjectModule::new(builder), true); + let module = UnwindModule::new(ObjectModule::new(builder), tcx, true); let producer = crate::debuginfo::producer(tcx.sess); let global_asm_config = GlobalAsmConfig::new(tcx.sess); diff --git a/compiler/rustc_codegen_cranelift/src/unwind_module.rs b/compiler/rustc_codegen_cranelift/src/unwind_module.rs index b4eb939cf2560..b294122d1a964 100644 --- a/compiler/rustc_codegen_cranelift/src/unwind_module.rs +++ b/compiler/rustc_codegen_cranelift/src/unwind_module.rs @@ -7,6 +7,7 @@ use cranelift_module::{ ModuleReloc, ModuleResult, }; use cranelift_object::{ObjectModule, ObjectProduct}; +use rustc_middle::ty::TyCtxt; use crate::UnwindContext; @@ -17,8 +18,8 @@ pub(crate) struct UnwindModule { } impl UnwindModule { - pub(crate) fn new(mut module: T, pic_eh_frame: bool) -> Self { - let unwind_context = UnwindContext::new(&mut module, pic_eh_frame); + pub(crate) fn new(mut module: T, tcx: TyCtxt<'_>, pic_eh_frame: bool) -> Self { + let unwind_context = UnwindContext::new(&mut module, tcx, pic_eh_frame); UnwindModule { module, unwind_context } } } diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 8045e8ae9d28f..bcbec130ae012 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -466,10 +466,12 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.declare_fn(symbol_name, fn_abi) } _ => { + let rust_name; let name = if wants_msvc_seh(self.sess()) { "__CxxFrameHandler3" } else { - "rust_eh_personality" + rust_name = rustc_symbol_mangling::eh_personality_symbol(tcx); + &rust_name }; self.declare_func(name, self.type_i32(), &[], true) } diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs index 4174eebcf7b02..376890f0ccfd0 100644 --- a/compiler/rustc_codegen_gcc/src/declare.rs +++ b/compiler/rustc_codegen_gcc/src/declare.rs @@ -179,7 +179,7 @@ fn declare_raw_fn<'gcc>( cx.functions.borrow_mut().insert(name.to_string(), func); #[cfg(feature = "master")] - if name == "rust_eh_personality" { + if name.ends_with("rust_eh_personality") { // NOTE: GCC will sometimes change the personality function set on a function from // rust_eh_personality to __gcc_personality_v0 as an optimization. // As such, we need to create a weak alias from __gcc_personality_v0 to diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index cbc7db8e9e23f..4caedbad934f1 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -248,8 +248,6 @@ impl CodegenBackend for GccCodegenBackend { { let lto_supported = gccjit::is_lto_supported(); self.lto_supported.store(lto_supported, Ordering::SeqCst); - - gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); } #[cfg(not(feature = "master"))] @@ -290,6 +288,8 @@ impl CodegenBackend for GccCodegenBackend { } fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { + #[cfg(feature = "master")] + self.set_personality_function(tcx); Box::new(codegen_crate(self.clone(), tcx)) } @@ -316,6 +316,17 @@ impl CodegenBackend for GccCodegenBackend { } } +impl GccCodegenBackend { + #[cfg(feature = "master")] + fn set_personality_function(&self, tcx: TyCtxt<'_>) { + let personality_symbol = + CString::new(rustc_symbol_mangling::eh_personality_symbol(tcx)).unwrap(); + // FIXME: Change gccjit to store an owned string internally (https://github.com/rust-lang/rust/pull/148413#discussion_r2749777937) + let personality_symbol = Box::leak(personality_symbol.into_boxed_c_str()); + gccjit::set_global_personality_function_name(personality_symbol.to_bytes_with_nul()); + } +} + fn new_context<'gcc, 'tcx>(tcx: TyCtxt<'tcx>) -> Context<'gcc> { let context = Context::default(); if matches!(tcx.sess.target.arch, Arch::X86 | Arch::X86_64) { diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 4883eb1087be3..e1f605904def2 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -82,7 +82,7 @@ fn prepare_lto( symbols_below_threshold.push(c"__llvm_profile_counter_bias".to_owned()); // LTO seems to discard this otherwise under certain circumstances. - symbols_below_threshold.push(c"rust_eh_personality".to_owned()); + symbols_below_threshold.push(CString::new(cgcx.rust_eh_personality_symbol.clone()).unwrap()); // If we're performing LTO for the entire crate graph, then for each of our // upstream dependencies, find the corresponding rlib and load the bitcode diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 668072ff082ec..6b98913f25ccd 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -991,7 +991,14 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { tcx.sess.pointer_authentication_functions(), ), _ => { - let name = name.unwrap_or("rust_eh_personality"); + let mangled_symbol; + let name = match name { + Some(name) => name, + None => { + mangled_symbol = rustc_symbol_mangling::eh_personality_symbol(tcx); + mangled_symbol.as_str() + } + }; if let Some(llfn) = self.get_declared_value(name) { llfn } else { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 552a91ffee071..f228723967ddf 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -321,6 +321,11 @@ impl CodegenBackend for LlvmCodegenBackend { llvm_util::target_has_mnemonic(sess, mnemonic) } + fn can_mangle_eh_personality(&self) -> bool { + // https://github.com/llvm/llvm-project/pull/166095 + llvm_util::get_version() > (22, 0, 0) + } + fn target_config(&self, sess: &Session) -> TargetConfig { target_config(sess) } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 2eaceb68a67a2..1b12907a5db89 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -348,6 +348,7 @@ pub struct CodegenContext { pub split_debuginfo: rustc_target::spec::SplitDebuginfo, pub split_dwarf_kind: rustc_session::config::SplitDwarfKind, pub pointer_size: Size, + pub rust_eh_personality_symbol: String, /// LLVM optimizations for which we want to print remarks. pub remark: Passes, @@ -1316,6 +1317,7 @@ fn start_executing_work( target_is_like_darwin: tcx.sess.target.is_like_darwin, target_is_like_aix: tcx.sess.target.is_like_aix, target_is_like_gpu: tcx.sess.target.is_like_gpu, + rust_eh_personality_symbol: rustc_symbol_mangling::eh_personality_symbol(tcx), split_debuginfo: tcx.sess.split_debuginfo(), split_dwarf_kind: tcx.sess.opts.unstable_opts.split_dwarf_kind, parallel, diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 36f4d858d0be5..5970d23de64b1 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -103,6 +103,12 @@ pub trait CodegenBackend { false } + /// Whether the `rust_eh_personality` symbol can be mangled (this is false if the codegen + /// backend hardcodes the name for certain checks). + fn can_mangle_eh_personality(&self) -> bool { + true + } + /// The metadata loader used to load rlib and dylib metadata. /// /// Alternative codegen backends may want to use different rlib or dylib formats than the diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 2737d2ca854a5..2f07917936e86 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -441,6 +441,8 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se sess.replaced_intrinsics = FxHashSet::from_iter(codegen_backend.replaced_intrinsics()); sess.fallback_intrinsics = FxHashSet::from_iter(codegen_backend.fallback_intrinsics()); sess.thin_lto_supported = codegen_backend.thin_lto_supported(); + sess.codegen_backend_supports_eh_personality_mangling = + codegen_backend.can_mangle_eh_personality(); let cfg = parse_cfg(sess.dcx(), config.crate_cfg); let mut cfg = config::build_configuration(&sess, cfg); diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 7db30b38f9be4..a4798575fdaea 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -369,6 +369,10 @@ pub struct Session { /// drown everything else in noise. miri_unleashed_features: Lock)>>, + /// Whether the codegen backend supports mangling of the personality. + /// See `CodegenBackend::can_mangle_eh_personality`. + pub codegen_backend_supports_eh_personality_mangling: bool, + /// Architecture to use for interpreting asm!. pub asm_arch: Option, @@ -1376,6 +1380,7 @@ pub fn build_session( driver_lint_caps, ctfe_backtrace, miri_unleashed_features: Lock::new(Default::default()), + codegen_backend_supports_eh_personality_mangling: false, // filled by `run_compiler` asm_arch, internal_target_features: Default::default(), cfg_version, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 93db093f630bd..9c465b409ca85 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -104,7 +104,7 @@ mod v0; pub mod test; -pub use v0::{mangle_cgu, mangle_internal_symbol}; +pub use v0::{eh_personality_symbol, mangle_cgu, mangle_internal_symbol}; /// Offload kernels need custom v0 symbol treatment because the host /// and device compilation passes run with different `stable_crate_id`s diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 9c80743694ab6..e047872e3d5da 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -127,10 +127,15 @@ pub fn mangle_cgu<'tcx>(tcx: TyCtxt<'tcx>, krate: CrateNum, cgu_name: Either(tcx: TyCtxt<'tcx>) -> String { + mangle_internal_symbol(tcx, "rust_eh_personality") +} + pub fn mangle_internal_symbol<'tcx>(tcx: TyCtxt<'tcx>, item_name: &str) -> String { match item_name { - // rust_eh_personality must not be renamed as LLVM hard-codes the name - "rust_eh_personality" => return item_name.to_owned(), + "rust_eh_personality" if !tcx.sess.codegen_backend_supports_eh_personality_mangling => { + return item_name.to_owned(); + } // Apple availability symbols need to not be mangled to be usable by // C/Objective-C code. "__isPlatformVersionAtLeast" | "__isOSVersionAtLeast" => return item_name.to_owned(), diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs index e1aaa2a03880f..6694a6568fdc1 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -227,6 +227,10 @@ impl TestCx<'_> { cmd.env("LLVM_BIN_DIR", llvm_bin_dir); } + if let Some(ref llvm_version) = self.config.llvm_version { + cmd.env("LLVM_VERSION", llvm_version.to_string()); + } + if let Some(ref remote_test_client) = self.config.remote_test_client { cmd.env("REMOTE_TEST_CLIENT", remote_test_client); } diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs index 70bed5a471ab2..29752c0e7653c 100644 --- a/src/tools/run-make-support/src/external_deps/llvm.rs +++ b/src/tools/run-make-support/src/external_deps/llvm.rs @@ -3,6 +3,19 @@ use std::path::{Path, PathBuf}; use crate::command::Command; use crate::env::env_var; +pub fn llvm_version() -> (u32, u32, u32) { + let version_string = env_var("LLVM_VERSION"); + let mut parts = version_string.split("."); + let mut part = || { + parts + .next() + .expect(&format!("invalid LLVM version: {version_string}")) + .parse::() + .expect(&format!("invalid LLVM version: {version_string}")) + }; + (part(), part(), part()) +} + /// Construct a new `llvm-readobj` invocation with the `GNU` output style. /// This assumes that `llvm-readobj` is available at `$LLVM_BIN_DIR/llvm-readobj`. #[track_caller] diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index d3c2115e745e0..329b447ce2d88 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -76,7 +76,7 @@ pub use crate::external_deps::llvm::{ self, LlvmAr, LlvmBcanalyzer, LlvmDis, LlvmDwarfdump, LlvmFilecheck, LlvmNm, LlvmObjcopy, LlvmObjdump, LlvmProfdata, LlvmReadobj, llvm_ar, llvm_as, llvm_bcanalyzer, llvm_dis, llvm_dwarfdump, llvm_filecheck, llvm_nm, llvm_objcopy, llvm_objdump, llvm_profdata, - llvm_readobj, + llvm_readobj, llvm_version, }; pub use crate::external_deps::python::python_command; pub use crate::external_deps::rustc::{self, Rustc, bare_rustc, rustc, rustc_minicore, rustc_path}; diff --git a/tests/codegen-llvm/gdb_debug_script_load.rs b/tests/codegen-llvm/gdb_debug_script_load.rs index 3e92eba10b121..044d8577df6a9 100644 --- a/tests/codegen-llvm/gdb_debug_script_load.rs +++ b/tests/codegen-llvm/gdb_debug_script_load.rs @@ -14,7 +14,7 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { loop {} } -#[no_mangle] +#[lang = "eh_personality"] extern "C" fn rust_eh_personality() { loop {} } diff --git a/tests/run-make/no-alloc-shim/foo.rs b/tests/run-make/no-alloc-shim/foo.rs index a22307f41b39e..247b73f47c9c6 100644 --- a/tests/run-make/no-alloc-shim/foo.rs +++ b/tests/run-make/no-alloc-shim/foo.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs)] +#![feature(rustc_attrs, lang_items)] #![no_std] #![no_main] @@ -11,7 +11,7 @@ fn panic_handler(_: &core::panic::PanicInfo) -> ! { loop {} } -#[no_mangle] +#[lang = "eh_personality"] extern "C" fn rust_eh_personality( _version: i32, _actions: i32, diff --git a/tests/run-make/repr128-dwarf/rmake.rs b/tests/run-make/repr128-dwarf/rmake.rs index 6b381f1f10bf4..29003b989fa1e 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -10,7 +10,7 @@ use std::rc::Rc; use gimli::read::DebuggingInformationEntry; use gimli::{AttributeValue, EndianRcSlice, Reader, RunTimeEndian}; use object::{Object, ObjectSection}; -use run_make_support::{gimli, object, rfs, rustc}; +use run_make_support::{gimli, llvm_version, object, rfs, rustc}; fn main() { let output = PathBuf::from("repr128"); diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs index 2cf579758002a..4bfee6a136297 100644 --- a/tests/run-make/symbols-all-mangled/rmake.rs +++ b/tests/run-make/symbols-all-mangled/rmake.rs @@ -4,7 +4,9 @@ //@ ignore-cross-compile (host-only) use run_make_support::object::read::{Object, ObjectSymbol}; -use run_make_support::{bin_name, dynamic_lib_name, object, rfs, rustc, static_lib_name}; +use run_make_support::{ + bin_name, dynamic_lib_name, llvm_version, object, rfs, rustc, static_lib_name, +}; fn main() { let staticlib_name = static_lib_name("a_lib"); @@ -19,13 +21,35 @@ fn main() { symbols_check(&exe_name); } +fn is_symbol_ok(sym: &str) -> bool { + let sym = strip_underscore_if_apple(sym); + // There are debuginfo helper symbols that get prefixed with DW.ref. + let sym = sym.strip_prefix("DW.ref.").unwrap_or(sym); + + if sym.starts_with("_ZN") || sym.starts_with("_R") { + return true; // Correctly mangled + } + + if sym.contains(".llvm.") { + // Starting in LLVM 21 we get various implementation-detail functions which + // contain .llvm. that are not a problem. + return true; + } + + if llvm_version() < (22, 0, 0) && sym.contains("rust_eh_personality") { + return true; // LLVM before 22 doesn't allow us to mangle this symbol + } + + false +} + fn symbols_check_archive(path: &str) { let binary_data = rfs::read(path); let file = object::read::archive::ArchiveFile::parse(&*binary_data).unwrap(); for symbol in file.symbols().unwrap().unwrap() { let symbol = symbol.unwrap(); - let name = strip_underscore_if_apple(std::str::from_utf8(symbol.name()).unwrap()); - if name.starts_with("_ZN") || name.starts_with("_R") { + let name = std::str::from_utf8(symbol.name()).unwrap(); + if is_symbol_ok(name) { continue; // Correctly mangled } @@ -35,16 +59,6 @@ fn symbols_check_archive(path: &str) { continue; // All compiler-builtins symbols must remain unmangled } - if name.contains("rust_eh_personality") { - continue; // Unfortunately LLVM doesn't allow us to mangle this symbol - } - - if name.contains(".llvm.") { - // Starting in LLVM 21 we get various implementation-detail functions which - // contain .llvm. that are not a problem. - continue; - } - panic!("Unmangled symbol found in {path}: {name}"); } } @@ -59,8 +73,8 @@ fn symbols_check(path: &str) { if symbol.is_weak() { continue; // Likely an intrinsic from compiler-builtins } - let name = strip_underscore_if_apple(symbol.name().unwrap()); - if name.starts_with("_ZN") || name.starts_with("_R") { + let name = symbol.name().unwrap(); + if is_symbol_ok(name) { continue; // Correctly mangled } @@ -71,16 +85,6 @@ fn symbols_check(path: &str) { continue; } - if name.contains("rust_eh_personality") { - continue; // Unfortunately LLVM doesn't allow us to mangle this symbol - } - - if name.contains(".llvm.") { - // Starting in LLVM 21 we get various implementation-detail functions which - // contain .llvm. that are not a problem. - continue; - } - panic!("Unmangled symbol found in {path}: {name}"); } } diff --git a/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs b/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs index 62d352facd178..52256cd834da7 100644 --- a/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs +++ b/tests/ui/linkage-attr/raw-dylib/elf/glibc-x86_64.rs @@ -6,7 +6,7 @@ //@ ignore-backends: gcc #![allow(incomplete_features)] -#![feature(raw_dylib_elf)] +#![feature(raw_dylib_elf, lang_items)] #![no_std] #![no_main] @@ -69,7 +69,7 @@ fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { exit(1); } -#[unsafe(no_mangle)] +#[lang = "eh_personality"] extern "C" fn rust_eh_personality( _version: i32, _actions: i32, From 4b76288461a781b488498a7a2b7d7616533216e4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 9 Jul 2026 17:31:57 +0200 Subject: [PATCH 2/3] Fix LLVM version test The PR in question was already included in LLVM 22. --- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index f228723967ddf..0776a24bc2417 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -323,7 +323,7 @@ impl CodegenBackend for LlvmCodegenBackend { fn can_mangle_eh_personality(&self) -> bool { // https://github.com/llvm/llvm-project/pull/166095 - llvm_util::get_version() > (22, 0, 0) + llvm_util::get_version() >= (22, 0, 0) } fn target_config(&self, sess: &Session) -> TargetConfig { From d487f44c43c4753b1bfddabd19c5c38db8423f87 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Jul 2026 15:15:26 +0200 Subject: [PATCH 3/3] Move cg_clif eh_personality_symbol call --- compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs | 6 +++--- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 6 +++++- compiler/rustc_codegen_cranelift/src/driver/jit.rs | 6 +++++- compiler/rustc_codegen_cranelift/src/unwind_module.rs | 5 ++--- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index 094fd0f0d1abe..9599664f9a4ac 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs @@ -25,7 +25,7 @@ pub(crate) struct UnwindContext { } impl UnwindContext { - pub(crate) fn new(module: &mut dyn Module, tcx: TyCtxt<'_>, pic_eh_frame: bool) -> Self { + pub(crate) fn new(module: &mut dyn Module, eh_personality: &str, pic_eh_frame: bool) -> Self { let endian = match module.isa().endianness() { Endianness::Little => RunTimeEndian::Little, Endianness::Big => RunTimeEndian::Big, @@ -70,7 +70,7 @@ impl UnwindContext { // FIXME use eh_personality lang item instead let personality = module .declare_function( - &rustc_symbol_mangling::eh_personality_symbol(tcx), + eh_personality, Linkage::Import, &Signature { params: vec![ @@ -89,7 +89,7 @@ impl UnwindContext { // Use indirection here to support PIC the case where rust_eh_personality is defined in // another DSO. let personality_ref = module - .declare_data("DW.ref.rust_eh_personality", Linkage::Local, false, false) + .declare_data(&format!("DW.ref.{eh_personality}"), Linkage::Local, false, false) .unwrap(); let mut personality_ref_data = DataDescription::new(); diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index f21d0df8461f6..1512e063f85da 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -62,7 +62,11 @@ fn make_module(tcx: TyCtxt<'_>, cgu_name: &str) -> AotModule { tcx.sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections), ); - let module = UnwindModule::new(ObjectModule::new(builder), tcx, true); + let module = UnwindModule::new( + ObjectModule::new(builder), + &rustc_symbol_mangling::eh_personality_symbol(tcx), + true, + ); let producer = crate::debuginfo::producer(tcx.sess); let global_asm_config = GlobalAsmConfig::new(tcx.sess); diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 32f60615844bc..22f1186930924 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -25,7 +25,11 @@ fn create_jit_module( let mut jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names()); crate::compiler_builtins::register_functions_for_jit(&mut jit_builder); jit_builder.symbol_lookup_fn(dep_symbol_lookup_fn(tcx.sess, crate_info.clone())); - let mut jit_module = UnwindModule::new(JITModule::new(jit_builder), false); + let mut jit_module = UnwindModule::new( + JITModule::new(jit_builder), + &rustc_symbol_mangling::eh_personality_symbol(tcx), + false, + ); let cx = DebugContext::new(tcx, jit_module.isa(), false, "dummy_cgu_name"); diff --git a/compiler/rustc_codegen_cranelift/src/unwind_module.rs b/compiler/rustc_codegen_cranelift/src/unwind_module.rs index b294122d1a964..d79960f418128 100644 --- a/compiler/rustc_codegen_cranelift/src/unwind_module.rs +++ b/compiler/rustc_codegen_cranelift/src/unwind_module.rs @@ -7,7 +7,6 @@ use cranelift_module::{ ModuleReloc, ModuleResult, }; use cranelift_object::{ObjectModule, ObjectProduct}; -use rustc_middle::ty::TyCtxt; use crate::UnwindContext; @@ -18,8 +17,8 @@ pub(crate) struct UnwindModule { } impl UnwindModule { - pub(crate) fn new(mut module: T, tcx: TyCtxt<'_>, pic_eh_frame: bool) -> Self { - let unwind_context = UnwindContext::new(&mut module, tcx, pic_eh_frame); + pub(crate) fn new(mut module: T, eh_personality: &str, pic_eh_frame: bool) -> Self { + let unwind_context = UnwindContext::new(&mut module, eh_personality, pic_eh_frame); UnwindModule { module, unwind_context } } }