Skip to content

Commit

Permalink
make naked functions always have external linkage *in LLVM*. If we do…
Browse files Browse the repository at this point in the history
… it earlier, then some other logic causes invalid visibility for the item (exporting when it shouldn't).
  • Loading branch information
folkertdev committed Jul 26, 2024
1 parent 15e0d8b commit 10169de
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 17 deletions.
10 changes: 3 additions & 7 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,13 +402,9 @@ pub fn from_fn_attrs<'ll, 'tcx>(
to_add.push(MemoryEffects::None.create_attr(cx.llcx));
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
// HACK(jubilee): "indirect branch tracking" works by attaching prologues to functions.
// And it is a module-level attribute, so the alternative is pulling naked functions into new LLVM modules.
// Otherwise LLVM's "naked" functions come with endbr prefixes per https://github.com/rust-lang/rust/issues/98768
to_add.push(AttributeKind::NoCfCheck.create_attr(cx.llcx));
// Need this for AArch64.
to_add.push(llvm::CreateAttrStringValue(cx.llcx, "branch-target-enforcement", "false"));
// do nothing; a naked function is converted into an extern function
// and a global assembly block. LLVM's support for naked functions is
// not used.
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR)
|| codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR_ZEROED)
Expand Down
10 changes: 9 additions & 1 deletion compiler/rustc_codegen_llvm/src/mono_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use rustc_codegen_ssa::traits::*;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::bug;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::mono::{Linkage, Visibility};
use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
use rustc_middle::ty::{self, Instance, TypeVisitableExt};
Expand Down Expand Up @@ -62,8 +63,15 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {

let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
let llvm_linkage =
if attrs.flags.contains(CodegenFnAttrFlags::NAKED) && linkage == Linkage::Internal {
// this is effectively an extern fn, and must have external linkage
llvm::Linkage::ExternalLinkage
} else {
base::linkage_to_llvm(linkage)
};
unsafe { llvm::LLVMRustSetLinkage(lldecl, llvm_linkage) };
base::set_link_section(lldecl, attrs);
if linkage == Linkage::LinkOnceODR || linkage == Linkage::WeakODR {
llvm::SetUniqueComdat(self.llmod, lldecl);
Expand Down
13 changes: 4 additions & 9 deletions compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
sym::rustc_allocator_zeroed => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR_ZEROED
}
sym::naked => {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;

// naked functions are generated as an extern function, and a global asm block that
// contains the naked function's body. In order to link these together, the linkage
// of the extern function must be external.
codegen_fn_attrs.linkage = Some(Linkage::External);
}
sym::naked => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
sym::no_mangle => {
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE
Expand Down Expand Up @@ -563,7 +556,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
});

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

0 comments on commit 10169de

Please sign in to comment.