aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorAhmed Bougacha <ahmed@bougacha.org>2024-06-21 10:20:15 -0700
committerGitHub <noreply@github.com>2024-06-21 10:20:15 -0700
commite23250ecb7e09170e584db60375100790f39fac9 (patch)
treef5defecd713d2a564250fcc0bc4440341cd19380 /clang/lib
parentecf2a53407f517a261ee296e1f922c647a13a503 (diff)
downloadllvm-e23250ecb7e09170e584db60375100790f39fac9.zip
llvm-e23250ecb7e09170e584db60375100790f39fac9.tar.gz
llvm-e23250ecb7e09170e584db60375100790f39fac9.tar.bz2
[clang] Implement function pointer signing and authenticated function calls (#93906)
The functions are currently always signed/authenticated with zero discriminator. Co-Authored-By: John McCall <rjmccall@apple.com>
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/CodeGen/CGBuiltin.cpp3
-rw-r--r--clang/lib/CodeGen/CGCall.cpp3
-rw-r--r--clang/lib/CodeGen/CGCall.h24
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp17
-rw-r--r--clang/lib/CodeGen/CGExprConstant.cpp19
-rw-r--r--clang/lib/CodeGen/CGPointerAuth.cpp39
-rw-r--r--clang/lib/CodeGen/CGPointerAuthInfo.h99
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp21
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h4
-rw-r--r--clang/lib/CodeGen/CodeGenModule.h20
-rw-r--r--clang/lib/Frontend/CompilerInvocation.cpp26
-rw-r--r--clang/lib/Headers/ptrauth.h34
12 files changed, 294 insertions, 15 deletions
diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index 2516ed4..d11e7a9 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -6015,8 +6015,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
// If this is a predefined lib function (e.g. malloc), emit the call
// using exactly the normal call path.
if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID))
- return emitLibraryCall(
- *this, FD, E, cast<llvm::Constant>(EmitScalarExpr(E->getCallee())));
+ return emitLibraryCall(*this, FD, E, CGM.getRawFunctionPointer(FD));
// Check that a call to a target specific builtin has the correct target
// features.
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index a071b16..2b30113 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5678,6 +5678,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
!isa_and_nonnull<FunctionDecl>(TargetDecl))
EmitKCFIOperandBundle(ConcreteCallee, BundleList);
+ // Add the pointer-authentication bundle.
+ EmitPointerAuthOperandBundle(ConcreteCallee.getPointerAuthInfo(), BundleList);
+
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl))
if (FD->hasAttr<StrictFPAttr>())
// All calls within a strictfp function are marked strictfp
diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h
index 6b676ac..412b44a 100644
--- a/clang/lib/CodeGen/CGCall.h
+++ b/clang/lib/CodeGen/CGCall.h
@@ -14,6 +14,7 @@
#ifndef LLVM_CLANG_LIB_CODEGEN_CGCALL_H
#define LLVM_CLANG_LIB_CODEGEN_CGCALL_H
+#include "CGPointerAuthInfo.h"
#include "CGValue.h"
#include "EHScopeStack.h"
#include "clang/AST/ASTFwd.h"
@@ -69,6 +70,10 @@ class CGCallee {
Last = Virtual
};
+ struct OrdinaryInfoStorage {
+ CGCalleeInfo AbstractInfo;
+ CGPointerAuthInfo PointerAuthInfo;
+ };
struct BuiltinInfoStorage {
const FunctionDecl *Decl;
unsigned ID;
@@ -85,7 +90,7 @@ class CGCallee {
SpecialKind KindOrFunctionPointer;
union {
- CGCalleeInfo AbstractInfo;
+ OrdinaryInfoStorage OrdinaryInfo;
BuiltinInfoStorage BuiltinInfo;
PseudoDestructorInfoStorage PseudoDestructorInfo;
VirtualInfoStorage VirtualInfo;
@@ -104,10 +109,13 @@ public:
/// Construct a callee. Call this constructor directly when this
/// isn't a direct call.
- CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr)
+ CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr,
+ /* FIXME: make parameter pointerAuthInfo mandatory */
+ const CGPointerAuthInfo &pointerAuthInfo = CGPointerAuthInfo())
: KindOrFunctionPointer(
SpecialKind(reinterpret_cast<uintptr_t>(functionPtr))) {
- AbstractInfo = abstractInfo;
+ OrdinaryInfo.AbstractInfo = abstractInfo;
+ OrdinaryInfo.PointerAuthInfo = pointerAuthInfo;
assert(functionPtr && "configuring callee without function pointer");
assert(functionPtr->getType()->isPointerTy());
}
@@ -173,7 +181,11 @@ public:
if (isVirtual())
return VirtualInfo.MD;
assert(isOrdinary());
- return AbstractInfo;
+ return OrdinaryInfo.AbstractInfo;
+ }
+ const CGPointerAuthInfo &getPointerAuthInfo() const {
+ assert(isOrdinary());
+ return OrdinaryInfo.PointerAuthInfo;
}
llvm::Value *getFunctionPointer() const {
assert(isOrdinary());
@@ -184,6 +196,10 @@ public:
KindOrFunctionPointer =
SpecialKind(reinterpret_cast<uintptr_t>(functionPtr));
}
+ void setPointerAuthInfo(CGPointerAuthInfo PointerAuth) {
+ assert(isOrdinary());
+ OrdinaryInfo.PointerAuthInfo = PointerAuth;
+ }
bool isVirtual() const {
return KindOrFunctionPointer == SpecialKind::Virtual;
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 3dfe5e0..534f46d 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2856,22 +2856,22 @@ static LValue EmitGlobalVarDeclLValue(CodeGenFunction &CGF,
return LV;
}
-static llvm::Constant *EmitFunctionDeclPointer(CodeGenModule &CGM,
- GlobalDecl GD) {
+llvm::Constant *CodeGenModule::getRawFunctionPointer(GlobalDecl GD,
+ llvm::Type *Ty) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
if (FD->hasAttr<WeakRefAttr>()) {
- ConstantAddress aliasee = CGM.GetWeakRefReference(FD);
+ ConstantAddress aliasee = GetWeakRefReference(FD);
return aliasee.getPointer();
}
- llvm::Constant *V = CGM.GetAddrOfFunction(GD);
+ llvm::Constant *V = GetAddrOfFunction(GD, Ty);
return V;
}
static LValue EmitFunctionDeclLValue(CodeGenFunction &CGF, const Expr *E,
GlobalDecl GD) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
- llvm::Value *V = EmitFunctionDeclPointer(CGF.CGM, GD);
+ llvm::Constant *V = CGF.CGM.getFunctionPointer(GD);
CharUnits Alignment = CGF.getContext().getDeclAlign(FD);
return CGF.MakeAddrLValue(V, E->getType(), Alignment,
AlignmentSource::Decl);
@@ -5506,7 +5506,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
// name to make it clear it's not the actual builtin.
if (CGF.CurFn->getName() != FDInlineName &&
OnlyHasInlineBuiltinDeclaration(FD)) {
- llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
+ llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
llvm::Function *Fn = llvm::cast<llvm::Function>(CalleePtr);
llvm::Module *M = Fn->getParent();
llvm::Function *Clone = M->getFunction(FDInlineName);
@@ -5529,7 +5529,7 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
return CGCallee::forBuiltin(builtinID, FD);
}
- llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
+ llvm::Constant *CalleePtr = CGF.CGM.getRawFunctionPointer(GD);
if (CGF.CGM.getLangOpts().CUDA && !CGF.CGM.getLangOpts().CUDAIsDevice &&
FD->hasAttr<CUDAGlobalAttr>())
CalleePtr = CGF.CGM.getCUDARuntime().getKernelStub(
@@ -5586,7 +5586,8 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) {
GD = GlobalDecl(VD);
CGCalleeInfo calleeInfo(functionType->getAs<FunctionProtoType>(), GD);
- CGCallee callee(calleeInfo, calleePtr);
+ CGPointerAuthInfo pointerAuth = CGM.getFunctionPointerAuthInfo(functionType);
+ CGCallee callee(calleeInfo, calleePtr, pointerAuth);
return callee;
}
diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp
index bc5f42d..dffb8ce 100644
--- a/clang/lib/CodeGen/CGExprConstant.cpp
+++ b/clang/lib/CodeGen/CGExprConstant.cpp
@@ -2024,8 +2024,25 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) {
if (D->hasAttr<WeakRefAttr>())
return CGM.GetWeakRefReference(D).getPointer();
+ auto PtrAuthSign = [&](llvm::Constant *C) {
+ CGPointerAuthInfo AuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
+
+ if (AuthInfo) {
+ if (hasNonZeroOffset())
+ return ConstantLValue(nullptr);
+
+ C = applyOffset(C);
+ C = CGM.getConstantSignedPointer(
+ C, AuthInfo.getKey(), nullptr,
+ cast_or_null<llvm::ConstantInt>(AuthInfo.getDiscriminator()));
+ return ConstantLValue(C, /*applied offset*/ true);
+ }
+
+ return ConstantLValue(C);
+ };
+
if (auto FD = dyn_cast<FunctionDecl>(D))
- return CGM.GetAddrOfFunction(FD);
+ return PtrAuthSign(CGM.getRawFunctionPointer(FD));
if (auto VD = dyn_cast<VarDecl>(D)) {
// We can never refer to a variable with local storage.
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp
index e1fb0bd..f0819b0 100644
--- a/clang/lib/CodeGen/CGPointerAuth.cpp
+++ b/clang/lib/CodeGen/CGPointerAuth.cpp
@@ -17,6 +17,24 @@
using namespace clang;
using namespace CodeGen;
+/// Return the abstract pointer authentication schema for a pointer to the given
+/// function type.
+CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {
+ const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;
+ if (!Schema)
+ return CGPointerAuthInfo();
+
+ assert(!Schema.isAddressDiscriminated() &&
+ "function pointers cannot use address-specific discrimination");
+
+ assert(!Schema.hasOtherDiscrimination() &&
+ "function pointers don't support any discrimination yet");
+
+ return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
+ /*IsaPointer=*/false, /*AuthenticatesNull=*/false,
+ /*Discriminator=*/nullptr);
+}
+
llvm::Constant *
CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
llvm::Constant *StorageAddress,
@@ -41,3 +59,24 @@ CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
llvm::ConstantInt::get(Int32Ty, Key),
IntegerDiscriminator, AddressDiscriminator);
}
+
+llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
+ QualType FunctionType) {
+ assert(FunctionType->isFunctionType() ||
+ FunctionType->isFunctionReferenceType() ||
+ FunctionType->isFunctionPointerType());
+
+ if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType))
+ return getConstantSignedPointer(
+ Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr,
+ cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));
+
+ return Pointer;
+}
+
+llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
+ llvm::Type *Ty) {
+ const auto *FD = cast<FunctionDecl>(GD.getDecl());
+ QualType FuncType = FD->getType();
+ return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);
+}
diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h
new file mode 100644
index 0000000..0a0c11f
--- /dev/null
+++ b/clang/lib/CodeGen/CGPointerAuthInfo.h
@@ -0,0 +1,99 @@
+//===----- CGPointerAuthInfo.h - -------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Pointer auth info class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_CODEGEN_CGPOINTERAUTHINFO_H
+#define LLVM_CLANG_LIB_CODEGEN_CGPOINTERAUTHINFO_H
+
+#include "clang/AST/Type.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/IR/Type.h"
+#include "llvm/IR/Value.h"
+
+namespace clang {
+namespace CodeGen {
+
+class CGPointerAuthInfo {
+private:
+ PointerAuthenticationMode AuthenticationMode : 2;
+ unsigned IsIsaPointer : 1;
+ unsigned AuthenticatesNullValues : 1;
+ unsigned Key : 2;
+ llvm::Value *Discriminator;
+
+public:
+ CGPointerAuthInfo()
+ : AuthenticationMode(PointerAuthenticationMode::None),
+ IsIsaPointer(false), AuthenticatesNullValues(false), Key(0),
+ Discriminator(nullptr) {}
+ CGPointerAuthInfo(unsigned Key, PointerAuthenticationMode AuthenticationMode,
+ bool IsIsaPointer, bool AuthenticatesNullValues,
+ llvm::Value *Discriminator)
+ : AuthenticationMode(AuthenticationMode), IsIsaPointer(IsIsaPointer),
+ AuthenticatesNullValues(AuthenticatesNullValues), Key(Key),
+ Discriminator(Discriminator) {
+ assert(!Discriminator || Discriminator->getType()->isIntegerTy() ||
+ Discriminator->getType()->isPointerTy());
+ }
+
+ explicit operator bool() const { return isSigned(); }
+
+ bool isSigned() const {
+ return AuthenticationMode != PointerAuthenticationMode::None;
+ }
+
+ unsigned getKey() const {
+ assert(isSigned());
+ return Key;
+ }
+ llvm::Value *getDiscriminator() const {
+ assert(isSigned());
+ return Discriminator;
+ }
+
+ PointerAuthenticationMode getAuthenticationMode() const {
+ return AuthenticationMode;
+ }
+
+ bool isIsaPointer() const { return IsIsaPointer; }
+
+ bool authenticatesNullValues() const { return AuthenticatesNullValues; }
+
+ bool shouldStrip() const {
+ return AuthenticationMode == PointerAuthenticationMode::Strip ||
+ AuthenticationMode == PointerAuthenticationMode::SignAndStrip;
+ }
+
+ bool shouldSign() const {
+ return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
+ AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
+ }
+
+ bool shouldAuth() const {
+ return AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
+ }
+
+ friend bool operator!=(const CGPointerAuthInfo &LHS,
+ const CGPointerAuthInfo &RHS) {
+ return LHS.Key != RHS.Key || LHS.Discriminator != RHS.Discriminator ||
+ LHS.AuthenticationMode != RHS.AuthenticationMode;
+ }
+
+ friend bool operator==(const CGPointerAuthInfo &LHS,
+ const CGPointerAuthInfo &RHS) {
+ return !(LHS != RHS);
+ }
+};
+
+} // end namespace CodeGen
+} // end namespace clang
+
+#endif
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 200c40d..650c566 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -861,6 +861,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy,
FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass)
SanOpts.Mask &= ~SanitizerKind::Null;
+ // Add pointer authentication attributes.
+ const CodeGenOptions &CodeGenOpts = CGM.getCodeGenOpts();
+ if (CodeGenOpts.PointerAuth.FunctionPointers)
+ Fn->addFnAttr("ptrauth-calls");
+
// Apply xray attributes to the function (as a string, for now)
bool AlwaysXRayAttr = false;
if (const auto *XRayAttr = D ? D->getAttr<XRayInstrumentAttr>() : nullptr) {
@@ -3042,3 +3047,19 @@ llvm::Value *CodeGenFunction::emitBoolVecConversion(llvm::Value *SrcVec,
return Builder.CreateShuffleVector(SrcVec, ShuffleMask, Name);
}
+
+void CodeGenFunction::EmitPointerAuthOperandBundle(
+ const CGPointerAuthInfo &PointerAuth,
+ SmallVectorImpl<llvm::OperandBundleDef> &Bundles) {
+ if (!PointerAuth.isSigned())
+ return;
+
+ auto *Key = Builder.getInt32(PointerAuth.getKey());
+
+ llvm::Value *Discriminator = PointerAuth.getDiscriminator();
+ if (!Discriminator)
+ Discriminator = Builder.getSize(0);
+
+ llvm::Value *Args[] = {Key, Discriminator};
+ Bundles.emplace_back("ptrauth", Args);
+}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index cdb5ae66..a9c497b 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4417,6 +4417,10 @@ public:
bool isPointerKnownNonNull(const Expr *E);
+ void EmitPointerAuthOperandBundle(
+ const CGPointerAuthInfo &Info,
+ SmallVectorImpl<llvm::OperandBundleDef> &Bundles);
+
// Return the copy constructor name with the prefix "__copy_constructor_"
// removed.
static std::string getNonTrivialCopyConstructorStr(QualType QT,
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index 04e1a39..99133047 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -69,6 +69,7 @@ class Expr;
class Stmt;
class StringLiteral;
class NamedDecl;
+class PointerAuthSchema;
class ValueDecl;
class VarDecl;
class LangOptions;
@@ -937,6 +938,25 @@ public:
// Return the function body address of the given function.
llvm::Constant *GetFunctionStart(const ValueDecl *Decl);
+ /// Return a function pointer for a reference to the given function.
+ /// This correctly handles weak references, but does not apply a
+ /// pointer signature.
+ llvm::Constant *getRawFunctionPointer(GlobalDecl GD,
+ llvm::Type *Ty = nullptr);
+
+ /// Return the ABI-correct function pointer value for a reference
+ /// to the given function. This will apply a pointer signature if
+ /// necessary, caching the result for the given function.
+ llvm::Constant *getFunctionPointer(GlobalDecl GD, llvm::Type *Ty = nullptr);
+
+ /// Return the ABI-correct function pointer value for a reference
+ /// to the given function. This will apply a pointer signature if
+ /// necessary.
+ llvm::Constant *getFunctionPointer(llvm::Constant *Pointer,
+ QualType FunctionType);
+
+ CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T);
+
llvm::Constant *
getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
llvm::Constant *StorageAddress,
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index cde4a84..a6d9f42 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1458,6 +1458,29 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts,
Opts.setProfileUse(CodeGenOptions::ProfileClangInstr);
}
+void CompilerInvocation::setDefaultPointerAuthOptions(
+ PointerAuthOptions &Opts, const LangOptions &LangOpts,
+ const llvm::Triple &Triple) {
+ assert(Triple.getArch() == llvm::Triple::aarch64);
+ if (LangOpts.PointerAuthCalls) {
+ using Key = PointerAuthSchema::ARM8_3Key;
+ using Discrimination = PointerAuthSchema::Discrimination;
+ // If you change anything here, be sure to update <ptrauth.h>.
+ Opts.FunctionPointers =
+ PointerAuthSchema(Key::ASIA, false, Discrimination::None);
+ }
+}
+
+static void parsePointerAuthOptions(PointerAuthOptions &Opts,
+ const LangOptions &LangOpts,
+ const llvm::Triple &Triple,
+ DiagnosticsEngine &Diags) {
+ if (!LangOpts.PointerAuthCalls)
+ return;
+
+ CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple);
+}
+
void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts,
ArgumentConsumer Consumer,
const llvm::Triple &T,
@@ -2153,6 +2176,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args,
Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true);
+ if (!LangOpts->CUDAIsDevice)
+ parsePointerAuthOptions(Opts.PointerAuth, *LangOpts, T, Diags);
+
if (Args.hasArg(options::OPT_ffinite_loops))
Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always;
else if (Args.hasArg(options::OPT_fno_finite_loops))
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index 6aad9ef..1a4bd02 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -28,6 +28,12 @@ typedef enum {
/* A process-specific key which can be used to sign data pointers. */
ptrauth_key_process_dependent_data = ptrauth_key_asdb,
+ /* The key used to sign C function pointers.
+ The extra data is always 0. */
+ ptrauth_key_function_pointer = ptrauth_key_process_independent_code,
+
+ /* Other pointers signed under the ABI use private ABI rules. */
+
} ptrauth_key;
/* An integer type of the appropriate size for a discriminator argument. */
@@ -131,6 +137,27 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
__builtin_ptrauth_auth_and_resign(__value, __old_key, __old_data, __new_key, \
__new_data)
+/* Authenticate a pointer using one scheme and resign it as a C
+ function pointer.
+
+ If the result is subsequently authenticated using the new scheme, that
+ authentication is guaranteed to fail if and only if the initial
+ authentication failed.
+
+ The value must be an expression of function pointer type.
+ The key must be a constant expression of type ptrauth_key.
+ The extra data must be an expression of pointer or integer type;
+ if an integer, it will be coerced to ptrauth_extra_data_t.
+ The result will have the same type as the original value.
+
+ This operation is guaranteed to not leave the intermediate value
+ available for attack before it is re-signed. Additionally, if this
+ expression is used syntactically as the function expression in a
+ call, only a single authentication will be performed. */
+#define ptrauth_auth_function(__value, __old_key, __old_data) \
+ ptrauth_auth_and_resign(__value, __old_key, __old_data, \
+ ptrauth_key_function_pointer, 0)
+
/* Authenticate a data pointer.
The value must be an expression of non-function pointer type.
@@ -217,6 +244,13 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
__value; \
})
+#define ptrauth_auth_function(__value, __old_key, __old_data) \
+ ({ \
+ (void)__old_key; \
+ (void)__old_data; \
+ __value; \
+ })
+
#define ptrauth_auth_data(__value, __old_key, __old_data) \
({ \
(void)__old_key; \