Skip to content

Commit adffb5b

Browse files
committed
[AArch64][PAC] Lower direct authenticated calls to ptrauth constants.
1 parent 507b0f6 commit adffb5b

File tree

5 files changed

+250
-8
lines changed

5 files changed

+250
-8
lines changed

llvm/lib/CodeGen/GlobalISel/CallLowering.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@ bool CallLowering::lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &CB,
149149
// Try looking through a bitcast from one function type to another.
150150
// Commonly happens with calls to objc_msgSend().
151151
const Value *CalleeV = CB.getCalledOperand()->stripPointerCasts();
152+
153+
// If IRTranslator chose to drop the ptrauth info, we can turn this into
154+
// a direct call.
155+
if (!PAI && CB.countOperandBundlesOfType(LLVMContext::OB_ptrauth)) {
156+
CalleeV = cast<ConstantPtrAuth>(CalleeV)->getPointer();
157+
assert(isa<Function>(CalleeV));
158+
}
159+
152160
if (const Function *F = dyn_cast<Function>(CalleeV)) {
153161
if (F->hasFnAttribute(Attribute::NonLazyBind)) {
154162
LLT Ty = getLLTForType(*F->getType(), DL);

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2649,17 +2649,24 @@ bool IRTranslator::translateCallBase(const CallBase &CB,
26492649
}
26502650

26512651
std::optional<CallLowering::PtrAuthInfo> PAI;
2652-
if (CB.countOperandBundlesOfType(LLVMContext::OB_ptrauth)) {
2652+
if (auto Bundle = CB.getOperandBundle(LLVMContext::OB_ptrauth)) {
26532653
// Functions should never be ptrauth-called directly.
26542654
assert(!CB.getCalledFunction() && "invalid direct ptrauth call");
26552655

2656-
auto PAB = CB.getOperandBundle("ptrauth");
2657-
const Value *Key = PAB->Inputs[0];
2658-
const Value *Discriminator = PAB->Inputs[1];
2659-
2660-
Register DiscReg = getOrCreateVReg(*Discriminator);
2661-
PAI = CallLowering::PtrAuthInfo{cast<ConstantInt>(Key)->getZExtValue(),
2662-
DiscReg};
2656+
const Value *Key = Bundle->Inputs[0];
2657+
const Value *Discriminator = Bundle->Inputs[1];
2658+
2659+
// Look through ptrauth constants to try to eliminate the matching bundle
2660+
// and turn this into a direct call with no ptrauth.
2661+
// CallLowering will use the raw pointer if it doesn't find the PAI.
2662+
auto *CalleeCPA = dyn_cast<ConstantPtrAuth>(CB.getCalledOperand());
2663+
if (!CalleeCPA || !isa<Function>(CalleeCPA->getPointer()) ||
2664+
!CalleeCPA->isKnownCompatibleWith(Key, Discriminator, *DL)) {
2665+
// If we can't make it direct, package the bundle into PAI.
2666+
Register DiscReg = getOrCreateVReg(*Discriminator);
2667+
PAI = CallLowering::PtrAuthInfo{cast<ConstantInt>(Key)->getZExtValue(),
2668+
DiscReg};
2669+
}
26632670
}
26642671

26652672
Register ConvergenceCtrlToken = 0;

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9374,6 +9374,14 @@ void SelectionDAGBuilder::LowerCallSiteWithPtrAuthBundle(
93749374
assert(Discriminator->getType()->isIntegerTy(64) &&
93759375
"Invalid ptrauth discriminator");
93769376

9377+
// Look through ptrauth constants to find the raw callee.
9378+
// Do a direct unauthenticated call if we found it and everything matches.
9379+
if (auto *CalleeCPA = dyn_cast<ConstantPtrAuth>(CalleeV))
9380+
if (CalleeCPA->isKnownCompatibleWith(Key, Discriminator,
9381+
DAG.getDataLayout()))
9382+
return LowerCallTo(CB, getValue(CalleeCPA->getPointer()), CB.isTailCall(),
9383+
CB.isMustTailCall(), EHPadBB);
9384+
93779385
// Functions should never be ptrauth-called directly.
93789386
assert(!isa<Function>(CalleeV) && "invalid direct ptrauth call");
93799387

llvm/test/CodeGen/AArch64/ptrauth-call.ll

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,138 @@ define i32 @test_tailcall_ib_arg_ind(ptr %arg0, i64 %arg1) #0 {
269269
ret i32 %tmp1
270270
}
271271

272+
; Test direct calls
273+
274+
define i32 @test_direct_call() #0 {
275+
; DARWIN-LABEL: test_direct_call:
276+
; DARWIN-NEXT: stp x29, x30, [sp, #-16]!
277+
; DARWIN-NEXT: bl _f
278+
; DARWIN-NEXT: ldp x29, x30, [sp], #16
279+
; DARWIN-NEXT: ret
280+
;
281+
; ELF-LABEL: test_direct_call:
282+
; ELF-NEXT: str x30, [sp, #-16]!
283+
; ELF-NEXT: bl f
284+
; ELF-NEXT: ldr x30, [sp], #16
285+
; ELF-NEXT: ret
286+
%tmp0 = call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 0, i64 42) ]
287+
ret i32 %tmp0
288+
}
289+
290+
define i32 @test_direct_tailcall(ptr %arg0) #0 {
291+
; DARWIN-LABEL: test_direct_tailcall:
292+
; DARWIN: b _f
293+
;
294+
; ELF-LABEL: test_direct_tailcall:
295+
; ELF-NEXT: b f
296+
%tmp0 = tail call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 0, i64 42) ]
297+
ret i32 %tmp0
298+
}
299+
300+
define i32 @test_direct_call_mismatch() #0 {
301+
; DARWIN-LABEL: test_direct_call_mismatch:
302+
; DARWIN-NEXT: stp x29, x30, [sp, #-16]!
303+
; DARWIN-NEXT: adrp x16, _f@GOTPAGE
304+
; DARWIN-NEXT: ldr x16, [x16, _f@GOTPAGEOFF]
305+
; DARWIN-NEXT: mov x17, #42
306+
; DARWIN-NEXT: pacia x16, x17
307+
; DARWIN-NEXT: mov x8, x16
308+
; DARWIN-NEXT: mov x17, #42
309+
; DARWIN-NEXT: blrab x8, x17
310+
; DARWIN-NEXT: ldp x29, x30, [sp], #16
311+
; DARWIN-NEXT: ret
312+
;
313+
; ELF-LABEL: test_direct_call_mismatch:
314+
; ELF-NEXT: str x30, [sp, #-16]!
315+
; ELF-NEXT: adrp x16, :got:f
316+
; ELF-NEXT: ldr x16, [x16, :got_lo12:f]
317+
; ELF-NEXT: mov x17, #42
318+
; ELF-NEXT: pacia x16, x17
319+
; ELF-NEXT: mov x8, x16
320+
; ELF-NEXT: mov x17, #42
321+
; ELF-NEXT: blrab x8, x17
322+
; ELF-NEXT: ldr x30, [sp], #16
323+
; ELF-NEXT: ret
324+
%tmp0 = call i32 ptrauth(ptr @f, i32 0, i64 42)() [ "ptrauth"(i32 1, i64 42) ]
325+
ret i32 %tmp0
326+
}
327+
328+
define i32 @test_direct_call_addr() #0 {
329+
; DARWIN-LABEL: test_direct_call_addr:
330+
; DARWIN-NEXT: stp x29, x30, [sp, #-16]!
331+
; DARWIN-NEXT: bl _f
332+
; DARWIN-NEXT: ldp x29, x30, [sp], #16
333+
; DARWIN-NEXT: ret
334+
;
335+
; ELF-LABEL: test_direct_call_addr:
336+
; ELF-NEXT: str x30, [sp, #-16]!
337+
; ELF-NEXT: bl f
338+
; ELF-NEXT: ldr x30, [sp], #16
339+
; ELF-NEXT: ret
340+
%tmp0 = call i32 ptrauth(ptr @f, i32 1, i64 0, ptr @f.ref.ib.0.addr)() [ "ptrauth"(i32 1, i64 ptrtoint (ptr @f.ref.ib.0.addr to i64)) ]
341+
ret i32 %tmp0
342+
}
343+
344+
define i32 @test_direct_call_addr_blend() #0 {
345+
; DARWIN-LABEL: test_direct_call_addr_blend:
346+
; DARWIN-NEXT: stp x29, x30, [sp, #-16]!
347+
; DARWIN-NEXT: bl _f
348+
; DARWIN-NEXT: ldp x29, x30, [sp], #16
349+
; DARWIN-NEXT: ret
350+
;
351+
; ELF-LABEL: test_direct_call_addr_blend:
352+
; ELF-NEXT: str x30, [sp, #-16]!
353+
; ELF-NEXT: bl f
354+
; ELF-NEXT: ldr x30, [sp], #16
355+
; ELF-NEXT: ret
356+
%tmp0 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr @f.ref.ib.42.addr to i64), i64 42)
357+
%tmp1 = call i32 ptrauth(ptr @f, i32 1, i64 42, ptr @f.ref.ib.42.addr)() [ "ptrauth"(i32 1, i64 %tmp0) ]
358+
ret i32 %tmp1
359+
}
360+
361+
define i32 @test_direct_call_addr_gep_different_index_types() #0 {
362+
; DARWIN-LABEL: test_direct_call_addr_gep_different_index_types:
363+
; DARWIN-NEXT: stp x29, x30, [sp, #-16]!
364+
; DARWIN-NEXT: bl _f
365+
; DARWIN-NEXT: ldp x29, x30, [sp], #16
366+
; DARWIN-NEXT: ret
367+
;
368+
; ELF-LABEL: test_direct_call_addr_gep_different_index_types:
369+
; ELF-NEXT: str x30, [sp, #-16]!
370+
; ELF-NEXT: bl f
371+
; ELF-NEXT: ldr x30, [sp], #16
372+
; ELF-NEXT: ret
373+
%tmp0 = call i32 ptrauth(ptr @f, i32 1, i64 0, ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.0.addr, i64 0, i32 0))() [ "ptrauth"(i32 1, i64 ptrtoint (ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.0.addr, i32 0, i32 0) to i64)) ]
374+
ret i32 %tmp0
375+
}
376+
377+
define i32 @test_direct_call_addr_blend_gep_different_index_types() #0 {
378+
; DARWIN-LABEL: test_direct_call_addr_blend_gep_different_index_types:
379+
; DARWIN-NEXT: stp x29, x30, [sp, #-16]!
380+
; DARWIN-NEXT: bl _f
381+
; DARWIN-NEXT: ldp x29, x30, [sp], #16
382+
; DARWIN-NEXT: ret
383+
;
384+
; ELF-LABEL: test_direct_call_addr_blend_gep_different_index_types:
385+
; ELF-NEXT: str x30, [sp, #-16]!
386+
; ELF-NEXT: bl f
387+
; ELF-NEXT: ldr x30, [sp], #16
388+
; ELF-NEXT: ret
389+
%tmp0 = call i64 @llvm.ptrauth.blend(i64 ptrtoint (ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.123.addr, i32 0, i32 0) to i64), i64 123)
390+
%tmp1 = call i32 ptrauth(ptr @f, i32 1, i64 123, ptr getelementptr ({ ptr }, ptr @f_struct.ref.ib.123.addr, i64 0, i32 0))() [ "ptrauth"(i32 1, i64 %tmp0) ]
391+
ret i32 %tmp1
392+
}
393+
394+
attributes #0 = { nounwind }
395+
396+
@f.ref.ib.42.addr = external global ptr
397+
@f.ref.ib.0.addr = external global ptr
398+
@f_struct.ref.ib.0.addr = external global ptr
399+
@f_struct.ref.ib.123.addr = external global ptr
400+
401+
declare void @f()
402+
403+
declare i64 @llvm.ptrauth.auth(i64, i32, i64)
404+
declare i64 @llvm.ptrauth.blend(i64, i64)
405+
272406
attributes #0 = { nounwind }

llvm/test/CodeGen/AArch64/ptrauth-invoke.ll

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,90 @@ continuebb:
9696
ret i32 %tmp0
9797
}
9898

99+
; DARWIN-LABEL: _test_invoke_ia_0_direct:
100+
; DARWIN-NEXT: [[FNBEGIN:L.*]]:
101+
; DARWIN-NEXT: .cfi_startproc
102+
; DARWIN-NEXT: .cfi_personality 155, ___gxx_personality_v0
103+
; DARWIN-NEXT: .cfi_lsda 16, [[EXCEPT:Lexception[0-9]+]]
104+
; DARWIN-NEXT: ; %bb.0:
105+
; DARWIN-NEXT: stp x20, x19, [sp, #-32]!
106+
; DARWIN-NEXT: stp x29, x30, [sp, #16]
107+
; DARWIN-NEXT: .cfi_def_cfa_offset 32
108+
; DARWIN-NEXT: .cfi_offset w30, -8
109+
; DARWIN-NEXT: .cfi_offset w29, -16
110+
; DARWIN-NEXT: .cfi_offset w19, -24
111+
; DARWIN-NEXT: .cfi_offset w20, -32
112+
; DARWIN-NEXT: [[PRECALL:L.*]]:
113+
; DARWIN-NEXT: bl _baz
114+
115+
; DARWIN-SDAG-NEXT: [[POSTCALL:L.*]]:
116+
; DARWIN-SDAG-NEXT: ; %bb.1:
117+
; DARWIN-SDAG-NEXT: mov x19, x0
118+
119+
; DARWIN-GISEL-NEXT: mov x19, x0
120+
; DARWIN-GISEL-NEXT: [[POSTCALL:L.*]]:
121+
122+
; DARWIN-NEXT: [[CALLBB:L.*]]:
123+
; DARWIN-NEXT: bl _foo
124+
; DARWIN-NEXT: mov x0, x19
125+
; DARWIN-NEXT: ldp x29, x30, [sp, #16]
126+
; DARWIN-NEXT: ldp x20, x19, [sp], #32
127+
; DARWIN-NEXT: ret
128+
; DARWIN-NEXT: [[LPADBB:LBB[0-9_]+]]:
129+
; DARWIN-NEXT: [[LPAD:L.*]]:
130+
; DARWIN-NEXT: mov w19, #-1
131+
; DARWIN-NEXT: b [[CALLBB]]
132+
133+
; ELF-LABEL: test_invoke_ia_0_direct:
134+
; ELF-NEXT: [[FNBEGIN:.L.*]]:
135+
; ELF-NEXT: .cfi_startproc
136+
; ELF-NEXT: .cfi_personality 156, DW.ref.__gxx_personality_v0
137+
; ELF-NEXT: .cfi_lsda 28, [[EXCEPT:.Lexception[0-9]+]]
138+
; ELF-NEXT: // %bb.0:
139+
; ELF-NEXT: stp x30, x19, [sp, #-16]!
140+
; ELF-NEXT: .cfi_def_cfa_offset 16
141+
; ELF-NEXT: .cfi_offset w19, -8
142+
; ELF-NEXT: .cfi_offset w30, -16
143+
; ELF-NEXT: [[PRECALL:.L.*]]:
144+
; ELF-NEXT: bl baz
145+
146+
; ELF-SDAG-NEXT: [[POSTCALL:.L.*]]:
147+
; ELF-SDAG-NEXT: // %bb.1:
148+
; ELF-SDAG-NEXT: mov w19, w0
149+
150+
; ELF-GISEL-NEXT: mov w19, w0
151+
; ELF-GISEL-NEXT: [[POSTCALL:.L.*]]:
152+
153+
; ELF-NEXT: [[CALLBB:.L.*]]:
154+
; ELF-NEXT: bl foo
155+
; ELF-NEXT: mov w0, w19
156+
; ELF-NEXT: ldp x30, x19, [sp], #16
157+
; ELF-NEXT: ret
158+
; ELF-NEXT: [[LPADBB:.LBB[0-9_]+]]:
159+
; ELF-NEXT: [[LPAD:.L.*]]:
160+
; ELF-NEXT: mov w19, #-1
161+
; ELF-NEXT: b [[CALLBB]]
162+
163+
; CHECK-LABEL: GCC_except_table{{.*}}:
164+
; CHECK-NEXT: [[EXCEPT]]:
165+
; CHECK: .uleb128 [[POSTCALL]]-[[PRECALL]] {{.*}} Call between [[PRECALL]] and [[POSTCALL]]
166+
; CHECK-NEXT: .uleb128 [[LPAD]]-[[FNBEGIN]] {{.*}} jumps to [[LPAD]]
167+
; CHECK-NEXT: .byte 0 {{.*}} On action: cleanup
168+
169+
define i32 @test_invoke_ia_0_direct() #0 personality ptr @__gxx_personality_v0 {
170+
%tmp0 = invoke i32 ptrauth (ptr @baz, i32 0)() [ "ptrauth"(i32 0, i64 0) ] to label %continuebb
171+
unwind label %unwindbb
172+
173+
unwindbb:
174+
%tmp1 = landingpad { ptr, i32 } cleanup
175+
call void @foo()
176+
ret i32 -1
177+
178+
continuebb:
179+
call void @foo()
180+
ret i32 %tmp0
181+
}
182+
99183
@_ZTIPKc = external constant ptr
100184
@hello_str = private unnamed_addr constant [6 x i8] c"hello\00", align 1
101185

@@ -265,6 +349,7 @@ continuebb:
265349

266350
declare void @foo()
267351
declare void @bar(ptr)
352+
declare i32 @baz()
268353

269354
declare i32 @__gxx_personality_v0(...)
270355
declare ptr @__cxa_allocate_exception(i64)

0 commit comments

Comments
 (0)