Skip to content

Commit 3751e53

Browse files
shashforgetru
authored andcommitted
[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 <[email protected]> (cherry picked from commit 1b37b9e)
1 parent f8a0ecf commit 3751e53

File tree

5 files changed

+167
-20
lines changed

5 files changed

+167
-20
lines changed

llvm/lib/Target/AArch64/AArch64BranchTargets.cpp

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ using namespace llvm;
3030
#define AARCH64_BRANCH_TARGETS_NAME "AArch64 Branch Targets"
3131

3232
namespace {
33+
// BTI HINT encoding: base (32) plus 'c' (2) and/or 'j' (4).
34+
enum : unsigned {
35+
BTIBase = 32, // Base immediate for BTI HINT
36+
BTIC = 1u << 1, // 2
37+
BTIJ = 1u << 2, // 4
38+
BTIMask = BTIC | BTIJ,
39+
};
40+
3341
class AArch64BranchTargets : public MachineFunctionPass {
3442
public:
3543
static char ID;
@@ -42,6 +50,7 @@ class AArch64BranchTargets : public MachineFunctionPass {
4250
void addBTI(MachineBasicBlock &MBB, bool CouldCall, bool CouldJump,
4351
bool NeedsWinCFI);
4452
};
53+
4554
} // end anonymous namespace
4655

4756
char AArch64BranchTargets::ID = 0;
@@ -62,9 +71,8 @@ bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) {
6271
if (!MF.getInfo<AArch64FunctionInfo>()->branchTargetEnforcement())
6372
return false;
6473

65-
LLVM_DEBUG(
66-
dbgs() << "********** AArch64 Branch Targets **********\n"
67-
<< "********** Function: " << MF.getName() << '\n');
74+
LLVM_DEBUG(dbgs() << "********** AArch64 Branch Targets **********\n"
75+
<< "********** Function: " << MF.getName() << '\n');
6876
const Function &F = MF.getFunction();
6977

7078
// LLVM does not consider basic blocks which are the targets of jump tables
@@ -103,6 +111,12 @@ bool AArch64BranchTargets::runOnMachineFunction(MachineFunction &MF) {
103111
JumpTableTargets.count(&MBB))
104112
CouldJump = true;
105113

114+
if (MBB.isEHPad()) {
115+
if (HasWinCFI && (MBB.isEHFuncletEntry() || MBB.isCleanupFuncletEntry()))
116+
CouldCall = true;
117+
else
118+
CouldJump = true;
119+
}
106120
if (CouldCall || CouldJump) {
107121
addBTI(MBB, CouldCall, CouldJump, HasWinCFI);
108122
MadeChange = true;
@@ -130,24 +144,34 @@ void AArch64BranchTargets::addBTI(MachineBasicBlock &MBB, bool CouldCall,
130144

131145
auto MBBI = MBB.begin();
132146

133-
// Skip the meta instructions, those will be removed anyway.
147+
// If the block starts with EH_LABEL(s), skip them first.
148+
while (MBBI != MBB.end() && MBBI->isEHLabel()) {
149+
++MBBI;
150+
}
151+
152+
// Skip meta/CFI/etc. (and EMITBKEY) to reach the first executable insn.
134153
for (; MBBI != MBB.end() &&
135154
(MBBI->isMetaInstruction() || MBBI->getOpcode() == AArch64::EMITBKEY);
136155
++MBBI)
137156
;
138157

139158
// SCTLR_EL1.BT[01] is set to 0 by default which means
140159
// PACI[AB]SP are implicitly BTI C so no BTI C instruction is needed there.
141-
if (MBBI != MBB.end() && HintNum == 34 &&
160+
if (MBBI != MBB.end() && ((HintNum & BTIMask) == BTIC) &&
142161
(MBBI->getOpcode() == AArch64::PACIASP ||
143162
MBBI->getOpcode() == AArch64::PACIBSP))
144163
return;
145164

146-
if (HasWinCFI && MBBI->getFlag(MachineInstr::FrameSetup)) {
147-
BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
148-
TII->get(AArch64::SEH_Nop));
165+
// Insert BTI exactly at the first executable instruction.
166+
const DebugLoc DL = MBB.findDebugLoc(MBBI);
167+
MachineInstr *BTI = BuildMI(MBB, MBBI, DL, TII->get(AArch64::HINT))
168+
.addImm(HintNum)
169+
.getInstr();
170+
171+
// WinEH: put .seh_nop after BTI when the first real insn is FrameSetup.
172+
if (HasWinCFI && MBBI != MBB.end() &&
173+
MBBI->getFlag(MachineInstr::FrameSetup)) {
174+
auto AfterBTI = std::next(MachineBasicBlock::iterator(BTI));
175+
BuildMI(MBB, AfterBTI, DL, TII->get(AArch64::SEH_Nop));
149176
}
150-
BuildMI(MBB, MBB.begin(), MBB.findDebugLoc(MBB.begin()),
151-
TII->get(AArch64::HINT))
152-
.addImm(HintNum);
153177
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -mtriple=aarch64-unknown-linux-gnu %s -o - | FileCheck %s
3+
4+
; Purpose: With BTI enabled, the landing pad (%lpad) begins with an EH_LABEL and the
5+
; first *executed* instruction is `bti j`. (BTI is inserted *after* the EH label and meta.)
6+
7+
declare i32 @__gxx_personality_v0(...)
8+
declare void @may_throw()
9+
10+
define void @test() #0 personality ptr @__gxx_personality_v0 {
11+
; CHECK-LABEL: test:
12+
; CHECK: .Lfunc_begin0:
13+
; CHECK-NEXT: .cfi_startproc
14+
; CHECK-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0
15+
; CHECK-NEXT: .cfi_lsda 28, .Lexception0
16+
; CHECK-NEXT: // %bb.0: // %entry
17+
; CHECK-NEXT: bti c
18+
; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
19+
; CHECK-NEXT: .cfi_def_cfa_offset 16
20+
; CHECK-NEXT: .cfi_offset w30, -16
21+
; CHECK-NEXT: .Ltmp0: // EH_LABEL
22+
; CHECK-NEXT: bl may_throw
23+
; CHECK-NEXT: .Ltmp1: // EH_LABEL
24+
; CHECK-NEXT: // %bb.1: // %common.ret
25+
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
26+
; CHECK-NEXT: ret
27+
; CHECK-NEXT: .LBB0_2: // %lpad
28+
; CHECK-NEXT: .Ltmp2: // EH_LABEL
29+
; CHECK-NEXT: bti j
30+
; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
31+
; CHECK-NEXT: ret
32+
entry:
33+
invoke void @may_throw()
34+
to label %ret unwind label %lpad
35+
36+
lpad:
37+
landingpad { ptr, i32 } cleanup
38+
ret void
39+
40+
ret:
41+
ret void
42+
}
43+
44+
attributes #0 = { noinline "branch-target-enforcement"="true" "target-features"="+bti" }

llvm/test/CodeGen/AArch64/sign-return-address-pauth-lr.ll

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -507,8 +507,8 @@ define i32 @leaf_sign_all_a_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r
507507
;
508508
; PAUTHLR-LABEL: leaf_sign_all_a_key_bti:
509509
; PAUTHLR: // %bb.0:
510-
; PAUTHLR-NEXT: bti c
511510
; PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc
511+
; PAUTHLR-NEXT: bti c
512512
; PAUTHLR-NEXT: .Ltmp10:
513513
; PAUTHLR-NEXT: paciasppc
514514
; 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
521521
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" {
522522
; COMPAT-LABEL: leaf_sign_all_b_key_bti:
523523
; COMPAT: // %bb.0:
524+
; COMPAT-NEXT: .cfi_b_key_frame
524525
; COMPAT-NEXT: hint #34
525-
; COMPAT-NEXT: .cfi_b_key_frame
526526
; COMPAT-NEXT: hint #39
527527
; COMPAT-NEXT: .cfi_negate_ra_state_with_pc
528528
; COMPAT-NEXT: .Ltmp11:
@@ -535,8 +535,8 @@ define i32 @leaf_sign_all_b_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r
535535
;
536536
; V83A-LABEL: leaf_sign_all_b_key_bti:
537537
; V83A: // %bb.0:
538-
; V83A-NEXT: hint #34
539538
; V83A-NEXT: .cfi_b_key_frame
539+
; V83A-NEXT: hint #34
540540
; V83A-NEXT: hint #39
541541
; V83A-NEXT: .cfi_negate_ra_state_with_pc
542542
; V83A-NEXT: .Ltmp11:
@@ -548,9 +548,9 @@ define i32 @leaf_sign_all_b_key_bti(i32 %x) "branch-protection-pauth-lr" "sign-r
548548
;
549549
; PAUTHLR-LABEL: leaf_sign_all_b_key_bti:
550550
; PAUTHLR: // %bb.0:
551-
; PAUTHLR-NEXT: bti c
552551
; PAUTHLR-NEXT: .cfi_b_key_frame
553552
; PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc
553+
; PAUTHLR-NEXT: bti c
554554
; PAUTHLR-NEXT: .Ltmp11:
555555
; PAUTHLR-NEXT: pacibsppc
556556
; 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
563563
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" {
564564
; CHECK-LABEL: leaf_sign_all_v83_b_key_bti:
565565
; CHECK: // %bb.0:
566-
; CHECK-NEXT: hint #34
567-
; CHECK-NEXT: .cfi_b_key_frame
568-
; CHECK-NEXT: hint #39
566+
; CHECK-NEXT: .cfi_b_key_frame
567+
; CHECK-NEXT: hint #34
568+
; CHECK-NEXT: hint #39
569569
; CHECK-NEXT: .cfi_negate_ra_state_with_pc
570570
; CHECK-NEXT: .Ltmp12:
571571
; CHECK-NEXT: pacibsp
@@ -576,9 +576,9 @@ define i32 @leaf_sign_all_v83_b_key_bti(i32 %x) "branch-protection-pauth-lr" "si
576576
;
577577
; PAUTHLR-LABEL: leaf_sign_all_v83_b_key_bti:
578578
; PAUTHLR: // %bb.0:
579-
; PAUTHLR-NEXT: bti c
580579
; PAUTHLR-NEXT: .cfi_b_key_frame
581580
; PAUTHLR-NEXT: .cfi_negate_ra_state_with_pc
581+
; PAUTHLR-NEXT: bti c
582582
; PAUTHLR-NEXT: .Ltmp12:
583583
; PAUTHLR-NEXT: pacibsppc
584584
; PAUTHLR-NEXT: adrp x16, .Ltmp12
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc -mtriple=aarch64-windows -mattr=+bti -o - %s | FileCheck %s
3+
4+
declare i32 @__CxxFrameHandler3(...)
5+
declare void @may_throw()
6+
7+
; Purpose: For WinEH funclets, entry is call-like: accept `bti c` / `hint #34` or a PAC prologue.
8+
9+
define dso_local void @wineh_funclet() #0 personality ptr @__CxxFrameHandler3 {
10+
; CHECK-LABEL: wineh_funclet:
11+
; CHECK: .Lfunc_begin0:
12+
; CHECK-NEXT: .seh_proc wineh_funclet
13+
; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except
14+
; CHECK-NEXT: // %bb.0: // %entry
15+
; CHECK-NEXT: bti c
16+
; CHECK-NEXT: .seh_nop
17+
; CHECK-NEXT: stp x29, x30, [sp, #-32]! // 16-byte Folded Spill
18+
; CHECK-NEXT: .seh_save_fplr_x 32
19+
; CHECK-NEXT: mov x29, sp
20+
; CHECK-NEXT: .seh_set_fp
21+
; CHECK-NEXT: .seh_endprologue
22+
; CHECK-NEXT: mov x0, #-2 // =0xfffffffffffffffe
23+
; CHECK-NEXT: stur x0, [x29, #16]
24+
; CHECK-NEXT: .Ltmp0: // EH_LABEL
25+
; CHECK-NEXT: bl may_throw
26+
; CHECK-NEXT: .Ltmp1: // EH_LABEL
27+
; CHECK-NEXT: .LBB0_1: // Block address taken
28+
; CHECK-NEXT: // %try.cont
29+
; CHECK-NEXT: $ehgcr_0_1:
30+
; CHECK-NEXT: bti j
31+
; CHECK-NEXT: .seh_startepilogue
32+
; CHECK-NEXT: ldp x29, x30, [sp], #32 // 16-byte Folded Reload
33+
; CHECK-NEXT: .seh_save_fplr_x 32
34+
; CHECK-NEXT: .seh_endepilogue
35+
; CHECK-NEXT: ret
36+
; CHECK-NEXT: .seh_endfunclet
37+
; CHECK-NEXT: .seh_handlerdata
38+
; CHECK-NEXT: .word $cppxdata$wineh_funclet@IMGREL
39+
; CHECK-NEXT: .text
40+
; CHECK-NEXT: .seh_endproc
41+
; CHECK-NEXT: .def "?catch$2@?0?wineh_funclet@4HA";
42+
; CHECK-NEXT: .scl 3;
43+
; CHECK-NEXT: .type 32;
44+
; CHECK-NEXT: .endef
45+
; CHECK-NEXT: .p2align 2
46+
; CHECK-NEXT: "?catch$2@?0?wineh_funclet@4HA":
47+
; CHECK-NEXT: .seh_proc "?catch$2@?0?wineh_funclet@4HA"
48+
; CHECK-NEXT: .seh_handler __CxxFrameHandler3, @unwind, @except
49+
; CHECK-NEXT: .LBB0_2: // %catch
50+
; CHECK-NEXT: bti c
51+
; CHECK-NEXT: .seh_nop
52+
; CHECK-NEXT: stp x29, x30, [sp, #-16]! // 16-byte Folded Spill
53+
; CHECK-NEXT: .seh_save_fplr_x 16
54+
; CHECK-NEXT: .seh_endprologue
55+
; CHECK-NEXT: bl may_throw
56+
; CHECK-NEXT: adrp x0, .LBB0_1
57+
; CHECK-NEXT: add x0, x0, .LBB0_1
58+
; CHECK-NEXT: .seh_startepilogue
59+
; CHECK-NEXT: ldp x29, x30, [sp], #16 // 16-byte Folded Reload
60+
; CHECK-NEXT: .seh_save_fplr_x 16
61+
; CHECK-NEXT: .seh_endepilogue
62+
; CHECK-NEXT: ret
63+
entry:
64+
invoke void @may_throw()
65+
to label %try.cont unwind label %catch.dispatch
66+
67+
catch.dispatch:
68+
%cs = catchswitch within none [label %catch] unwind to caller
69+
70+
catch:
71+
%cp = catchpad within %cs [ptr null, i32 0, ptr null]
72+
call void @may_throw() ["funclet"(token %cp)]
73+
catchret from %cp to label %try.cont
74+
75+
try.cont:
76+
ret void
77+
}
78+
79+
attributes #0 = { noinline "branch-target-enforcement"="true" }

llvm/test/CodeGen/AArch64/wineh-bti.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ lbl4:
2929

3030
; CHECK-LABEL: func:
3131
; CHECK-NEXT: .seh_proc func
32-
; CHECK-NEXT: // %bb.0:
32+
; CHECK: // %bb.0: // %entry
3333
; CHECK-NEXT: hint #34
3434
; CHECK-NEXT: .seh_nop
3535
; CHECK-NEXT: str x19, [sp, #-16]!

0 commit comments

Comments
 (0)