From 96a3af6cddab8182c9cdbf54aa71bdf3ac5b3605 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 | 3 ++ 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, 114 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs index ad0a15bf7f6e5..371d7d7b01be2 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 cd82df386f5ce..af067bea0d473 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 38e0e5f329f76..98a31f556478d 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -465,10 +465,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().target) { "__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 d7a3ef3b4a6c5..9e4a0788b673c 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -226,8 +226,6 @@ impl CodegenBackend for GccCodegenBackend { target_info: Arc::new(IntoDynSyncSend(context.get_target_info())), lto_supported: gccjit::is_lto_supported(), }); - - gccjit::set_global_personality_function_name(b"rust_eh_personality\0"); } #[cfg(not(feature = "master"))] @@ -263,6 +261,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)) } @@ -285,6 +285,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 cb12c103834af..7ad23152ce8c9 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 3cfea4b80eb2b..26ec6a7c4cef2 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -1039,7 +1039,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 3b02910ff9c85..3d79c40925c02 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -369,6 +369,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: &EarlySession) -> 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 c93aa87b25077..61ff0d2c21591 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -345,6 +345,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, @@ -1308,6 +1309,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 38d562d028f34..ef06d0f914cec 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -89,6 +89,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 006a320f11637..c9d6d25403a70 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -470,6 +470,9 @@ pub fn run_compiler(config: Config, f: impl FnOnce(&Compiler) -> R + Se sess.check_config = parse_check_cfg(&sess, config.crate_check_cfg); + sess.codegen_backend_supports_eh_personality_mangling = + codegen_backend.can_mangle_eh_personality(); + if let Some(psess_created) = config.psess_created { psess_created(&mut sess.psess); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 274cfe8d7eb8a..95790409c21e6 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -491,6 +491,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, @@ -1497,6 +1501,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(), global_backend_features, 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 e0d9d6976bd14..ccf3e2749a4a4 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -126,10 +126,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 9c1485bbf5665..31f59e374053b 100644 --- a/src/tools/compiletest/src/runtest/run_make.rs +++ b/src/tools/compiletest/src/runtest/run_make.rs @@ -240,6 +240,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 7a8de3b54521e..0cc1cccde7ab9 100644 --- a/tests/run-make/repr128-dwarf/rmake.rs +++ b/tests/run-make/repr128-dwarf/rmake.rs @@ -13,7 +13,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 edc7dc60b0368dc6ddaccb34bb37d4492d3360aa 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 3d79c40925c02..9d2252d9547b1 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -371,7 +371,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: &EarlySession) -> TargetConfig { From 33e2e9302779215dcbac92c6379e9f25f7279948 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 371d7d7b01be2..18eb85289e520 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 af067bea0d473..5aa2e451bcb98 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 8bf1cd9bf85bc..9864cefbf9368 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 } } }