Skip to content

Commit 0e85001

Browse files
ahatanakrjmccall
authored andcommitted
[clang] Implement function pointer signing.
Co-Authored-By: John McCall <[email protected]>
1 parent 1a23a99 commit 0e85001

23 files changed

+633
-17
lines changed

clang/include/clang/Basic/CodeGenOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1414
#define LLVM_CLANG_BASIC_CODEGENOPTIONS_H
1515

16+
#include "clang/Basic/PointerAuthOptions.h"
1617
#include "clang/Basic/Sanitizers.h"
1718
#include "clang/Basic/XRayInstr.h"
1819
#include "llvm/ADT/FloatingPointMode.h"
@@ -388,6 +389,9 @@ class CodeGenOptions : public CodeGenOptionsBase {
388389

389390
std::vector<std::string> Reciprocals;
390391

392+
/// Configuration for pointer-signing.
393+
PointerAuthOptions PointerAuth;
394+
391395
/// The preferred width for auto-vectorization transforms. This is intended to
392396
/// override default transforms based on the width of the architected vector
393397
/// registers.

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,9 @@ def err_drv_omp_host_ir_file_not_found : Error<
351351
"target regions but cannot be found">;
352352
def err_drv_omp_host_target_not_supported : Error<
353353
"target '%0' is not a supported OpenMP host target">;
354+
def err_drv_ptrauth_not_supported : Error<
355+
"target '%0' does not support native pointer authentication">;
356+
354357
def err_drv_expecting_fopenmp_with_fopenmp_targets : Error<
355358
"'-fopenmp-targets' must be used in conjunction with a '-fopenmp' option "
356359
"compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">;

clang/include/clang/Basic/LangOptions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,8 @@ class LangOptionsBase {
346346
BKey
347347
};
348348

349+
using PointerAuthenticationMode = ::clang::PointerAuthenticationMode;
350+
349351
enum class ThreadModelKind {
350352
/// POSIX Threads.
351353
POSIX,

clang/include/clang/Basic/PointerAuthOptions.h

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,146 @@
1414
#ifndef LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
1515
#define LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H
1616

17+
#include "clang/Basic/LLVM.h"
18+
#include "clang/Basic/LangOptions.h"
19+
#include "llvm/Support/ErrorHandling.h"
20+
#include "llvm/Target/TargetOptions.h"
21+
#include <map>
22+
#include <memory>
23+
#include <string>
24+
#include <vector>
25+
1726
namespace clang {
1827

1928
constexpr unsigned PointerAuthKeyNone = -1;
2029

30+
class PointerAuthSchema {
31+
public:
32+
enum class Kind : unsigned {
33+
None,
34+
ARM8_3,
35+
};
36+
37+
/// Hardware pointer-signing keys in ARM8.3.
38+
///
39+
/// These values are the same used in ptrauth.h.
40+
enum class ARM8_3Key : unsigned {
41+
ASIA = 0,
42+
ASIB = 1,
43+
ASDA = 2,
44+
ASDB = 3
45+
};
46+
47+
/// Forms of extra discrimination.
48+
enum class Discrimination : unsigned {
49+
/// No additional discrimination.
50+
None,
51+
52+
/// Discriminate using a constant value.
53+
Constant,
54+
};
55+
56+
private:
57+
Kind TheKind : 2;
58+
unsigned IsAddressDiscriminated : 1;
59+
unsigned IsIsaPointer : 1;
60+
unsigned AuthenticatesNullValues : 1;
61+
PointerAuthenticationMode SelectedAuthenticationMode : 2;
62+
Discrimination DiscriminationKind : 2;
63+
unsigned Key : 4;
64+
unsigned ConstantDiscriminator : 16;
65+
66+
public:
67+
PointerAuthSchema() : TheKind(Kind::None) {}
68+
69+
PointerAuthSchema(
70+
ARM8_3Key Key, bool IsAddressDiscriminated,
71+
PointerAuthenticationMode AuthenticationMode,
72+
Discrimination OtherDiscrimination,
73+
std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt,
74+
bool IsIsaPointer = false, bool AuthenticatesNullValues = false)
75+
: TheKind(Kind::ARM8_3), IsAddressDiscriminated(IsAddressDiscriminated),
76+
IsIsaPointer(IsIsaPointer),
77+
AuthenticatesNullValues(AuthenticatesNullValues),
78+
SelectedAuthenticationMode(AuthenticationMode),
79+
DiscriminationKind(OtherDiscrimination), Key(unsigned(Key)) {
80+
assert((getOtherDiscrimination() != Discrimination::Constant ||
81+
ConstantDiscriminatorOrNone) &&
82+
"constant discrimination requires a constant!");
83+
if (ConstantDiscriminatorOrNone)
84+
ConstantDiscriminator = *ConstantDiscriminatorOrNone;
85+
}
86+
87+
PointerAuthSchema(
88+
ARM8_3Key Key, bool IsAddressDiscriminated,
89+
Discrimination OtherDiscrimination,
90+
std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt,
91+
bool IsIsaPointer = false, bool AuthenticatesNullValues = false)
92+
: PointerAuthSchema(Key, IsAddressDiscriminated,
93+
PointerAuthenticationMode::SignAndAuth,
94+
OtherDiscrimination, ConstantDiscriminatorOrNone,
95+
IsIsaPointer, AuthenticatesNullValues) {}
96+
97+
Kind getKind() const { return TheKind; }
98+
99+
explicit operator bool() const { return isEnabled(); }
100+
101+
bool isEnabled() const { return getKind() != Kind::None; }
102+
103+
bool isAddressDiscriminated() const {
104+
assert(getKind() != Kind::None);
105+
return IsAddressDiscriminated;
106+
}
107+
108+
bool isIsaPointer() const {
109+
assert(getKind() != Kind::None);
110+
return IsIsaPointer;
111+
}
112+
113+
bool authenticatesNullValues() const {
114+
assert(getKind() != Kind::None);
115+
return AuthenticatesNullValues;
116+
}
117+
118+
bool hasOtherDiscrimination() const {
119+
return getOtherDiscrimination() != Discrimination::None;
120+
}
121+
122+
Discrimination getOtherDiscrimination() const {
123+
assert(getKind() != Kind::None);
124+
return DiscriminationKind;
125+
}
126+
127+
uint16_t getConstantDiscrimination() const {
128+
assert(getOtherDiscrimination() == Discrimination::Constant);
129+
return (uint16_t)ConstantDiscriminator;
130+
}
131+
132+
unsigned getKey() const {
133+
switch (getKind()) {
134+
case Kind::None:
135+
llvm_unreachable("calling getKey() on disabled schema");
136+
case Kind::ARM8_3:
137+
return unsigned(getARM8_3Key());
138+
}
139+
llvm_unreachable("bad key kind");
140+
}
141+
142+
PointerAuthenticationMode getAuthenticationMode() const {
143+
return SelectedAuthenticationMode;
144+
}
145+
146+
ARM8_3Key getARM8_3Key() const {
147+
assert(getKind() == Kind::ARM8_3);
148+
return ARM8_3Key(Key);
149+
}
150+
};
151+
152+
struct PointerAuthOptions {
153+
/// The ABI for C function pointers.
154+
PointerAuthSchema FunctionPointers;
155+
};
156+
21157
} // end namespace clang
22158

23159
#endif

clang/include/clang/Frontend/CompilerInvocation.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@ class CompilerInvocation : public CompilerInvocationBase {
305305
/// executable), for finding the builtin compiler path.
306306
static std::string GetResourcesPath(const char *Argv0, void *MainAddr);
307307

308+
/// Populate \p Opts with the default set of pointer authentication-related
309+
/// options given \p LangOpts and \p Triple. Return true if defaults are
310+
/// available.
311+
///
312+
/// Note: This is intended to be used by tools which must be aware of
313+
/// pointer authentication-related code generation, e.g. lldb.
314+
static bool setDefaultPointerAuthOptions(PointerAuthOptions &Opts,
315+
const LangOptions &LangOpts,
316+
const llvm::Triple &Triple);
317+
308318
/// Retrieve a module hash string that is suitable for uniquely
309319
/// identifying the conditions under which the module was built.
310320
std::string getModuleHash() const;

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5999,8 +5999,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
59995999
// If this is a predefined lib function (e.g. malloc), emit the call
60006000
// using exactly the normal call path.
60016001
if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
6002-
return emitLibraryCall(
6003-
*this, FD, E, cast<llvm::Constant>(EmitScalarExpr(E->getCallee())));
6002+
return emitLibraryCall(*this, FD, E, CGM.getRawFunctionPointer(FD));
60046003

60056004
// Check that a call to a target specific builtin has the correct target
60066005
// features.

clang/lib/CodeGen/CGCall.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5677,6 +5677,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
56775677
!isa_and_nonnull<FunctionDecl>(TargetDecl))
56785678
EmitKCFIOperandBundle(ConcreteCallee, BundleList);
56795679

5680+
// Add the pointer-authentication bundle.
5681+
EmitPointerAuthOperandBundle(ConcreteCallee.getPointerAuthInfo(), BundleList);
5682+
56805683
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
56815684
if (FD->hasAttr<StrictFPAttr>())
56825685
// All calls within a strictfp function are marked strictfp

clang/lib/CodeGen/CGCall.h

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H
1515
#define LLVM_CLANG_LIB_CODEGEN_CGCALL_H
1616

17+
#include "CGPointerAuthInfo.h"
1718
#include "CGValue.h"
1819
#include "EHScopeStack.h"
1920
#include "clang/AST/ASTFwd.h"
@@ -69,6 +70,10 @@ class CGCallee {
6970
Last = Virtual
7071
};
7172

73+
struct OrdinaryInfoStorage {
74+
CGCalleeInfo AbstractInfo;
75+
CGPointerAuthInfo PointerAuthInfo;
76+
};
7277
struct BuiltinInfoStorage {
7378
const FunctionDecl *Decl;
7479
unsigned ID;
@@ -85,7 +90,7 @@ class CGCallee {
8590

8691
SpecialKind KindOrFunctionPointer;
8792
union {
88-
CGCalleeInfo AbstractInfo;
93+
OrdinaryInfoStorage OrdinaryInfo;
8994
BuiltinInfoStorage BuiltinInfo;
9095
PseudoDestructorInfoStorage PseudoDestructorInfo;
9196
VirtualInfoStorage VirtualInfo;
@@ -104,10 +109,13 @@ class CGCallee {
104109

105110
/// Construct a callee. Call this constructor directly when this
106111
/// isn't a direct call.
107-
CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr)
112+
CGCallee(
113+
const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr,
114+
const CGPointerAuthInfo &pointerAuthInfo = /*FIXME*/ CGPointerAuthInfo())
108115
: KindOrFunctionPointer(
109116
SpecialKind(reinterpret_cast<uintptr_t>(functionPtr))) {
110-
AbstractInfo = abstractInfo;
117+
OrdinaryInfo.AbstractInfo = abstractInfo;
118+
OrdinaryInfo.PointerAuthInfo = pointerAuthInfo;
111119
assert(functionPtr && "configuring callee without function pointer");
112120
assert(functionPtr->getType()->isPointerTy());
113121
}
@@ -128,12 +136,12 @@ class CGCallee {
128136

129137
static CGCallee forDirect(llvm::Constant *functionPtr,
130138
const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
131-
return CGCallee(abstractInfo, functionPtr);
139+
return CGCallee(abstractInfo, functionPtr, CGPointerAuthInfo());
132140
}
133141

134142
static CGCallee forDirect(llvm::FunctionCallee functionPtr,
135143
const CGCalleeInfo &abstractInfo = CGCalleeInfo()) {
136-
return CGCallee(abstractInfo, functionPtr.getCallee());
144+
return CGCallee(abstractInfo, functionPtr.getCallee(), CGPointerAuthInfo());
137145
}
138146

139147
static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr,
@@ -173,7 +181,11 @@ class CGCallee {
173181
if (isVirtual())
174182
return VirtualInfo.MD;
175183
assert(isOrdinary());
176-
return AbstractInfo;
184+
return OrdinaryInfo.AbstractInfo;
185+
}
186+
const CGPointerAuthInfo &getPointerAuthInfo() const {
187+
assert(isOrdinary());
188+
return OrdinaryInfo.PointerAuthInfo;
177189
}
178190
llvm::Value *getFunctionPointer() const {
179191
assert(isOrdinary());
@@ -184,6 +196,10 @@ class CGCallee {
184196
KindOrFunctionPointer =
185197
SpecialKind(reinterpret_cast<uintptr_t>(functionPtr));
186198
}
199+
void setPointerAuthInfo(CGPointerAuthInfo pointerAuth) {
200+
assert(isOrdinary());
201+
OrdinaryInfo.PointerAuthInfo = pointerAuth;
202+
}
187203

188204
bool isVirtual() const {
189205
return KindOrFunctionPointer == SpecialKind::Virtual;

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2850,22 +2850,22 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
28502850
return LV;
28512851
}
28522852

2853-
static llvm::Constant *EmitFunctionDeclPointer(CodeGenModule &CGM,
2854-
GlobalDecl GD) {
2853+
llvm::Constant *CodeGenModule::getRawFunctionPointer(GlobalDecl GD,
2854+
llvm::Type *Ty) {
28552855
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
28562856
if (FD->hasAttr<WeakRefAttr>()) {
2857-
ConstantAddress aliasee = CGM.GetWeakRefReference(FD);
2857+
ConstantAddress aliasee = GetWeakRefReference(FD);
28582858
return aliasee.getPointer();
28592859
}
28602860

2861-
llvm::Constant *V = CGM.GetAddrOfFunction(GD);
2861+
llvm::Constant *V = GetAddrOfFunction(GD, Ty);
28622862
return V;
28632863
}
28642864

28652865
static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, const Expr *E,
28662866
GlobalDecl GD) {
28672867
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
2868-
llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, GD);
2868+
llvm::Constant *V = CGF.CGM.getFunctionPointer(GD);
28692869
CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
28702870
return CGF.MakeAddrLValue(V, E->getType(), Alignment,
28712871
AlignmentSource::Decl);
@@ -5501,7 +5501,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
55015501
// name to make it clear it's not the actual builtin.
55025502
if (CGF.CurFn->getName() != FDInlineName &&
55035503
OnlyHasInlineBuiltinDeclaration(FD)) {
5504-
llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
5504+
llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
55055505
llvm::Function *Fn = llvm::cast<llvm::Function>(CalleePtr);
55065506
llvm::Module *M = Fn->getParent();
55075507
llvm::Function *Clone = M->getFunction(FDInlineName);
@@ -5524,7 +5524,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
55245524
return CGCallee::forBuiltin(builtinID, FD);
55255525
}
55265526

5527-
llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
5527+
llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
55285528
if (CGF.CGM.getLangOpts().CUDA && !CGF.CGM.getLangOpts().CUDAIsDevice &&
55295529
FD->hasAttr<CUDAGlobalAttr>())
55305530
CalleePtr = CGF.CGM.getCUDARuntime().getKernelStub(
@@ -5581,7 +5581,8 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) {
55815581
GD = GlobalDecl(VD);
55825582

55835583
CGCalleeInfo calleeInfo(functionType->getAs<FunctionProtoType>(), GD);
5584-
CGCallee callee(calleeInfo, calleePtr);
5584+
CGPointerAuthInfo pointerAuth = CGM.getFunctionPointerAuthInfo(functionType);
5585+
CGCallee callee(calleeInfo, calleePtr, pointerAuth);
55855586
return callee;
55865587
}
55875588

clang/lib/CodeGen/CGExprConstant.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1956,8 +1956,25 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
19561956
if (D->hasAttr<WeakRefAttr>())
19571957
return CGM.GetWeakRefReference(D).getPointer();
19581958

1959+
auto PtrAuthSign = [&](llvm::Constant *C) {
1960+
CGPointerAuthInfo AuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
1961+
1962+
if (AuthInfo) {
1963+
if (hasNonZeroOffset())
1964+
return ConstantLValue(nullptr);
1965+
1966+
C = applyOffset(C);
1967+
C = CGM.getConstantSignedPointer(
1968+
C, AuthInfo.getKey(), nullptr,
1969+
cast_or_null<llvm::Constant>(AuthInfo.getDiscriminator()));
1970+
return ConstantLValue(C, /*applied offset*/ true);
1971+
}
1972+
1973+
return ConstantLValue(C);
1974+
};
1975+
19591976
if (auto FD = dyn_cast<FunctionDecl>(D))
1960-
return CGM.GetAddrOfFunction(FD);
1977+
return PtrAuthSign(CGM.getRawFunctionPointer(FD));
19611978

19621979
if (auto VD = dyn_cast<VarDecl>(D)) {
19631980
// We can never refer to a variable with local storage.

0 commit comments

Comments
 (0)