Skip to content

Commit c12bc57

Browse files
authored
Do not use R12 for indirect tail calls with PACBTI (#82661)
When compiling for thumbv8.1m with +pacbti and making an indirect tail call, the compiler was free to put the function pointer into R12. This is incorrect because R12 is restored to contain authentication code for the caller's return address. This patch excludes R12 from the set of registers the compiler can put the function pointer in. Fixes #75998
1 parent c106abf commit c12bc57

11 files changed

+112
-15
lines changed

llvm/lib/Target/ARM/ARMBaseInstrInfo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ static inline bool isIndirectCall(const MachineInstr &MI) {
683683
case ARM::BX_CALL:
684684
case ARM::BMOVPCRX_CALL:
685685
case ARM::TCRETURNri:
686+
case ARM::TCRETURNrinotr12:
686687
case ARM::TAILJMPr:
687688
case ARM::TAILJMPr4:
688689
case ARM::tBLXr:

llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,7 +2197,8 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
21972197
}
21982198

21992199
case ARM::TCRETURNdi:
2200-
case ARM::TCRETURNri: {
2200+
case ARM::TCRETURNri:
2201+
case ARM::TCRETURNrinotr12: {
22012202
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
22022203
if (MBBI->getOpcode() == ARM::SEH_EpilogEnd)
22032204
MBBI--;
@@ -2241,7 +2242,8 @@ bool ARMExpandPseudo::ExpandMI(MachineBasicBlock &MBB,
22412242
// Add the default predicate in Thumb mode.
22422243
if (STI->isThumb())
22432244
MIB.add(predOps(ARMCC::AL));
2244-
} else if (RetOpcode == ARM::TCRETURNri) {
2245+
} else if (RetOpcode == ARM::TCRETURNri ||
2246+
RetOpcode == ARM::TCRETURNrinotr12) {
22452247
unsigned Opcode =
22462248
STI->isThumb() ? ARM::tTAILJMPr
22472249
: (STI->hasV4TOps() ? ARM::TAILJMPr : ARM::TAILJMPr4);

llvm/lib/Target/ARM/ARMFrameLowering.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,8 @@ static int getArgumentStackToRestore(MachineFunction &MF,
257257
if (MBB.end() != MBBI) {
258258
unsigned RetOpcode = MBBI->getOpcode();
259259
IsTailCallReturn = RetOpcode == ARM::TCRETURNdi ||
260-
RetOpcode == ARM::TCRETURNri;
260+
RetOpcode == ARM::TCRETURNri ||
261+
RetOpcode == ARM::TCRETURNrinotr12;
261262
}
262263
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
263264

@@ -486,6 +487,7 @@ static MachineBasicBlock::iterator insertSEH(MachineBasicBlock::iterator MBBI,
486487

487488
case ARM::tBX_RET:
488489
case ARM::TCRETURNri:
490+
case ARM::TCRETURNrinotr12:
489491
MIB = BuildMI(MF, DL, TII.get(ARM::SEH_Nop_Ret))
490492
.addImm(/*Wide=*/0)
491493
.setMIFlags(Flags);
@@ -1615,7 +1617,9 @@ void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB,
16151617
if (MBB.end() != MI) {
16161618
DL = MI->getDebugLoc();
16171619
unsigned RetOpcode = MI->getOpcode();
1618-
isTailCall = (RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNri);
1620+
isTailCall =
1621+
(RetOpcode == ARM::TCRETURNdi || RetOpcode == ARM::TCRETURNri ||
1622+
RetOpcode == ARM::TCRETURNrinotr12);
16191623
isInterrupt =
16201624
RetOpcode == ARM::SUBS_PC_LR || RetOpcode == ARM::t2SUBS_PC_LR;
16211625
isTrap =

llvm/lib/Target/ARM/ARMInstrInfo.td

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2677,6 +2677,9 @@ let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [SP] in {
26772677
def TCRETURNri : PseudoInst<(outs), (ins tcGPR:$dst, i32imm:$SPDiff), IIC_Br, []>,
26782678
Sched<[WriteBr]>;
26792679

2680+
def TCRETURNrinotr12 : PseudoInst<(outs), (ins tcGPRnotr12:$dst, i32imm:$SPDiff), IIC_Br, []>,
2681+
Sched<[WriteBr]>;
2682+
26802683
def TAILJMPd : ARMPseudoExpand<(outs), (ins arm_br_target:$dst),
26812684
4, IIC_Br, [],
26822685
(Bcc arm_br_target:$dst, (ops 14, zero_reg))>,
@@ -6081,8 +6084,14 @@ def : ARMPat<(ARMWrapperJT tjumptable:$dst),
60816084
// TODO: add,sub,and, 3-instr forms?
60826085

60836086
// Tail calls. These patterns also apply to Thumb mode.
6087+
// Regular indirect tail call
60846088
def : Pat<(ARMtcret tcGPR:$dst, (i32 timm:$SPDiff)),
6085-
(TCRETURNri tcGPR:$dst, timm:$SPDiff)>;
6089+
(TCRETURNri tcGPR:$dst, timm:$SPDiff)>,
6090+
Requires<[NoSignRetAddr]>;
6091+
// Indirect tail call when PACBTI is enabled
6092+
def : Pat<(ARMtcret tcGPRnotr12:$dst, (i32 timm:$SPDiff)),
6093+
(TCRETURNrinotr12 tcGPRnotr12:$dst, timm:$SPDiff)>,
6094+
Requires<[SignRetAddr]>;
60866095
def : Pat<(ARMtcret (i32 tglobaladdr:$dst), (i32 timm:$SPDiff)),
60876096
(TCRETURNdi texternalsym:$dst, (i32 timm:$SPDiff))>;
60886097
def : Pat<(ARMtcret (i32 texternalsym:$dst), (i32 timm:$SPDiff)),

llvm/lib/Target/ARM/ARMPredicates.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ def DontGenExecuteOnly : Predicate<"!Subtarget->genExecuteOnly()">;
228228
def GenT1ExecuteOnly : Predicate<"Subtarget->genExecuteOnly() && "
229229
"Subtarget->isThumb1Only() && "
230230
"!Subtarget->hasV8MBaselineOps()">;
231+
let RecomputePerFunction = 1 in {
232+
def SignRetAddr : Predicate<[{ MF->getInfo<ARMFunctionInfo>()->shouldSignReturnAddress(true) }]>;
233+
def NoSignRetAddr : Predicate<[{ !MF->getInfo<ARMFunctionInfo>()->shouldSignReturnAddress(true) }]>;
234+
}
231235

232236
// Armv8.5-A extensions
233237
def HasSB : Predicate<"Subtarget->hasSB()">,

llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -156,11 +156,6 @@ ARMRegisterBankInfo::ARMRegisterBankInfo(const TargetRegisterInfo &TRI) {
156156
"Subclass not added?");
157157
assert(RBGPR.covers(*TRI.getRegClass(ARM::tcGPRRegClassID)) &&
158158
"Subclass not added?");
159-
assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnoip_and_tcGPRRegClassID)) &&
160-
"Subclass not added?");
161-
assert(RBGPR.covers(*TRI.getRegClass(
162-
ARM::tGPREven_and_GPRnoip_and_tcGPRRegClassID)) &&
163-
"Subclass not added?");
164159
assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPROdd_and_tcGPRRegClassID)) &&
165160
"Subclass not added?");
166161
assert(getMaximumSize(RBGPR.getID()) == 32 &&
@@ -188,16 +183,16 @@ ARMRegisterBankInfo::getRegBankFromRegClass(const TargetRegisterClass &RC,
188183
case GPRnoip_and_GPRnopcRegClassID:
189184
case rGPRRegClassID:
190185
case GPRspRegClassID:
191-
case GPRnoip_and_tcGPRRegClassID:
192186
case tcGPRRegClassID:
187+
case tcGPRnotr12RegClassID:
193188
case tGPRRegClassID:
194189
case tGPREvenRegClassID:
195190
case tGPROddRegClassID:
196191
case tGPR_and_tGPREvenRegClassID:
197192
case tGPR_and_tGPROddRegClassID:
198193
case tGPREven_and_tcGPRRegClassID:
199-
case tGPREven_and_GPRnoip_and_tcGPRRegClassID:
200194
case tGPROdd_and_tcGPRRegClassID:
195+
case tGPREven_and_tcGPRnotr12RegClassID:
201196
return getRegBank(ARM::GPRRegBankID);
202197
case HPRRegClassID:
203198
case SPR_8RegClassID:

llvm/lib/Target/ARM/ARMRegisterInfo.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,16 @@ def tcGPR : RegisterClass<"ARM", [i32], 32, (add R0, R1, R2, R3, R12)> {
373373
}];
374374
}
375375

376+
// Some pointer authentication instructions require the use of R12. When return
377+
// address signing is enabled, authentication of the caller's return address
378+
// must be performed before a tail call is made. Therefore, indirect tail call
379+
// jump cannot be from R12.
380+
// FIXME: All PACBTI instruction currently implemented in the compiler
381+
// implicitly use R12. When instructions that allow PAC to be placed in a
382+
// specific register are implemented the restriction needs to be updated to
383+
// make sure that PACBTI signature and indirect tail call both use a different register.
384+
def tcGPRnotr12 : RegisterClass<"ARM", [i32], 32, (add R0, R1, R2, R3)>;
385+
376386
def tGPROdd : RegisterClass<"ARM", [i32], 32, (add R1, R3, R5, R7, R9, R11)> {
377387
let AltOrders = [(and tGPROdd, tGPR)];
378388
let AltOrderSelect = [{

llvm/lib/Target/ARM/Thumb1FrameLowering.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1044,9 +1044,9 @@ static void popRegsFromStack(MachineBasicBlock &MBB,
10441044
continue;
10451045

10461046
if (Reg == ARM::LR) {
1047-
if (!MBB.succ_empty() ||
1048-
MI->getOpcode() == ARM::TCRETURNdi ||
1049-
MI->getOpcode() == ARM::TCRETURNri)
1047+
if (!MBB.succ_empty() || MI->getOpcode() == ARM::TCRETURNdi ||
1048+
MI->getOpcode() == ARM::TCRETURNri ||
1049+
MI->getOpcode() == ARM::TCRETURNrinotr12)
10501050
// LR may only be popped into PC, as part of return sequence.
10511051
// If this isn't the return sequence, we'll need emitPopSpecialFixUp
10521052
// to restore LR the hard way.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+pacbti< %s | FileCheck %s
2+
3+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
4+
target triple = "thumbv8.1m.main-m.main-unknown"
5+
6+
; When PACBTI is enabled, indirect tail-calls must not use R12 that is used
7+
; to store authentication code.
8+
9+
define void @pacbti_disabled(ptr %p) "sign-return-address"="none" {
10+
entry:
11+
tail call void %p()
12+
; CHECK: bx {{r0|r1|r2|r3|r12}}
13+
ret void
14+
}
15+
16+
define void @pacbti_enabled(ptr %p) "sign-return-address"="all" {
17+
entry:
18+
tail call void %p()
19+
; CHECK: bx {{r0|r1|r2|r3}}
20+
ret void
21+
}
22+
23+
define void @pacbti_disabled_force_r12(ptr %p) "sign-return-address"="none" {
24+
entry:
25+
%p_r12 = tail call ptr asm "", "={r12},{r12},~{lr}"(ptr %p)
26+
tail call void %p_r12()
27+
; CHECK: bx r12
28+
ret void
29+
}
30+
31+
define void @pacbti_enabled_force_r12(ptr %p) "sign-return-address"="all" {
32+
entry:
33+
%p_r12 = tail call ptr asm "", "={r12},{r12},~{lr}"(ptr %p)
34+
tail call void %p_r12()
35+
; CHECK: bx {{r0|r1|r2|r3}}
36+
ret void
37+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+pacbti< %s | FileCheck %s
2+
3+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
4+
target triple = "thumbv8.1m.main-m.main-unknown"
5+
6+
define dso_local void @sgign_return_address(ptr noundef readonly %fptr_arg) local_unnamed_addr #0 {
7+
entry:
8+
%0 = tail call ptr asm "", "={r12},{r12},~{lr}"(ptr %fptr_arg)
9+
tail call void %0()
10+
; CHECK: bx {{r0|r1|r2|r3}}
11+
ret void
12+
}
13+
14+
!llvm.module.flags = !{!1}
15+
16+
!1 = !{i32 8, !"sign-return-address", i32 1}
17+
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; RUN: llc -mtriple=thumbv8.1m.main-none-none-eabi -mattr=+pacbti< %s | FileCheck %s
2+
3+
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
4+
target triple = "thumbv8.1m.main-m.main-unknown"
5+
6+
define dso_local void @sgign_return_address_all(ptr noundef readonly %fptr_arg) local_unnamed_addr #0 {
7+
entry:
8+
%0 = tail call ptr asm "", "={r12},{r12},~{lr}"(ptr %fptr_arg)
9+
tail call void %0()
10+
; CHECK: bx {{r0|r1|r2|r3}}
11+
ret void
12+
}
13+
14+
!llvm.module.flags = !{!1}
15+
16+
!1 = !{i32 8, !"sign-return-address", i32 1}
17+
!2 = !{i32 8, !"sign-return-address-all", i32 1}
18+

0 commit comments

Comments
 (0)