diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index e7239ebfecf63..dd41cd39bf9f2 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -181,7 +181,8 @@ fn prefix_and_suffix<'tcx>( } } Linkage::Internal => { - // write nothing + // LTO can fail when internal linkage is used. + emit_fatal("naked functions may not have internal linkage") } Linkage::Common => emit_fatal("Functions may not have common linkage"), Linkage::AvailableExternally => { diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index b87ab840a32d5..f7769454ef85d 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -580,6 +580,16 @@ fn internalize_symbols<'tcx>( } } + // When LTO inlines the caller of a naked function, it will attempt but fail to make the + // naked function symbol visible. To ensure that LTO works correctly, do not default + // naked functions to internal linkage and default visibility. + if let MonoItem::Fn(instance) = item { + let flags = cx.tcx.codegen_instance_attrs(instance.def).flags; + if flags.contains(CodegenFnAttrFlags::NAKED) { + continue; + } + } + // If we got here, we did not find any uses from other CGUs, so // it's fine to make this monomorphization internal. data.linkage = Linkage::Internal; diff --git a/tests/assembly-llvm/naked-functions/aix.rs b/tests/assembly-llvm/naked-functions/aix.rs index 57ff0e183bed5..61d3d3b640eeb 100644 --- a/tests/assembly-llvm/naked-functions/aix.rs +++ b/tests/assembly-llvm/naked-functions/aix.rs @@ -9,7 +9,7 @@ //@[aix] needs-llvm-components: powerpc #![crate_type = "lib"] -#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)] +#![feature(no_core, asm_experimental_arch)] #![no_core] // tests that naked functions work for the `powerpc64-ibm-aix` target. diff --git a/tests/assembly-llvm/naked-functions/hidden.rs b/tests/assembly-llvm/naked-functions/hidden.rs new file mode 100644 index 0000000000000..467e4d1dfe4b7 --- /dev/null +++ b/tests/assembly-llvm/naked-functions/hidden.rs @@ -0,0 +1,41 @@ +//@ revisions: macos-x86 macos-aarch64 linux-x86 +//@ add-core-stubs +//@ assembly-output: emit-asm +// +//@[macos-aarch64] compile-flags: --target aarch64-apple-darwin +//@[macos-aarch64] needs-llvm-components: aarch64 +// +//@[macos-x86] compile-flags: --target x86_64-apple-darwin +//@[macos-x86] needs-llvm-components: x86 +// +//@[linux-x86] compile-flags: --target x86_64-unknown-linux-gnu +//@[linux-x86] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +// Tests that naked functions that are not externally linked (e.g. via `no_mangle`) +// are marked as `Visibility::Hidden` and emit `.private_extern` or `.hidden`. +// +// Without this directive, LTO may fail because the symbol is not visible. +// See also https://github.com/rust-lang/rust/issues/148307. + +extern crate minicore; +use minicore::*; + +// CHECK: .p2align 2 +// macos-x86,macos-aarch64: .private_extern +// linux-x86: .globl +// linux-x86: .hidden +// CHECK: ret +#[unsafe(naked)] +extern "C" fn ret() { + naked_asm!("ret") +} + +// CHECK-LABEL: entry +#[no_mangle] +pub fn entry() { + ret() +}