Skip to content

Commit 20bbad2

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 11e7dcc commit 20bbad2

File tree

14 files changed

+359
-14
lines changed

14 files changed

+359
-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
@@ -924,6 +924,13 @@ def err_ptrauth_value_bad_type :
924924
Error<"%select{signed value|extra discriminator|blended pointer|blended "
925925
"integer}0 must have %select{pointer|integer|pointer or integer}1 "
926926
"type; type here is %2">;
927+
def err_ptrauth_bad_constant_pointer :
928+
Error<"argument to ptrauth_sign_constant must refer to a global variable "
929+
"or function">;
930+
def err_ptrauth_bad_constant_discriminator :
931+
Error<"discriminator argument to ptrauth_sign_constant must be a constant "
932+
"integer, the address of the global variable where the result "
933+
"will be stored, or a blend of the two">;
927934
def warn_ptrauth_sign_null_pointer :
928935
Warning<"signing a null pointer will yield a non-null pointer">,
929936
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
@@ -5285,6 +5285,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
52855285
case Builtin::BI__iso_volatile_store64:
52865286
return RValue::get(EmitISOVolatileStore(*this, E));
52875287

5288+
case Builtin::BI__builtin_ptrauth_sign_constant:
5289+
return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
5290+
52885291
case Builtin::BI__builtin_ptrauth_auth:
52895292
case Builtin::BI__builtin_ptrauth_auth_and_resign:
52905293
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
@@ -937,6 +937,11 @@ class CodeGenModule : public CodeGenTypeCache {
937937
// Return the function body address of the given function.
938938
llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
939939

940+
llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer,
941+
unsigned key,
942+
llvm::Constant *storageAddress,
943+
llvm::Constant *extraDiscrim);
944+
940945
// Return whether RTTI information should be emitted for this target.
941946
bool shouldEmitRTTI(bool ForEH = false) {
942947
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
@@ -68,12 +68,30 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
6868
On arm64e, the integer must fall within the range of a uint16_t;
6969
other bits may be ignored.
7070
71+
For the purposes of ptrauth_sign_constant, the result of calling
72+
this function is considered a constant expression if the arguments
73+
are constant. Some restrictions may be imposed on the pointer.
74+
7175
The first argument must be an expression of pointer type.
7276
The second argument must be an expression of integer type.
7377
The result will have type uintptr_t. */
7478
#define ptrauth_blend_discriminator(__pointer, __integer) \
7579
__builtin_ptrauth_blend_discriminator(__pointer, __integer)
7680

81+
/* Add a signature to the given pointer value using a specific key,
82+
using the given extra data as a salt to the signing process.
83+
84+
The value must be a constant expression of pointer type.
85+
The key must be a constant expression of type ptrauth_key.
86+
The extra data must be a constant expression of pointer or integer type;
87+
if an integer, it will be coerced to ptrauth_extra_data_t.
88+
The result will have the same type as the original value.
89+
90+
This is a constant expression if the extra data is an integer or
91+
null pointer constant. */
92+
#define ptrauth_sign_constant(__value, __key, __data) \
93+
__builtin_ptrauth_sign_constant(__value, __key, __data)
94+
7795
/* Add a signature to the given pointer value using a specific key,
7896
using the given extra data as a salt to the signing process.
7997
@@ -175,6 +193,13 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
175193
((ptrauth_extra_data_t)0); \
176194
})
177195

196+
#define ptrauth_sign_constant(__value, __key, __data) \
197+
({ \
198+
(void)__key; \
199+
(void)__data; \
200+
__value; \
201+
})
202+
178203
#define ptrauth_sign_unauthenticated(__value, __key, __data) \
179204
({ \
180205
(void)__key; \

0 commit comments

Comments
 (0)