https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/156170
>From 51081359fa4a76c9d20489084ce2a399b5bfc520 Mon Sep 17 00:00:00 2001 From: Shashi Shankar <shashishankar1...@gmail.com> Date: Sat, 30 Aug 2025 11:56:03 +0200 Subject: [PATCH 1/2] [AArch64][BTI] Add BTI at EH entries. (#155308) Mark EH landing pads as indirect-branch targets (BTI j) and treat WinEH funclet entries as call-like (BTI c). Add lit tests for ELF and COFF. Tests: Adds lit tests: bti-ehpad.ll and wineh-bti-funclet.ll. Fixes: #149267 Signed-off-by: Shashi Shankar <shashishankar1...@gmail.com> (cherry picked from commit 1b37b9e6d788d7058381b68b5ab265bcb6181335) --- .../Target/AArch64/AArch64BranchTargets.cpp | 46 ++++++++--- llvm/test/CodeGen/AArch64/bti-ehpad.ll | 44 +++++++++++ .../AArch64/sign-return-address-pauth-lr.ll | 16 ++-- .../test/CodeGen/AArch64/wineh-bti-funclet.ll | 79 +++++++++++++++++++ llvm/test/CodeGen/AArch64/wineh-bti.ll | 2 +- 5 files changed, 167 insertions(+), 20 deletions(-) create mode 100644 llvm/test/CodeGen/AArch64/bti-ehpad.ll create mode 100644 llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll diff --git a/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp b/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp index 3436dc9ef4521..137ff898e86a3 100644 --- a/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp +++ b/llvm/lib/Target/AArch64/AArch64BranchTargets.cpp @@ -30,6 +30,14 @@ using namespace llvm; #define AARCH64_BRANCH_TARGETS_NAME "AArch64 Branch Targets" namespace { +// BTI HINT encoding: base (32) plus 'c' (2) and/or 'j' (4). +enum : unsigned { + BTIBase = 32, // Base immediate for BTI HINT + BTIC = 1u << 1, // 2 + BTIJ = 1u << 2, // 4 + BTIMask = BTIC | BTIJ, +}; + class AArch64BranchTargets : public MachineFunctionPass { public: static char ID; @@ -42,6 +50,7 @@ class AArch64BranchTargets : public MachineFunctionPass { void addBTI(MachineBasicBlock &MBB, bool CouldCall, bool CouldJump, bool NeedsWinCFI); }; + } // end anonymous namespace char AArch64BranchTargets::ID = 0; @@ -62,9 +71,8 @@ bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) { if (!MF.getInfo<AArch64FunctionInfo>()->branchTargetEnforcement()) return false; - LLVM_DEBUG( - dbgs() << "********** AArch64 Branch Targets **********\n" - << "********** Function: " << MF.getName() << '\n'); + LLVM_DEBUG(dbgs() << "********** AArch64 Branch Targets **********\n" + << "********** Function: " << MF.getName() << '\n'); const Function &F = MF.getFunction(); // LLVM does not consider basic blocks which are the targets of jump tables @@ -103,6 +111,12 @@ bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) { JumpTableTargets.count(&MBB)) CouldJump = true; + if (MBB.isEHPad()) { + if (HasWinCFI && (MBB.isEHFuncletEntry() || MBB.isCleanupFuncletEntry())) + CouldCall = true; + else + CouldJump = true; + } if (CouldCall || CouldJump) { addBTI(MBB, CouldCall, CouldJump, HasWinCFI); MadeChange = true; @@ -130,7 +144,12 @@ void AArch64BranchTargets::addBTI(MachineBasicBlock &MBB, bool CouldCall, auto MBBI = MBB.begin(); - // Skip the meta instructions, those will be removed anyway. + // If the block starts with EH_LABEL(s), skip them first. + while (MBBI != MBB.end() && MBBI->isEHLabel()) { + ++MBBI; + } + + // Skip meta/CFI/etc. (and EMITBKEY) to reach the first executable insn. for (; MBBI != MBB.end() && (MBBI->isMetaInstruction() || MBBI->getOpcode() == AArch64::EMITBKEY); ++MBBI) @@ -138,16 +157,21 @@ void AArch64BranchTargets::addBTI(MachineBasicBlock &MBB, bool CouldCall, // SCTLR_EL1.BT[01] is set to 0 by default which means // PACI[AB]SP are implicitly BTI C so no BTI C instruction is needed there. - if (MBBI != MBB.end() && HintNum == 34 && + if (MBBI != MBB.end() && ((HintNum & BTIMask) == BTIC) && (MBBI->getOpcode() == AArch64::PACIASP || MBBI->getOpcode() == AArch64::PACIBSP)) return; - if (HasWinCFI && MBBI->getFlag(MachineInstr::FrameSetup)) { - BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()), - TII->get(AArch64::SEH_Nop)); + // Insert BTI exactly at the first executable instruction. + const DebugLoc DL = MBB.findDebugLoc(MBBI); + MachineInstr *BTI = BuildMI(MBB, MBBI, DL, TII->get(AArch64::HINT)) + .addImm(HintNum) + .getInstr(); + + // WinEH: put .seh_nop after BTI when the first real insn is FrameSetup. + if (HasWinCFI && MBBI != MBB.end() && + MBBI->getFlag(MachineInstr::FrameSetup)) { + auto AfterBTI = std::next(MachineBasicBlock::iterator(BTI)); + BuildMI(MBB, AfterBTI, DL, TII->get(AArch64::SEH_Nop)); } - BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()), - TII->get(AArch64::HINT)) - .addImm(HintNum); } diff --git a/llvm/test/CodeGen/AArch64/bti-ehpad.ll b/llvm/test/CodeGen/AArch64/bti-ehpad.ll new file mode 100644 index 0000000000000..674421adaf51c --- /dev/null +++ b/llvm/test/CodeGen/AArch64/bti-ehpad.ll @@ -0,0 +1,44 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=aarch64-unknown-linux-gnu %s -o - | FileCheck %s + +; Purpose: With BTI enabled, the landing pad (%lpad) begins with an EH_LABEL and the +; first *executed* instruction is `bti j`. (BTI is inserted *after* the EH label and meta.) + +declare i32 @__gxx_personality_v0(...) +declare void @may_throw() + +define void @test() #0 personality ptr @__gxx_personality_v0 { +; CHECK-LABEL: test: +; CHECK: .Lfunc_begin0: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0 +; CHECK-NEXT: .cfi_lsda 28, .Lexception0 +; CHECK-NEXT: // %bb.0: // %entry +; CHECK-NEXT: bti c +; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill +; CHECK-NEXT: .cfi_def_cfa_offset 16 +; CHECK-NEXT: .cfi_offset w30, -16 +; CHECK-NEXT: .Ltmp0: // EH_LABEL +; CHECK-NEXT: bl may_throw +; CHECK-NEXT: .Ltmp1: // EH_LABEL +; CHECK-NEXT: // %bb.1: // %common.ret +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +; CHECK-NEXT: .LBB0_2: // %lpad +; CHECK-NEXT: .Ltmp2: // EH_LABEL +; CHECK-NEXT: bti j +; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload +; CHECK-NEXT: ret +entry: + invoke void @may_throw() + to label %ret unwind label %lpad + +lpad: + landingpad { ptr, i32 } cleanup + ret void + +ret: + ret void +} + +attributes #0 = { noinline "branch-target-enforcement"="true" "target-features"="+bti" } diff --git a/llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll b/llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll index 85aa6846cd800..0091469edde92 100644 --- a/llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll +++ b/llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll @@ -507,8 +507,8 @@ define i32 @leaf_sign_all_a_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r ; ; PAUTHLR-LABEL: leaf_sign_all_a_key_bti: ; PAUTHLR: // %bb.0: -; PAUTHLR-NEXT: bti c ; PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc +; PAUTHLR-NEXT: bti c ; PAUTHLR-NEXT: .Ltmp10: ; PAUTHLR-NEXT: paciasppc ; PAUTHLR-NEXT: adrp x16, .Ltmp10 @@ -521,8 +521,8 @@ define i32 @leaf_sign_all_a_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r define i32 @leaf_sign_all_b_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-return-address"="all" "sign-return-address-key"="b_key" "branch-target-enforcement" { ; COMPAT-LABEL: leaf_sign_all_b_key_bti: ; COMPAT: // %bb.0: +; COMPAT-NEXT: .cfi_b_key_frame ; COMPAT-NEXT: hint #34 -; COMPAT-NEXT: .cfi_b_key_frame ; COMPAT-NEXT: hint #39 ; COMPAT-NEXT: .cfi_negate_ra_state_with_pc ; COMPAT-NEXT: .Ltmp11: @@ -535,8 +535,8 @@ define i32 @leaf_sign_all_b_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r ; ; V83A-LABEL: leaf_sign_all_b_key_bti: ; V83A: // %bb.0: -; V83A-NEXT: hint #34 ; V83A-NEXT: .cfi_b_key_frame +; V83A-NEXT: hint #34 ; V83A-NEXT: hint #39 ; V83A-NEXT: .cfi_negate_ra_state_with_pc ; V83A-NEXT: .Ltmp11: @@ -548,9 +548,9 @@ define i32 @leaf_sign_all_b_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r ; ; PAUTHLR-LABEL: leaf_sign_all_b_key_bti: ; PAUTHLR: // %bb.0: -; PAUTHLR-NEXT: bti c ; PAUTHLR-NEXT: .cfi_b_key_frame ; PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc +; PAUTHLR-NEXT: bti c ; PAUTHLR-NEXT: .Ltmp11: ; PAUTHLR-NEXT: pacibsppc ; PAUTHLR-NEXT: adrp x16, .Ltmp11 @@ -563,9 +563,9 @@ define i32 @leaf_sign_all_b_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r define i32 @leaf_sign_all_v83_b_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-return-address"="all" "target-features"="+v8.3a" "sign-return-address-key"="b_key" "branch-target-enforcement" { ; CHECK-LABEL: leaf_sign_all_v83_b_key_bti: ; CHECK: // %bb.0: -; CHECK-NEXT: hint #34 -; CHECK-NEXT: .cfi_b_key_frame -; CHECK-NEXT: hint #39 +; CHECK-NEXT: .cfi_b_key_frame +; CHECK-NEXT: hint #34 +; CHECK-NEXT: hint #39 ; CHECK-NEXT: .cfi_negate_ra_state_with_pc ; CHECK-NEXT: .Ltmp12: ; CHECK-NEXT: pacibsp @@ -576,9 +576,9 @@ define i32 @leaf_sign_all_v83_b_key_bti(i32 %x) "branch-protection-pauth-lr" "si ; ; PAUTHLR-LABEL: leaf_sign_all_v83_b_key_bti: ; PAUTHLR: // %bb.0: -; PAUTHLR-NEXT: bti c ; PAUTHLR-NEXT: .cfi_b_key_frame ; PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc +; PAUTHLR-NEXT: bti c ; PAUTHLR-NEXT: .Ltmp12: ; PAUTHLR-NEXT: pacibsppc ; PAUTHLR-NEXT: adrp x16, .Ltmp12 diff --git a/llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll b/llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll new file mode 100644 index 0000000000000..4f4f984b8974b --- /dev/null +++ b/llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll @@ -0,0 +1,79 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc -mtriple=aarch64-windows -mattr=+bti -o - %s | FileCheck %s + +declare i32 @__CxxFrameHandler3(...) +declare void @may_throw() + +; Purpose: For WinEH funclets, entry is call-like: accept `bti c` / `hint #34` or a PAC prologue. + +define dso_local void @wineh_funclet() #0 personality ptr @__CxxFrameHandler3 { +; CHECK-LABEL: wineh_funclet: +; CHECK: .Lfunc_begin0: +; CHECK-NEXT: .seh_proc wineh_funclet +; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except +; CHECK-NEXT: // %bb.0: // %entry +; CHECK-NEXT: bti c +; CHECK-NEXT: .seh_nop +; CHECK-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill +; CHECK-NEXT: .seh_save_fplr_x 32 +; CHECK-NEXT: mov x29, sp +; CHECK-NEXT: .seh_set_fp +; CHECK-NEXT: .seh_endprologue +; CHECK-NEXT: mov x0, #-2 // =0xfffffffffffffffe +; CHECK-NEXT: stur x0, [x29, #16] +; CHECK-NEXT: .Ltmp0: // EH_LABEL +; CHECK-NEXT: bl may_throw +; CHECK-NEXT: .Ltmp1: // EH_LABEL +; CHECK-NEXT: .LBB0_1: // Block address taken +; CHECK-NEXT: // %try.cont +; CHECK-NEXT: $ehgcr_0_1: +; CHECK-NEXT: bti j +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload +; CHECK-NEXT: .seh_save_fplr_x 32 +; CHECK-NEXT: .seh_endepilogue +; CHECK-NEXT: ret +; CHECK-NEXT: .seh_endfunclet +; CHECK-NEXT: .seh_handlerdata +; CHECK-NEXT: .word $cppxdata$wineh_funclet@IMGREL +; CHECK-NEXT: .text +; CHECK-NEXT: .seh_endproc +; CHECK-NEXT: .def "?catch$2@?0?wineh_funclet@4HA"; +; CHECK-NEXT: .scl 3; +; CHECK-NEXT: .type 32; +; CHECK-NEXT: .endef +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: "?catch$2@?0?wineh_funclet@4HA": +; CHECK-NEXT: .seh_proc "?catch$2@?0?wineh_funclet@4HA" +; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except +; CHECK-NEXT: .LBB0_2: // %catch +; CHECK-NEXT: bti c +; CHECK-NEXT: .seh_nop +; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill +; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: .seh_endprologue +; CHECK-NEXT: bl may_throw +; CHECK-NEXT: adrp x0, .LBB0_1 +; CHECK-NEXT: add x0, x0, .LBB0_1 +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: ldp x29, x30, [sp], #16 // 16-byte Folded Reload +; CHECK-NEXT: .seh_save_fplr_x 16 +; CHECK-NEXT: .seh_endepilogue +; CHECK-NEXT: ret +entry: + invoke void @may_throw() + to label %try.cont unwind label %catch.dispatch + +catch.dispatch: + %cs = catchswitch within none [label %catch] unwind to caller + +catch: + %cp = catchpad within %cs [ptr null, i32 0, ptr null] + call void @may_throw() ["funclet"(token %cp)] + catchret from %cp to label %try.cont + +try.cont: + ret void +} + +attributes #0 = { noinline "branch-target-enforcement"="true" } diff --git a/llvm/test/CodeGen/AArch64/wineh-bti.ll b/llvm/test/CodeGen/AArch64/wineh-bti.ll index 8b8960d37f9ef..86555a7f64366 100644 --- a/llvm/test/CodeGen/AArch64/wineh-bti.ll +++ b/llvm/test/CodeGen/AArch64/wineh-bti.ll @@ -29,7 +29,7 @@ lbl4: ; CHECK-LABEL: func: ; CHECK-NEXT: .seh_proc func -; CHECK-NEXT: // %bb.0: +; CHECK: // %bb.0: // %entry ; CHECK-NEXT: hint #34 ; CHECK-NEXT: .seh_nop ; CHECK-NEXT: str x19, [sp, #-16]! >From 910b1ef507173197ab687271a0b9f3e99fa159d0 Mon Sep 17 00:00:00 2001 From: David Green <david.gr...@arm.com> Date: Mon, 1 Sep 2025 07:20:47 +0100 Subject: [PATCH 2/2] Remove EH_LABEL comments from tests --- llvm/test/CodeGen/AArch64/bti-ehpad.ll | 6 +++--- llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/test/CodeGen/AArch64/bti-ehpad.ll b/llvm/test/CodeGen/AArch64/bti-ehpad.ll index 674421adaf51c..dee4bd3ec8adf 100644 --- a/llvm/test/CodeGen/AArch64/bti-ehpad.ll +++ b/llvm/test/CodeGen/AArch64/bti-ehpad.ll @@ -18,14 +18,14 @@ define void @test() #0 personality ptr @__gxx_personality_v0 { ; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill ; CHECK-NEXT: .cfi_def_cfa_offset 16 ; CHECK-NEXT: .cfi_offset w30, -16 -; CHECK-NEXT: .Ltmp0: // EH_LABEL +; CHECK-NEXT: .Ltmp0: ; CHECK-NEXT: bl may_throw -; CHECK-NEXT: .Ltmp1: // EH_LABEL +; CHECK-NEXT: .Ltmp1: ; CHECK-NEXT: // %bb.1: // %common.ret ; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload ; CHECK-NEXT: ret ; CHECK-NEXT: .LBB0_2: // %lpad -; CHECK-NEXT: .Ltmp2: // EH_LABEL +; CHECK-NEXT: .Ltmp2: ; CHECK-NEXT: bti j ; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload ; CHECK-NEXT: ret diff --git a/llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll b/llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll index 4f4f984b8974b..3a1eaf04af5ab 100644 --- a/llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll +++ b/llvm/test/CodeGen/AArch64/wineh-bti-funclet.ll @@ -21,9 +21,9 @@ define dso_local void @wineh_funclet() #0 personality ptr @__CxxFrameHandler3 { ; CHECK-NEXT: .seh_endprologue ; CHECK-NEXT: mov x0, #-2 // =0xfffffffffffffffe ; CHECK-NEXT: stur x0, [x29, #16] -; CHECK-NEXT: .Ltmp0: // EH_LABEL +; CHECK-NEXT: .Ltmp0: ; CHECK-NEXT: bl may_throw -; CHECK-NEXT: .Ltmp1: // EH_LABEL +; CHECK-NEXT: .Ltmp1: ; CHECK-NEXT: .LBB0_1: // Block address taken ; CHECK-NEXT: // %try.cont ; CHECK-NEXT: $ehgcr_0_1: _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits