Auto merge of #148339 - folkertdev:naked-macos-private-extern, r=Amanieu

naked functions: emit `.private_extern` on macos

fixes https://github.com/rust-lang/rust/issues/148307

Emit `.private_extern` on macos when the naked function uses `Linkage::Internal`. Failing to do so can cause issues with LTO.

The documentation on this directive is kind of sparse, but I believe this is at least not incorrect, and does fix the issue.

r? @Amanieu
cc @bjorn3
This commit is contained in:
rust-bors[bot] 2026-01-07 20:38:46 +00:00 committed by GitHub
commit fecb335cba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 54 additions and 2 deletions

View file

@ -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 => {

View file

@ -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;

View file

@ -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.

View file

@ -0,0 +1,41 @@
//@ revisions: macos-x86 macos-aarch64 linux-x86
//@ add-minicore
//@ 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()
}