Skip to content

Commit 1a23a99

Browse files
[clang] Define ptrauth_sign_constant builtin.
This is constant-expression equivalent to __builtin_ptrauth_sign, allowing its usage in global initializers, but requiring constant pointers and discriminators. Co-Authored-By: John McCall <[email protected]>
1 parent 61be7a9 commit 1a23a99

File tree

14 files changed

+360
-14
lines changed

14 files changed

+360
-14
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4393,6 +4393,12 @@ def PtrauthSignUnauthenticated : Builtin {
43934393
let Prototype = "void*(void*,int,void*)";
43944394
}
43954395

4396+
def PtrauthSignConstant : Builtin {
4397+
let Spellings = ["__builtin_ptrauth_sign_constant"];
4398+
let Attributes = [CustomTypeChecking, NoThrow, Const, Constexpr];
4399+
let Prototype = "void*(void*,int,void*)";
4400+
}
4401+
43964402
def PtrauthSignGenericData : Builtin {
43974403
let Spellings = ["__builtin_ptrauth_sign_generic_data"];
43984404
let Attributes = [CustomTypeChecking, NoThrow, Const];

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,13 @@ def err_ptrauth_value_bad_type :
922922
Error<"%select{signed value|extra discriminator|blended pointer|blended "
923923
"integer}0 must have %select{pointer|integer|pointer or integer}1 "
924924
"type; type here is %2">;
925+
def err_ptrauth_bad_constant_pointer :
926+
Error<"argument to ptrauth_sign_constant must refer to a global variable "
927+
"or function">;
928+
def err_ptrauth_bad_constant_discriminator :
929+
Error<"discriminator argument to ptrauth_sign_constant must be a constant "
930+
"integer, the address of the global variable where the result "
931+
"will be stored, or a blend of the two">;
925932
def warn_ptrauth_sign_null_pointer :
926933
Warning<"signing a null pointer will yield a non-null pointer">,
927934
InGroup<PtrAuthNullPointers>;

clang/include/clang/CodeGen/CodeGenABITypes.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ llvm::Type *convertTypeForMemory(CodeGenModule &CGM, QualType T);
104104
unsigned getLLVMFieldNumber(CodeGenModule &CGM,
105105
const RecordDecl *RD, const FieldDecl *FD);
106106

107+
/// Return a signed constant pointer.
108+
llvm::Constant *getConstantSignedPointer(CodeGenModule &CGM,
109+
llvm::Constant *pointer,
110+
unsigned key,
111+
llvm::Constant *storageAddress,
112+
llvm::Constant *otherDiscriminator);
107113
/// Given the language and code-generation options that Clang was configured
108114
/// with, set the default LLVM IR attributes for a function definition.
109115
/// The attributes set here are mostly global target-configuration and

clang/lib/AST/ExprConstant.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2042,6 +2042,7 @@ static bool IsNoOpCall(const CallExpr *E) {
20422042
unsigned Builtin = E->getBuiltinCallee();
20432043
return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||
20442044
Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||
2045+
Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||
20452046
Builtin == Builtin::BI__builtin_function_start);
20462047
}
20472048

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5273,6 +5273,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
52735273
case Builtin::BI__iso_volatile_store64:
52745274
return RValue::get(EmitISOVolatileStore(*this, E));
52755275

5276+
case Builtin::BI__builtin_ptrauth_sign_constant:
5277+
return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
5278+
52765279
case Builtin::BI__builtin_ptrauth_auth:
52775280
case Builtin::BI__builtin_ptrauth_auth_and_resign:
52785281
case Builtin::BI__builtin_ptrauth_blend_discriminator:

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1856,6 +1856,12 @@ class ConstantLValueEmitter : public ConstStmtVisitor<ConstantLValueEmitter,
18561856
ConstantLValue VisitMaterializeTemporaryExpr(
18571857
const MaterializeTemporaryExpr *E);
18581858

1859+
ConstantLValue emitPointerAuthSignConstant(const CallExpr *E);
1860+
llvm::Constant *emitPointerAuthPointer(const Expr *E);
1861+
unsigned emitPointerAuthKey(const Expr *E);
1862+
std::pair<llvm::Constant*, llvm::Constant*>
1863+
emitPointerAuthDiscriminator(const Expr *E);
1864+
18591865
bool hasNonZeroOffset() const {
18601866
return !Value.getLValueOffset().isZero();
18611867
}
@@ -2048,6 +2054,10 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
20482054
if (builtin == Builtin::BI__builtin_function_start)
20492055
return CGM.GetFunctionStart(
20502056
E->getArg(0)->getAsBuiltinConstantDeclRef(CGM.getContext()));
2057+
2058+
if (builtin == Builtin::BI__builtin_ptrauth_sign_constant)
2059+
return emitPointerAuthSignConstant(E);
2060+
20512061
if (builtin != Builtin::BI__builtin___CFStringMakeConstantString &&
20522062
builtin != Builtin::BI__builtin___NSStringMakeConstantString)
20532063
return nullptr;
@@ -2061,6 +2071,58 @@ ConstantLValueEmitter::VisitCallExpr(const CallExpr *E) {
20612071
}
20622072
}
20632073

2074+
ConstantLValue
2075+
ConstantLValueEmitter::emitPointerAuthSignConstant(const CallExpr *E) {
2076+
auto unsignedPointer = emitPointerAuthPointer(E->getArg(0));
2077+
auto key = emitPointerAuthKey(E->getArg(1));
2078+
llvm::Constant *storageAddress;
2079+
llvm::Constant *otherDiscriminator;
2080+
std::tie(storageAddress, otherDiscriminator) =
2081+
emitPointerAuthDiscriminator(E->getArg(2));
2082+
2083+
auto signedPointer =
2084+
CGM.getConstantSignedPointer(unsignedPointer, key, storageAddress,
2085+
otherDiscriminator);
2086+
return signedPointer;
2087+
}
2088+
2089+
llvm::Constant *ConstantLValueEmitter::emitPointerAuthPointer(const Expr *E) {
2090+
Expr::EvalResult result;
2091+
bool succeeded = E->EvaluateAsRValue(result, CGM.getContext());
2092+
assert(succeeded); (void) succeeded;
2093+
2094+
// The assertions here are all checked by Sema.
2095+
assert(result.Val.isLValue());
2096+
return ConstantEmitter(CGM, Emitter.CGF)
2097+
.emitAbstract(E->getExprLoc(), result.Val, E->getType());
2098+
}
2099+
2100+
unsigned ConstantLValueEmitter::emitPointerAuthKey(const Expr *E) {
2101+
return E->EvaluateKnownConstInt(CGM.getContext()).getZExtValue();
2102+
}
2103+
2104+
std::pair<llvm::Constant*, llvm::Constant*>
2105+
ConstantLValueEmitter::emitPointerAuthDiscriminator(const Expr *E) {
2106+
E = E->IgnoreParens();
2107+
2108+
if (auto call = dyn_cast<CallExpr>(E)) {
2109+
if (call->getBuiltinCallee() ==
2110+
Builtin::BI__builtin_ptrauth_blend_discriminator) {
2111+
auto pointer = ConstantEmitter(CGM).emitAbstract(call->getArg(0),
2112+
call->getArg(0)->getType());
2113+
auto extra = ConstantEmitter(CGM).emitAbstract(call->getArg(1),
2114+
call->getArg(1)->getType());
2115+
return { pointer, extra };
2116+
}
2117+
}
2118+
2119+
auto result = ConstantEmitter(CGM).emitAbstract(E, E->getType());
2120+
if (result->getType()->isPointerTy())
2121+
return { result, nullptr };
2122+
else
2123+
return { nullptr, result };
2124+
}
2125+
20642126
ConstantLValue
20652127
ConstantLValueEmitter::VisitBlockExpr(const BlockExpr *E) {
20662128
StringRef functionName;

clang/lib/CodeGen/CGPointerAuth.cpp

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This file contains common routines relating to the emission of
10+
// pointer authentication operations.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "CGCXXABI.h"
15+
#include "CGCall.h"
16+
#include "CodeGenFunction.h"
17+
#include "CodeGenModule.h"
18+
#include "clang/AST/Attr.h"
19+
#include "clang/Basic/PointerAuthOptions.h"
20+
#include "clang/CodeGen/CodeGenABITypes.h"
21+
#include "clang/CodeGen/ConstantInitBuilder.h"
22+
23+
#include "llvm/ADT/DenseMap.h"
24+
#include "llvm/IR/ValueMap.h"
25+
#include "llvm/Analysis/ValueTracking.h"
26+
#include <vector>
27+
28+
using namespace clang;
29+
using namespace CodeGen;
30+
31+
/// Build a signed-pointer "ptrauth" constant.
32+
static llvm::ConstantPtrAuth *
33+
buildConstantAddress(CodeGenModule &CGM, llvm::Constant *pointer, unsigned key,
34+
llvm::Constant *storageAddress,
35+
llvm::Constant *otherDiscriminator) {
36+
llvm::Constant *addressDiscriminator = nullptr;
37+
if (storageAddress) {
38+
addressDiscriminator = storageAddress;
39+
assert(storageAddress->getType() == CGM.UnqualPtrTy);
40+
} else {
41+
addressDiscriminator = llvm::Constant::getNullValue(CGM.UnqualPtrTy);
42+
}
43+
44+
llvm::ConstantInt *integerDiscriminator = nullptr;
45+
if (otherDiscriminator) {
46+
assert(otherDiscriminator->getType() == CGM.Int64Ty);
47+
integerDiscriminator = cast<llvm::ConstantInt>(otherDiscriminator);
48+
} else {
49+
integerDiscriminator = llvm::ConstantInt::get(CGM.Int64Ty, 0);
50+
}
51+
52+
return llvm::ConstantPtrAuth::get(
53+
pointer, llvm::ConstantInt::get(CGM.Int32Ty, key), integerDiscriminator,
54+
addressDiscriminator);
55+
}
56+
57+
llvm::Constant *
58+
CodeGenModule::getConstantSignedPointer(llvm::Constant *pointer,
59+
unsigned key,
60+
llvm::Constant *storageAddress,
61+
llvm::Constant *otherDiscriminator) {
62+
// Unique based on the underlying value, not a signing of it.
63+
auto stripped = pointer->stripPointerCasts();
64+
65+
// Build the constant.
66+
return buildConstantAddress(*this, stripped, key, storageAddress,
67+
otherDiscriminator);
68+
}
69+
70+
llvm::Constant *
71+
CodeGen::getConstantSignedPointer(CodeGenModule &CGM,
72+
llvm::Constant *pointer, unsigned key,
73+
llvm::Constant *storageAddress,
74+
llvm::Constant *otherDiscriminator) {
75+
return CGM.getConstantSignedPointer(pointer, key, storageAddress,
76+
otherDiscriminator);
77+
}

clang/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ add_clang_library(clangCodeGen
8989
CGOpenCLRuntime.cpp
9090
CGOpenMPRuntime.cpp
9191
CGOpenMPRuntimeGPU.cpp
92+
CGPointerAuth.cpp
9293
CGRecordLayoutBuilder.cpp
9394
CGStmt.cpp
9495
CGStmtOpenMP.cpp

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,11 @@ class CodeGenModule : public CodeGenTypeCache {
938938
// Return the function body address of the given function.
939939
llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
940940

941+
llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
942+
unsigned key,
943+
llvm::Constant *storageAddress,
944+
llvm::Constant *extraDiscrim);
945+
941946
// Return whether RTTI information should be emitted for this target.
942947
bool shouldEmitRTTI(bool ForEH = false) {
943948
return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice &&

clang/lib/Headers/ptrauth.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,30 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
7878
On arm64e, the integer must fall within the range of a uint16_t;
7979
other bits may be ignored.
8080
81+
For the purposes of ptrauth_sign_constant, the result of calling
82+
this function is considered a constant expression if the arguments
83+
are constant. Some restrictions may be imposed on the pointer.
84+
8185
The first argument must be an expression of pointer type.
8286
The second argument must be an expression of integer type.
8387
The result will have type uintptr_t. */
8488
#define ptrauth_blend_discriminator(__pointer, __integer) \
8589
__builtin_ptrauth_blend_discriminator(__pointer, __integer)
8690

91+
/* Add a signature to the given pointer value using a specific key,
92+
using the given extra data as a salt to the signing process.
93+
94+
The value must be a constant expression of pointer type.
95+
The key must be a constant expression of type ptrauth_key.
96+
The extra data must be a constant expression of pointer or integer type;
97+
if an integer, it will be coerced to ptrauth_extra_data_t.
98+
The result will have the same type as the original value.
99+
100+
This is a constant expression if the extra data is an integer or
101+
null pointer constant. */
102+
#define ptrauth_sign_constant(__value, __key, __data) \
103+
__builtin_ptrauth_sign_constant(__value, __key, __data)
104+
87105
/* Add a signature to the given pointer value using a specific key,
88106
using the given extra data as a salt to the signing process.
89107
@@ -183,6 +201,13 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
183201
((ptrauth_extra_data_t)0); \
184202
})
185203

204+
#define ptrauth_sign_constant(__value, __key, __data) \
205+
({ \
206+
(void)__key; \
207+
(void)__data; \
208+
__value; \
209+
})
210+
186211
#define ptrauth_sign_unauthenticated(__value, __key, __data) \
187212
({ \
188213
(void)__key; \

0 commit comments

Comments
 (0)