Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion compiler/rustc_codegen_ssa/src/mir/naked_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Comment on lines -184 to +185
Copy link
Contributor Author

@folkertdev folkertdev Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this too strict? We could allow it, but I think this is only reachable now with an explicit linkage attribute (which is unstable).

}
Linkage::Common => emit_fatal("Functions may not have common linkage"),
Linkage::AvailableExternally => {
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_monomorphize/src/partitioning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion tests/assembly-llvm/naked-functions/aix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
41 changes: 41 additions & 0 deletions tests/assembly-llvm/naked-functions/hidden.rs
Original file line number Diff line number Diff line change
@@ -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()
}
Loading