Skip to content

Commit 10169de

Browse files
committed
make naked functions always have external linkage *in LLVM*. If we do it earlier, then some other logic causes invalid visibility for the item (exporting when it shouldn't).
1 parent 15e0d8b commit 10169de

File tree

3 files changed

+16
-17
lines changed

3 files changed

+16
-17
lines changed

compiler/rustc_codegen_llvm/src/attributes.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -402,13 +402,9 @@ pub fn from_fn_attrs<'ll, 'tcx>(
402402
to_add.push(MemoryEffects::None.create_attr(cx.llcx));
403403
}
404404
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
405-
to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
406-
// HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions.
407-
// And it is a module-level attribute, so the alternative is pulling naked functions into new LLVM modules.
408-
// Otherwise LLVM's "naked" functions come with endbr prefixes per https://github.com/rust-lang/rust/issues/98768
409-
to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx));
410-
// Need this for AArch64.
411-
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
405+
// do nothing; a naked function is converted into an extern function
406+
// and a global assembly block. LLVM's support for naked functions is
407+
// not used.
412408
}
413409
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
414410
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)

compiler/rustc_codegen_llvm/src/mono_item.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_codegen_ssa::traits::*;
88
use rustc_hir::def::DefKind;
99
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1010
use rustc_middle::bug;
11+
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
1112
use rustc_middle::mir::mono::{Linkage, Visibility};
1213
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
1314
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
@@ -62,8 +63,15 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
6263

6364
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
6465
let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
65-
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
6666
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
67+
let llvm_linkage =
68+
if attrs.flags.contains(CodegenFnAttrFlags::NAKED) && linkage == Linkage::Internal {
69+
// this is effectively an extern fn, and must have external linkage
70+
llvm::Linkage::ExternalLinkage
71+
} else {
72+
base::linkage_to_llvm(linkage)
73+
};
74+
unsafe { llvm::LLVMRustSetLinkage(lldecl, llvm_linkage) };
6775
base::set_link_section(lldecl, attrs);
6876
if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR {
6977
llvm::SetUniqueComdat(self.llmod, lldecl);

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

+4-9
Original file line numberDiff line numberDiff line change
@@ -109,14 +109,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
109109
sym::rustc_allocator_zeroed => {
110110
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
111111
}
112-
sym::naked => {
113-
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
114-
115-
// naked functions are generated as an extern function, and a global asm block that
116-
// contains the naked function's body. In order to link these together, the linkage
117-
// of the extern function must be external.
118-
codegen_fn_attrs.linkage = Some(Linkage::External);
119-
}
112+
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
120113
sym::no_mangle => {
121114
if tcx.opt_item_name(did.to_def_id()).is_some() {
122115
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE
@@ -563,7 +556,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
563556
}
564557
});
565558

566-
// naked function MUST NOT be inlined!
559+
// naked function MUST NOT be inlined! This attribute is required for the rust compiler itself,
560+
// but not for the code generation backend because at that point the naked function will just be
561+
// a declaration, with a definition provided in global assembly.
567562
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
568563
codegen_fn_attrs.inline = InlineAttr::Never;
569564
}

0 commit comments

Comments
 (0)