Skip to content

Commit c5cde09

Browse files
ahmedbougachaahatanakarjmccall
committed
[AArch64][PAC] Support and document ptrauth builtins and -fptrauth-intrinsics.
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 <[email protected]> Co-Authored-By: John McCall <[email protected]>
1 parent 82acec1 commit c5cde09

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
@@ -4244,6 +4245,10 @@ reordering of memory accesses and side effect instructions. Other instructions
42444245
like simple arithmetic may be reordered around the intrinsic. If you expect to
42454246
have no reordering at all, use inline assembly instead.
42464247
4248+
Pointer Authentication
4249+
^^^^^^^^^^^^^^^^^^^^^^
4250+
See :doc:`PointerAuthentication`.
4251+
42474252
X86/X86-64 Language Extensions
42484253
------------------------------
42494254

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
@@ -4324,6 +4324,43 @@ def CoroSuspend : CoroLangBuiltin {
43244324
let Prototype = "char(_Constant bool)";
43254325
}
43264326

4327+
// Pointer authentication builtins.
4328+
def PtrauthStrip : Builtin {
4329+
let Spellings = ["__builtin_ptrauth_strip"];
4330+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4331+
let Prototype = "void*(void*,int)";
4332+
}
4333+
4334+
def PtrauthBlendDiscriminator : Builtin {
4335+
let Spellings = ["__builtin_ptrauth_blend_discriminator"];
4336+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4337+
let Prototype = "size_t(void*,int)";
4338+
}
4339+
4340+
def PtrauthSignUnauthenticated : Builtin {
4341+
let Spellings = ["__builtin_ptrauth_sign_unauthenticated"];
4342+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4343+
let Prototype = "void*(void*,int,void*)";
4344+
}
4345+
4346+
def PtrauthSignGenericData : Builtin {
4347+
let Spellings = ["__builtin_ptrauth_sign_generic_data"];
4348+
let Attributes = [CustomTypeChecking, NoThrow, Const];
4349+
let Prototype = "size_t(void*,void*)";
4350+
}
4351+
4352+
def PtrauthAuthAndResign : Builtin {
4353+
let Spellings = ["__builtin_ptrauth_auth_and_resign"];
4354+
let Attributes = [CustomTypeChecking, NoThrow];
4355+
let Prototype = "void*(void*,int,void*,int,void*)";
4356+
}
4357+
4358+
def PtrauthAuth : Builtin {
4359+
let Spellings = ["__builtin_ptrauth_auth"];
4360+
let Attributes = [CustomTypeChecking, NoThrow];
4361+
let Prototype = "void*(void*,int,void*)";
4362+
}
4363+
43274364
// OpenCL v2.0 s6.13.16, s9.17.3.5 - Pipe functions.
43284365
// We need the generic prototype, since the packet type could be anything.
43294366
def ReadPipe : OCLPipeLangBuiltin {

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,6 +865,7 @@ def ZeroLengthArray : DiagGroup<"zero-length-array">;
865865
def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
866866
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
867867
def MisleadingIndentation : DiagGroup<"misleading-indentation">;
868+
def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">;
868869

869870
// This covers both the deprecated case (in C++98)
870871
// 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"
@@ -1549,6 +1550,11 @@ class TargetInfo : public TransferrableTargetInfo,
15491550
return getAddressSpaceMap()[(unsigned)AS];
15501551
}
15511552

1553+
/// Determine whether the given pointer-authentication key is valid.
1554+
///
1555+
/// The value has been coerced to type 'int'.
1556+
virtual bool validatePointerAuthKey(const llvm::APSInt &value) const;
1557+
15521558
/// Map from the address space field in builtin description strings to the
15531559
/// language address space.
15541560
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
@@ -4068,6 +4068,14 @@ defm strict_return : BoolFOption<"strict-return",
40684068
" of a non-void function as unreachable">,
40694069
PosFlag<SetTrue>>;
40704070

4071+
let Group = f_Group in {
4072+
let Visibility = [ClangOption,CC1Option] in {
4073+
def fptrauth_intrinsics : Flag<["-"], "fptrauth-intrinsics">,
4074+
HelpText<"Enable pointer authentication intrinsics">;
4075+
}
4076+
def fno_ptrauth_intrinsics : Flag<["-"], "fno-ptrauth-intrinsics">;
4077+
}
4078+
40714079
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
40724080
Visibility<[ClangOption, CC1Option]>,
40734081
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
@@ -3041,6 +3041,8 @@ class Sema final {
30413041
SourceLocation AtomicQualLoc = SourceLocation(),
30423042
SourceLocation UnalignedQualLoc = SourceLocation());
30433043

3044+
bool checkConstantPointerAuthKey(Expr *keyExpr, unsigned &key);
3045+
30443046
static bool adjustContextForLocalExternDecl(DeclContext *&DC);
30453047
void DiagnoseFunctionSpecifiers(const DeclSpec &DS);
30463048
NamedDecl *getShadowedDeclaration(const TypedefNameDecl *D,

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
@@ -5207,6 +5207,73 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
52075207
case Builtin::BI__iso_volatile_store64:
52085208
return RValue::get(EmitISOVolatileStore(*this, E));
52095209

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

clang/lib/Driver/ToolChains/Clang.cpp

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

7174+
if (Args.hasFlag(options::OPT_fptrauth_intrinsics,
7175+
options::OPT_fno_ptrauth_intrinsics, false))
7176+
CmdArgs.push_back("-fptrauth-intrinsics");
7177+
71747178
// -fsigned-bitfields is default, and clang doesn't yet support
71757179
// -funsigned-bitfields.
71767180
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
@@ -3288,6 +3288,17 @@ static void ParseAPINotesArgs(APINotesOptions &Opts, ArgList &Args,
32883288
Opts.ModuleSearchPaths.push_back(A->getValue());
32893289
}
32903290

3291+
static void GeneratePointerAuthArgs(const LangOptions &Opts,
3292+
ArgumentConsumer Consumer) {
3293+
if (Opts.PointerAuthIntrinsics)
3294+
GenerateArg(Consumer, OPT_fptrauth_intrinsics);
3295+
}
3296+
3297+
static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
3298+
DiagnosticsEngine &Diags) {
3299+
Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics);
3300+
}
3301+
32913302
/// Check if input file kind and language standard are compatible.
32923303
static bool IsInputCompatibleWithStandard(InputKind IK,
32933304
const LangStandard &S) {
@@ -4606,6 +4617,8 @@ bool CompilerInvocation::CreateFromArgsImpl(
46064617
Res.getFileSystemOpts().WorkingDir);
46074618
ParseAPINotesArgs(Res.getAPINotesOpts(), Args, Diags);
46084619

4620+
ParsePointerAuthArgs(LangOpts, Args, Diags);
4621+
46094622
ParseLangArgs(LangOpts, Args, DashX, T, Res.getPreprocessorOpts().Includes,
46104623
Diags);
46114624
if (Res.getFrontendOpts().ProgramAction == frontend::RewriteObjC)
@@ -4836,6 +4849,7 @@ void CompilerInvocationBase::generateCC1CommandLine(
48364849
GenerateTargetArgs(getTargetOpts(), Consumer);
48374850
GenerateHeaderSearchArgs(getHeaderSearchOpts(), Consumer);
48384851
GenerateAPINotesArgs(getAPINotesOpts(), Consumer);
4852+
GeneratePointerAuthArgs(getLangOpts(), Consumer);
48394853
GenerateLangArgs(getLangOpts(), Consumer, T, getFrontendOpts().DashX);
48404854
GenerateCodeGenArgs(getCodeGenOpts(), Consumer, T,
48414855
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
@@ -317,3 +317,8 @@ module opencl_c {
317317
header "opencl-c.h"
318318
header "opencl-c-base.h"
319319
}
320+
321+
module ptrauth {
322+
header "ptrauth.h"
323+
export *
324+
}

0 commit comments

Comments
 (0)