Skip to content

Commit 0481f04

Browse files
ahmedbougachaahatanakarjmccall
authored
[AArch64][PAC] Support ptrauth builtins and -fptrauth-intrinsics. (llvm#65996)
This defines the basic set of pointer authentication clang builtins (provided in a new header, ptrauth.h), with diagnostics and IRGen support. The availability of the builtins is gated on a new flag, `-fptrauth-intrinsics`. Note that this only includes the basic intrinsics, and notably excludes `ptrauth_sign_constant`, `ptrauth_type_discriminator`, and `ptrauth_string_discriminator`, which need extra logic to be fully supported. This also introduces clang/docs/PointerAuthentication.rst, which describes the ptrauth model in general, in addition to these builtins. Co-Authored-By: Akira Hatanaka <ahatanaka@apple.com> Co-Authored-By: John McCall <rjmccall@apple.com>
1 parent 60fa2b0 commit 0481f04

25 files changed

+1294
-0
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Clang Language Extensions
1313
BlockLanguageSpec
1414
Block-ABI-Apple
1515
AutomaticReferenceCounting
16+
PointerAuthentication
1617
MatrixTypes
1718

1819
Introduction
@@ -4318,6 +4319,10 @@ reordering of memory accesses and side effect instructions. Other instructions
43184319
like simple arithmetic may be reordered around the intrinsic. If you expect to
43194320
have no reordering at all, use inline assembly instead.
43204321
4322+
Pointer Authentication
4323+
^^^^^^^^^^^^^^^^^^^^^^
4324+
See :doc:`PointerAuthentication`.
4325+
43214326
X86/X86-64 Language Extensions
43224327
------------------------------
43234328

clang/docs/PointerAuthentication.rst

Lines changed: 485 additions & 0 deletions
Large diffs are not rendered by default.

clang/include/clang/Basic/Builtins.td

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4354,6 +4354,43 @@ def CoroSuspend : CoroLangBuiltin {
43544354
let Prototype = "char(_Constant bool)";
43554355
}
43564356

4357+
// Pointer authentication builtins.
4358+
def PtrauthStrip : Builtin {
4359+
let Spellings = ["__builtin_ptrauth_strip"];
4360+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4361+
let Prototype = "void*(void*,int)";
4362+
}
4363+
4364+
def PtrauthBlendDiscriminator : Builtin {
4365+
let Spellings = ["__builtin_ptrauth_blend_discriminator"];
4366+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4367+
let Prototype = "size_t(void*,int)";
4368+
}
4369+
4370+
def PtrauthSignUnauthenticated : Builtin {
4371+
let Spellings = ["__builtin_ptrauth_sign_unauthenticated"];
4372+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4373+
let Prototype = "void*(void*,int,void*)";
4374+
}
4375+
4376+
def PtrauthSignGenericData : Builtin {
4377+
let Spellings = ["__builtin_ptrauth_sign_generic_data"];
4378+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4379+
let Prototype = "size_t(void*,void*)";
4380+
}
4381+
4382+
def PtrauthAuthAndResign : Builtin {
4383+
let Spellings = ["__builtin_ptrauth_auth_and_resign"];
4384+
let Attributes = [CustomTypeChecking, NoThrow];
4385+
let Prototype = "void*(void*,int,void*,int,void*)";
4386+
}
4387+
4388+
def PtrauthAuth : Builtin {
4389+
let Spellings = ["__builtin_ptrauth_auth"];
4390+
let Attributes = [CustomTypeChecking, NoThrow];
4391+
let Prototype = "void*(void*,int,void*)";
4392+
}
4393+
43574394
// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
43584395
// We need the generic prototype, since the packet type could be anything.
43594396
def ReadPipe : OCLPipeLangBuiltin {

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -875,6 +875,7 @@ def ZeroLengthArray : DiagGroup<"zero-length-array">;
875875
def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
876876
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
877877
def MisleadingIndentation : DiagGroup<"misleading-indentation">;
878+
def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">;
878879

879880
// This covers both the deprecated case (in C++98)
880881
// and the extension case (in C++11 onwards).

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,22 @@ def warn_fortify_scanf_overflow : Warning<
911911
def err_function_start_invalid_type: Error<
912912
"argument must be a function">;
913913

914+
def err_ptrauth_disabled :
915+
Error<"this target does not support pointer authentication">;
916+
def err_ptrauth_invalid_key :
917+
Error<"%0 does not identify a valid pointer authentication key for "
918+
"the current target">;
919+
def err_ptrauth_value_bad_type :
920+
Error<"%select{signed value|extra discriminator|blended pointer|blended "
921+
"integer}0 must have %select{pointer|integer|pointer or integer}1 "
922+
"type; type here is %2">;
923+
def warn_ptrauth_sign_null_pointer :
924+
Warning<"signing a null pointer will yield a non-null pointer">,
925+
InGroup<PtrAuthNullPointers>;
926+
def warn_ptrauth_auth_null_pointer :
927+
Warning<"authenticating a null pointer will almost certainly trap">,
928+
InGroup<PtrAuthNullPointers>;
929+
914930
/// main()
915931
// static main() is not an error in C, just in C++.
916932
def warn_static_main : Warning<"'main' should not be declared static">,

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ FEATURE(memory_sanitizer,
101101
FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread))
102102
FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow))
103103
FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo))
104+
FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics)
104105
FEATURE(swiftasynccc,
105106
PP.getTargetInfo().checkCallingConvention(CC_SwiftAsync) ==
106107
clang::TargetInfo::CCCR_OK)

clang/include/clang/Basic/LangOptions.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ LANGOPT(DllExportInlines , 1, 1, "dllexported classes dllexport inline methods"
161161
LANGOPT(RelaxedTemplateTemplateArgs, 1, 0, "C++17 relaxed matching of template template arguments")
162162
LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features")
163163

164+
LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
165+
164166
LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
165167

166168
COMPATIBLE_LANGOPT(RecoveryAST, 1, 1, "Preserve expressions in AST when encountering errors")

clang/include/clang/Basic/TargetInfo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "clang/Basic/TargetOptions.h"
2525
#include "llvm/ADT/APFloat.h"
2626
#include "llvm/ADT/APInt.h"
27+
#include "llvm/ADT/APSInt.h"
2728
#include "llvm/ADT/ArrayRef.h"
2829
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2930
#include "llvm/ADT/SmallSet.h"
@@ -1571,6 +1572,11 @@ class TargetInfo : public TransferrableTargetInfo,
15711572
return getAddressSpaceMap()[(unsigned)AS];
15721573
}
15731574

1575+
/// Determine whether the given pointer-authentication key is valid.
1576+
///
1577+
/// The value has been coerced to type 'int'.
1578+
virtual bool validatePointerAuthKey(const llvm::APSInt &value) const;
1579+
15741580
/// Map from the address space field in builtin description strings to the
15751581
/// language address space.
15761582
virtual LangAS getOpenCLBuiltinAddressSpace(unsigned AS) const {

clang/include/clang/Driver/Options.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4106,6 +4106,14 @@ defm strict_return : BoolFOption<"strict-return",
41064106
" of a non-void function as unreachable">,
41074107
PosFlag<SetTrue>>;
41084108

4109+
let Group = f_Group in {
4110+
let Visibility = [ClangOption,CC1Option] in {
4111+
def fptrauth_intrinsics : Flag<["-"], "fptrauth-intrinsics">,
4112+
HelpText<"Enable pointer authentication intrinsics">;
4113+
}
4114+
def fno_ptrauth_intrinsics : Flag<["-"], "fno-ptrauth-intrinsics">;
4115+
}
4116+
41094117
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
41104118
Visibility<[ClangOption, CC1Option]>,
41114119
HelpText<"Enable matrix data type and related builtin functions">,

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3060,6 +3060,8 @@ class Sema final {
30603060
TemplateIdAnnotation *TemplateId,
30613061
bool IsMemberSpecialization);
30623062

3063+
bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key);
3064+
30633065
void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
30643066
NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D,
30653067
const LookupResult &R);

clang/lib/Basic/TargetInfo.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,10 @@ bool TargetInfo::validateInputConstraint(
925925
return true;
926926
}
927927

928+
bool TargetInfo::validatePointerAuthKey(const llvm::APSInt &value) const {
929+
return false;
930+
}
931+
928932
void TargetInfo::CheckFixedPointBits() const {
929933
// Check that the number of fractional and integral bits (and maybe sign) can
930934
// fit into the bits given for a fixed point type.

clang/lib/Basic/Targets/AArch64.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clang/Basic/LangOptions.h"
1515
#include "clang/Basic/TargetBuiltins.h"
1616
#include "clang/Basic/TargetInfo.h"
17+
#include "llvm/ADT/APSInt.h"
1718
#include "llvm/ADT/ArrayRef.h"
1819
#include "llvm/ADT/StringExtras.h"
1920
#include "llvm/ADT/StringSwitch.h"
@@ -1450,6 +1451,11 @@ int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const {
14501451
return -1;
14511452
}
14521453

1454+
bool AArch64TargetInfo::validatePointerAuthKey(
1455+
const llvm::APSInt &value) const {
1456+
return 0 <= value && value <= 3;
1457+
}
1458+
14531459
bool AArch64TargetInfo::hasInt128Type() const { return true; }
14541460

14551461
AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple,

clang/lib/Basic/Targets/AArch64.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,8 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
195195

196196
int getEHDataRegisterNumber(unsigned RegNo) const override;
197197

198+
bool validatePointerAuthKey(const llvm::APSInt &value) const override;
199+
198200
const char *getBFloat16Mangling() const override { return "u6__bf16"; };
199201
bool hasInt128Type() const override;
200202

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5208,6 +5208,73 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
52085208
case Builtin::BI__iso_volatile_store64:
52095209
return RValue::get(EmitISOVolatileStore(*this, E));
52105210

5211+
case Builtin::BI__builtin_ptrauth_auth:
5212+
case Builtin::BI__builtin_ptrauth_auth_and_resign:
5213+
case Builtin::BI__builtin_ptrauth_blend_discriminator:
5214+
case Builtin::BI__builtin_ptrauth_sign_generic_data:
5215+
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
5216+
case Builtin::BI__builtin_ptrauth_strip: {
5217+
// Emit the arguments.
5218+
SmallVector<llvm::Value *, 5> Args;
5219+
for (auto argExpr : E->arguments())
5220+
Args.push_back(EmitScalarExpr(argExpr));
5221+
5222+
// Cast the value to intptr_t, saving its original type.
5223+
llvm::Type *OrigValueType = Args[0]->getType();
5224+
if (OrigValueType->isPointerTy())
5225+
Args[0] = Builder.CreatePtrToInt(Args[0], IntPtrTy);
5226+
5227+
switch (BuiltinID) {
5228+
case Builtin::BI__builtin_ptrauth_auth_and_resign:
5229+
if (Args[4]->getType()->isPointerTy())
5230+
Args[4] = Builder.CreatePtrToInt(Args[4], IntPtrTy);
5231+
LLVM_FALLTHROUGH;
5232+
5233+
case Builtin::BI__builtin_ptrauth_auth:
5234+
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
5235+
if (Args[2]->getType()->isPointerTy())
5236+
Args[2] = Builder.CreatePtrToInt(Args[2], IntPtrTy);
5237+
break;
5238+
5239+
case Builtin::BI__builtin_ptrauth_sign_generic_data:
5240+
if (Args[1]->getType()->isPointerTy())
5241+
Args[1] = Builder.CreatePtrToInt(Args[1], IntPtrTy);
5242+
break;
5243+
5244+
case Builtin::BI__builtin_ptrauth_blend_discriminator:
5245+
case Builtin::BI__builtin_ptrauth_strip:
5246+
break;
5247+
}
5248+
5249+
// Call the intrinsic.
5250+
auto IntrinsicID = [&]() -> unsigned {
5251+
switch (BuiltinID) {
5252+
case Builtin::BI__builtin_ptrauth_auth:
5253+
return llvm::Intrinsic::ptrauth_auth;
5254+
case Builtin::BI__builtin_ptrauth_auth_and_resign:
5255+
return llvm::Intrinsic::ptrauth_resign;
5256+
case Builtin::BI__builtin_ptrauth_blend_discriminator:
5257+
return llvm::Intrinsic::ptrauth_blend;
5258+
case Builtin::BI__builtin_ptrauth_sign_generic_data:
5259+
return llvm::Intrinsic::ptrauth_sign_generic;
5260+
case Builtin::BI__builtin_ptrauth_sign_unauthenticated:
5261+
return llvm::Intrinsic::ptrauth_sign;
5262+
case Builtin::BI__builtin_ptrauth_strip:
5263+
return llvm::Intrinsic::ptrauth_strip;
5264+
}
5265+
llvm_unreachable("bad ptrauth intrinsic");
5266+
}();
5267+
auto Intrinsic = CGM.getIntrinsic(IntrinsicID);
5268+
llvm::Value *Result = EmitRuntimeCall(Intrinsic, Args);
5269+
5270+
if (BuiltinID != Builtin::BI__builtin_ptrauth_sign_generic_data &&
5271+
BuiltinID != Builtin::BI__builtin_ptrauth_blend_discriminator &&
5272+
OrigValueType->isPointerTy()) {
5273+
Result = Builder.CreateIntToPtr(Result, OrigValueType);
5274+
}
5275+
return RValue::get(Result);
5276+
}
5277+
52115278
case Builtin::BI__exception_code:
52125279
case Builtin::BI_exception_code:
52135280
return RValue::get(EmitSEHExceptionCode());

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7199,6 +7199,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
71997199
// -fno-common is the default, set -fcommon only when that flag is set.
72007200
Args.addOptInFlag(CmdArgs, options::OPT_fcommon, options::OPT_fno_common);
72017201

7202+
if (Args.hasFlag(options::OPT_fptrauth_intrinsics,
7203+
options::OPT_fno_ptrauth_intrinsics, false))
7204+
CmdArgs.push_back("-fptrauth-intrinsics");
7205+
72027206
// -fsigned-bitfields is default, and clang doesn't yet support
72037207
// -funsigned-bitfields.
72047208
if (!Args.hasFlag(options::OPT_fsigned_bitfields,

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3293,6 +3293,17 @@ static void ParseAPINotesArgs(APINotesOptions &Opts, ArgList &Args,
32933293
Opts.ModuleSearchPaths.push_back(A->getValue());
32943294
}
32953295

3296+
static void GeneratePointerAuthArgs(const LangOptions &Opts,
3297+
ArgumentConsumer Consumer) {
3298+
if (Opts.PointerAuthIntrinsics)
3299+
GenerateArg(Consumer, OPT_fptrauth_intrinsics);
3300+
}
3301+
3302+
static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
3303+
DiagnosticsEngine &Diags) {
3304+
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
3305+
}
3306+
32963307
/// Check if input file kind and language standard are compatible.
32973308
static bool IsInputCompatibleWithStandard(InputKind IK,
32983309
const LangStandard &S) {
@@ -4613,6 +4624,8 @@ bool CompilerInvocation::CreateFromArgsImpl(
46134624
Res.getFileSystemOpts().WorkingDir);
46144625
ParseAPINotesArgs(Res.getAPINotesOpts(), Args, Diags);
46154626

4627+
ParsePointerAuthArgs(LangOpts, Args, Diags);
4628+
46164629
ParseLangArgs(LangOpts, Args, DashX, T, Res.getPreprocessorOpts().Includes,
46174630
Diags);
46184631
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
@@ -4843,6 +4856,7 @@ void CompilerInvocationBase::generateCC1CommandLine(
48434856
GenerateTargetArgs(getTargetOpts(), Consumer);
48444857
GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer);
48454858
GenerateAPINotesArgs(getAPINotesOpts(), Consumer);
4859+
GeneratePointerAuthArgs(getLangOpts(), Consumer);
48464860
GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX);
48474861
GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T,
48484862
getFrontendOpts().OutputFile, &getLangOpts());

clang/lib/Headers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ set(x86_files
214214
popcntintrin.h
215215
prfchiintrin.h
216216
prfchwintrin.h
217+
ptrauth.h
217218
ptwriteintrin.h
218219
raointintrin.h
219220
rdpruintrin.h

clang/lib/Headers/module.modulemap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,3 +315,8 @@ module opencl_c {
315315
header "opencl-c.h"
316316
header "opencl-c-base.h"
317317
}
318+
319+
module ptrauth {
320+
header "ptrauth.h"
321+
export *
322+
}

0 commit comments

Comments
 (0)