Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove branch target prologues from #[naked] fn #98998

Merged
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
6 changes: 6 additions & 0 deletions compiler/rustc_codegen_llvm/src/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,12 @@ pub fn from_fn_attrs<'ll, 'tcx>(
}
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"));
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) {
// apply to return place instead of function (unlike all other attributes applied in this function)
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@ pub enum AttributeKind {
StackProtect = 32,
NoUndef = 33,
SanitizeMemTag = 34,
NoCfCheck = 35,
}

/// LLVMIntPredicate
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ enum LLVMRustAttribute {
StackProtect = 32,
NoUndef = 33,
SanitizeMemTag = 34,
NoCfCheck = 35,
};

typedef struct OpaqueRustString *RustStringRef;
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ static Attribute::AttrKind fromRust(LLVMRustAttribute Kind) {
return Attribute::NoAlias;
case NoCapture:
return Attribute::NoCapture;
case NoCfCheck:
return Attribute::NoCfCheck;
case NoInline:
return Attribute::NoInline;
case NonNull:
Expand Down
21 changes: 21 additions & 0 deletions src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti
// assembly-output: emit-asm
// needs-asm-support
// only-aarch64

#![crate_type = "lib"]
#![feature(naked_functions)]
use std::arch::asm;

// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
// meaning "no prologue whatsoever, no, really, not one instruction."
// Unfortunately, aarch64's "branch target identification" works via hints at landing sites.
// LLVM implements this via making sure of that, even for functions with the naked attribute.
// So, we must emit an appropriate instruction instead!
#[no_mangle]
#[naked]
pub unsafe extern "C" fn _hlt() -> ! {
// CHECK-NOT: hint #34
// CHECK: hlt #0x1
asm!("hlt #1", options(noreturn))
}
24 changes: 24 additions & 0 deletions src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// compile-flags: -C no-prepopulate-passes -Zcf-protection=full
// assembly-output: emit-asm
// needs-asm-support
// only-x86_64

#![crate_type = "lib"]
#![feature(naked_functions)]
use std::arch::asm;

// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
// meaning "no prologue whatsoever, no, really, not one instruction."
// Unfortunately, x86's control-flow enforcement, specifically indirect branch protection,
// works by using an instruction for each possible landing site,
// and LLVM implements this via making sure of that.
#[no_mangle]
#[naked]
pub unsafe extern "sysv64" fn will_halt() -> ! {
// CHECK-NOT: endbr{{32|64}}
// CHECK: hlt
asm!("hlt", options(noreturn))
}

// what about aarch64?
// "branch-protection"=false
2 changes: 1 addition & 1 deletion src/test/codegen/naked-noinline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ pub unsafe fn g() {
f();
}

// CHECK: attributes [[ATTR]] = { naked noinline{{.*}} }
// CHECK: attributes [[ATTR]] = { naked{{.*}}noinline{{.*}} }