
Try to optimize a call to the result of a ptrauth intrinsic, potentially into the ptrauth call bundle: call(ptrauth.resign(p)), ["ptrauth"()] -> call p, ["ptrauth"()] call(ptrauth.sign(p)), ["ptrauth"()] -> call p as long as the key/discriminator are the same in sign and auth-bundle, and we don't change the key in the bundle (to a potentially-invalid key.) Generating a plain call to a raw unauthenticated pointer is generally undesirable, but if we ended up seeing a naked ptrauth.sign in the first place, we already have suspicious code. Unauthenticated calls are also easier to spot than naked signs, so let the indirect call shine. Note that there is an arguably unsafe extension to this, where we don't bother checking that the key in bundle and intrinsic are the same (and also allow folding away an auth into a bundle.) This can end up generating calls with a bundle that has an invalid key (which an informed frontend wouldn't have otherwise done), which can be problematic. The C that generates that is straightforward but arguably unreasonable. That wouldn't be an issue if we were to bite the bullet and make these fully AArch64-specific, allowing key knowledge to be embedded here.
143 lines
5.8 KiB
LLVM
143 lines
5.8 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
|
|
|
|
define i32 @test_ptrauth_call_sign(ptr %p) {
|
|
; CHECK-LABEL: @test_ptrauth_call_sign(
|
|
; CHECK-NEXT: [[V3:%.*]] = call i32 [[P:%.*]]()
|
|
; CHECK-NEXT: ret i32 [[V3]]
|
|
;
|
|
%v0 = ptrtoint ptr %p to i64
|
|
%v1 = call i64 @llvm.ptrauth.sign(i64 %v0, i32 2, i64 5678)
|
|
%v2 = inttoptr i64 %v1 to ptr
|
|
%v3 = call i32 %v2() [ "ptrauth"(i32 2, i64 5678) ]
|
|
ret i32 %v3
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_sign_otherbundle(ptr %p) {
|
|
; CHECK-LABEL: @test_ptrauth_call_sign_otherbundle(
|
|
; CHECK-NEXT: [[V3:%.*]] = call i32 [[P:%.*]]() [ "somebundle"(ptr null), "otherbundle"(i64 0) ]
|
|
; CHECK-NEXT: ret i32 [[V3]]
|
|
;
|
|
%v0 = ptrtoint ptr %p to i64
|
|
%v1 = call i64 @llvm.ptrauth.sign(i64 %v0, i32 2, i64 5678)
|
|
%v2 = inttoptr i64 %v1 to ptr
|
|
%v3 = call i32 %v2() [ "somebundle"(ptr null), "ptrauth"(i32 2, i64 5678), "otherbundle"(i64 0) ]
|
|
ret i32 %v3
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_resign(ptr %p) {
|
|
; CHECK-LABEL: @test_ptrauth_call_resign(
|
|
; CHECK-NEXT: [[V3:%.*]] = call i32 [[P:%.*]]() [ "ptrauth"(i32 1, i64 1234) ]
|
|
; CHECK-NEXT: ret i32 [[V3]]
|
|
;
|
|
%v0 = ptrtoint ptr %p to i64
|
|
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 1, i64 1234, i32 1, i64 5678)
|
|
%v2 = inttoptr i64 %v1 to ptr
|
|
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
|
|
ret i32 %v3
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_resign_blend(ptr %pp) {
|
|
; CHECK-LABEL: @test_ptrauth_call_resign_blend(
|
|
; CHECK-NEXT: [[V01:%.*]] = load ptr, ptr [[PP:%.*]], align 8
|
|
; CHECK-NEXT: [[V6:%.*]] = call i32 [[V01]]() [ "ptrauth"(i32 1, i64 1234) ]
|
|
; CHECK-NEXT: ret i32 [[V6]]
|
|
;
|
|
%v0 = load ptr, ptr %pp, align 8
|
|
%v1 = ptrtoint ptr %pp to i64
|
|
%v2 = ptrtoint ptr %v0 to i64
|
|
%v3 = call i64 @llvm.ptrauth.blend(i64 %v1, i64 5678)
|
|
%v4 = call i64 @llvm.ptrauth.resign(i64 %v2, i32 1, i64 1234, i32 1, i64 %v3)
|
|
%v5 = inttoptr i64 %v4 to ptr
|
|
%v6 = call i32 %v5() [ "ptrauth"(i32 1, i64 %v3) ]
|
|
ret i32 %v6
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_resign_blend_2(ptr %pp) {
|
|
; CHECK-LABEL: @test_ptrauth_call_resign_blend_2(
|
|
; CHECK-NEXT: [[V01:%.*]] = load ptr, ptr [[PP:%.*]], align 8
|
|
; CHECK-NEXT: [[V1:%.*]] = ptrtoint ptr [[PP]] to i64
|
|
; CHECK-NEXT: [[V3:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[V1]], i64 5678)
|
|
; CHECK-NEXT: [[V6:%.*]] = call i32 [[V01]]() [ "ptrauth"(i32 0, i64 [[V3]]) ]
|
|
; CHECK-NEXT: ret i32 [[V6]]
|
|
;
|
|
%v0 = load ptr, ptr %pp, align 8
|
|
%v1 = ptrtoint ptr %pp to i64
|
|
%v2 = ptrtoint ptr %v0 to i64
|
|
%v3 = call i64 @llvm.ptrauth.blend(i64 %v1, i64 5678)
|
|
%v4 = call i64 @llvm.ptrauth.resign(i64 %v2, i32 0, i64 %v3, i32 0, i64 1234)
|
|
%v5 = inttoptr i64 %v4 to ptr
|
|
%v6 = call i32 %v5() [ "ptrauth"(i32 0, i64 1234) ]
|
|
ret i32 %v6
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_resign_mismatch_key(ptr %p) {
|
|
; CHECK-LABEL: @test_ptrauth_call_resign_mismatch_key(
|
|
; CHECK-NEXT: [[V0:%.*]] = ptrtoint ptr [[P:%.*]] to i64
|
|
; CHECK-NEXT: [[V1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[V0]], i32 1, i64 1234, i32 0, i64 5678)
|
|
; CHECK-NEXT: [[V2:%.*]] = inttoptr i64 [[V1]] to ptr
|
|
; CHECK-NEXT: [[V3:%.*]] = call i32 [[V2]]() [ "ptrauth"(i32 1, i64 5678) ]
|
|
; CHECK-NEXT: ret i32 [[V3]]
|
|
;
|
|
%v0 = ptrtoint ptr %p to i64
|
|
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 1, i64 1234, i32 0, i64 5678)
|
|
%v2 = inttoptr i64 %v1 to ptr
|
|
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
|
|
ret i32 %v3
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_resign_mismatch_disc(ptr %p) {
|
|
; CHECK-LABEL: @test_ptrauth_call_resign_mismatch_disc(
|
|
; CHECK-NEXT: [[V0:%.*]] = ptrtoint ptr [[P:%.*]] to i64
|
|
; CHECK-NEXT: [[V1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[V0]], i32 1, i64 1234, i32 0, i64 9900)
|
|
; CHECK-NEXT: [[V2:%.*]] = inttoptr i64 [[V1]] to ptr
|
|
; CHECK-NEXT: [[V3:%.*]] = call i32 [[V2]]() [ "ptrauth"(i32 1, i64 5678) ]
|
|
; CHECK-NEXT: ret i32 [[V3]]
|
|
;
|
|
%v0 = ptrtoint ptr %p to i64
|
|
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 1, i64 1234, i32 0, i64 9900)
|
|
%v2 = inttoptr i64 %v1 to ptr
|
|
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
|
|
ret i32 %v3
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_resign_mismatch_blend(ptr %pp) {
|
|
; CHECK-LABEL: @test_ptrauth_call_resign_mismatch_blend(
|
|
; CHECK-NEXT: [[V0:%.*]] = load ptr, ptr [[PP:%.*]], align 8
|
|
; CHECK-NEXT: [[V1:%.*]] = ptrtoint ptr [[PP]] to i64
|
|
; CHECK-NEXT: [[V2:%.*]] = ptrtoint ptr [[V0]] to i64
|
|
; CHECK-NEXT: [[V6:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[V1]], i64 5678)
|
|
; CHECK-NEXT: [[V4:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[V2]], i32 1, i64 1234, i32 1, i64 [[V6]])
|
|
; CHECK-NEXT: [[V5:%.*]] = inttoptr i64 [[V4]] to ptr
|
|
; CHECK-NEXT: [[V3:%.*]] = call i32 [[V5]]() [ "ptrauth"(i32 1, i64 [[V1]]) ]
|
|
; CHECK-NEXT: ret i32 [[V3]]
|
|
;
|
|
%v0 = load ptr, ptr %pp, align 8
|
|
%v1 = ptrtoint ptr %pp to i64
|
|
%v2 = ptrtoint ptr %v0 to i64
|
|
%v3 = call i64 @llvm.ptrauth.blend(i64 %v1, i64 5678)
|
|
%v4 = call i64 @llvm.ptrauth.resign(i64 %v2, i32 1, i64 1234, i32 1, i64 %v3)
|
|
%v5 = inttoptr i64 %v4 to ptr
|
|
%v6 = call i32 %v5() [ "ptrauth"(i32 1, i64 %v1) ]
|
|
ret i32 %v6
|
|
}
|
|
|
|
define i32 @test_ptrauth_call_resign_changing_call_key(ptr %p) {
|
|
; CHECK-LABEL: @test_ptrauth_call_resign_changing_call_key(
|
|
; CHECK-NEXT: [[V0:%.*]] = ptrtoint ptr [[P:%.*]] to i64
|
|
; CHECK-NEXT: [[V1:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[V0]], i32 2, i64 1234, i32 1, i64 5678)
|
|
; CHECK-NEXT: [[V2:%.*]] = inttoptr i64 [[V1]] to ptr
|
|
; CHECK-NEXT: [[V3:%.*]] = call i32 [[V2]]() [ "ptrauth"(i32 1, i64 5678) ]
|
|
; CHECK-NEXT: ret i32 [[V3]]
|
|
;
|
|
%v0 = ptrtoint ptr %p to i64
|
|
%v1 = call i64 @llvm.ptrauth.resign(i64 %v0, i32 2, i64 1234, i32 1, i64 5678)
|
|
%v2 = inttoptr i64 %v1 to ptr
|
|
%v3 = call i32 %v2() [ "ptrauth"(i32 1, i64 5678) ]
|
|
ret i32 %v3
|
|
}
|
|
|
|
declare i64 @llvm.ptrauth.sign(i64, i32, i64)
|
|
declare i64 @llvm.ptrauth.resign(i64, i32, i64, i32, i64)
|
|
declare i64 @llvm.ptrauth.blend(i64, i64)
|