https://github.com/ahmedbougacha updated https://github.com/llvm/llvm-project/pull/93906
>From 016baec5833f0fba4280e67ba24caed48e8a1017 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <ahata...@gmail.com> Date: Fri, 24 May 2024 20:23:36 -0700 Subject: [PATCH 1/6] [clang] Implement function pointer signing. Co-Authored-By: John McCall <rjmcc...@apple.com> --- clang/include/clang/Basic/CodeGenOptions.h | 4 + .../clang/Basic/DiagnosticDriverKinds.td | 3 + clang/include/clang/Basic/LangOptions.h | 2 + .../include/clang/Basic/PointerAuthOptions.h | 136 ++++++++++++++++++ .../clang/Frontend/CompilerInvocation.h | 10 ++ clang/lib/CodeGen/CGBuiltin.cpp | 3 +- clang/lib/CodeGen/CGCall.cpp | 3 + clang/lib/CodeGen/CGCall.h | 28 +++- clang/lib/CodeGen/CGExpr.cpp | 17 +-- clang/lib/CodeGen/CGExprConstant.cpp | 19 ++- clang/lib/CodeGen/CGPointerAuth.cpp | 51 +++++++ clang/lib/CodeGen/CGPointerAuthInfo.h | 96 +++++++++++++ clang/lib/CodeGen/CodeGenFunction.cpp | 58 ++++++++ clang/lib/CodeGen/CodeGenFunction.h | 10 ++ clang/lib/CodeGen/CodeGenModule.h | 33 +++++ clang/lib/Frontend/CompilerInvocation.cpp | 36 +++++ clang/lib/Headers/ptrauth.h | 34 +++++ .../CodeGen/ptrauth-function-attributes.c | 13 ++ .../test/CodeGen/ptrauth-function-init-fail.c | 5 + clang/test/CodeGen/ptrauth-function-init.c | 31 ++++ .../CodeGen/ptrauth-function-lvalue-cast.c | 23 +++ clang/test/CodeGen/ptrauth-weak_import.c | 10 ++ clang/test/CodeGenCXX/ptrauth.cpp | 24 ++++ 23 files changed, 632 insertions(+), 17 deletions(-) create mode 100644 clang/lib/CodeGen/CGPointerAuthInfo.h create mode 100644 clang/test/CodeGen/ptrauth-function-attributes.c create mode 100644 clang/test/CodeGen/ptrauth-function-init-fail.c create mode 100644 clang/test/CodeGen/ptrauth-function-init.c create mode 100644 clang/test/CodeGen/ptrauth-function-lvalue-cast.c create mode 100644 clang/test/CodeGen/ptrauth-weak_import.c create mode 100644 clang/test/CodeGenCXX/ptrauth.cpp diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 00523a84d3895..f2a707a8ba8d7 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_BASIC_CODEGENOPTIONS_H #define LLVM_CLANG_BASIC_CODEGENOPTIONS_H +#include "clang/Basic/PointerAuthOptions.h" #include "clang/Basic/Sanitizers.h" #include "clang/Basic/XRayInstr.h" #include "llvm/ADT/FloatingPointMode.h" @@ -391,6 +392,9 @@ class CodeGenOptions : public CodeGenOptionsBase { std::vector<std::string> Reciprocals; + /// Configuration for pointer-signing. + PointerAuthOptions PointerAuth; + /// The preferred width for auto-vectorization transforms. This is intended to /// override default transforms based on the width of the architected vector /// registers. diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index 1ca2cb85565a1..ab002c24eb08c 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -351,6 +351,9 @@ def err_drv_omp_host_ir_file_not_found : Error< "target regions but cannot be found">; def err_drv_omp_host_target_not_supported : Error< "target '%0' is not a supported OpenMP host target">; +def err_drv_ptrauth_not_supported : Error< + "target '%0' does not support native pointer authentication">; + def err_drv_expecting_fopenmp_with_fopenmp_targets : Error< "'-fopenmp-targets' must be used in conjunction with a '-fopenmp' option " "compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">; diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 75e88afbd9705..5216822e45b1b 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -346,6 +346,8 @@ class LangOptionsBase { BKey }; + using PointerAuthenticationMode = ::clang::PointerAuthenticationMode; + enum class ThreadModelKind { /// POSIX Threads. POSIX, diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index e5cdcc31ebfb7..32b179e3f9460 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -14,10 +14,146 @@ #ifndef LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H #define LLVM_CLANG_BASIC_POINTERAUTHOPTIONS_H +#include "clang/Basic/LLVM.h" +#include "clang/Basic/LangOptions.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Target/TargetOptions.h" +#include <map> +#include <memory> +#include <string> +#include <vector> + namespace clang { constexpr unsigned PointerAuthKeyNone = -1; +class PointerAuthSchema { +public: + enum class Kind : unsigned { + None, + ARM8_3, + }; + + /// Hardware pointer-signing keys in ARM8.3. + /// + /// These values are the same used in ptrauth.h. + enum class ARM8_3Key : unsigned { + ASIA = 0, + ASIB = 1, + ASDA = 2, + ASDB = 3 + }; + + /// Forms of extra discrimination. + enum class Discrimination : unsigned { + /// No additional discrimination. + None, + + /// Discriminate using a constant value. + Constant, + }; + +private: + Kind TheKind : 2; + unsigned IsAddressDiscriminated : 1; + unsigned IsIsaPointer : 1; + unsigned AuthenticatesNullValues : 1; + PointerAuthenticationMode SelectedAuthenticationMode : 2; + Discrimination DiscriminationKind : 2; + unsigned Key : 4; + unsigned ConstantDiscriminator : 16; + +public: + PointerAuthSchema() : TheKind(Kind::None) {} + + PointerAuthSchema( + ARM8_3Key Key, bool IsAddressDiscriminated, + PointerAuthenticationMode AuthenticationMode, + Discrimination OtherDiscrimination, + std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt, + bool IsIsaPointer = false, bool AuthenticatesNullValues = false) + : TheKind(Kind::ARM8_3), IsAddressDiscriminated(IsAddressDiscriminated), + IsIsaPointer(IsIsaPointer), + AuthenticatesNullValues(AuthenticatesNullValues), + SelectedAuthenticationMode(AuthenticationMode), + DiscriminationKind(OtherDiscrimination), Key(unsigned(Key)) { + assert((getOtherDiscrimination() != Discrimination::Constant || + ConstantDiscriminatorOrNone) && + "constant discrimination requires a constant!"); + if (ConstantDiscriminatorOrNone) + ConstantDiscriminator = *ConstantDiscriminatorOrNone; + } + + PointerAuthSchema( + ARM8_3Key Key, bool IsAddressDiscriminated, + Discrimination OtherDiscrimination, + std::optional<uint16_t> ConstantDiscriminatorOrNone = std::nullopt, + bool IsIsaPointer = false, bool AuthenticatesNullValues = false) + : PointerAuthSchema(Key, IsAddressDiscriminated, + PointerAuthenticationMode::SignAndAuth, + OtherDiscrimination, ConstantDiscriminatorOrNone, + IsIsaPointer, AuthenticatesNullValues) {} + + Kind getKind() const { return TheKind; } + + explicit operator bool() const { return isEnabled(); } + + bool isEnabled() const { return getKind() != Kind::None; } + + bool isAddressDiscriminated() const { + assert(getKind() != Kind::None); + return IsAddressDiscriminated; + } + + bool isIsaPointer() const { + assert(getKind() != Kind::None); + return IsIsaPointer; + } + + bool authenticatesNullValues() const { + assert(getKind() != Kind::None); + return AuthenticatesNullValues; + } + + bool hasOtherDiscrimination() const { + return getOtherDiscrimination() != Discrimination::None; + } + + Discrimination getOtherDiscrimination() const { + assert(getKind() != Kind::None); + return DiscriminationKind; + } + + uint16_t getConstantDiscrimination() const { + assert(getOtherDiscrimination() == Discrimination::Constant); + return (uint16_t)ConstantDiscriminator; + } + + unsigned getKey() const { + switch (getKind()) { + case Kind::None: + llvm_unreachable("calling getKey() on disabled schema"); + case Kind::ARM8_3: + return unsigned(getARM8_3Key()); + } + llvm_unreachable("bad key kind"); + } + + PointerAuthenticationMode getAuthenticationMode() const { + return SelectedAuthenticationMode; + } + + ARM8_3Key getARM8_3Key() const { + assert(getKind() == Kind::ARM8_3); + return ARM8_3Key(Key); + } +}; + +struct PointerAuthOptions { + /// The ABI for C function pointers. + PointerAuthSchema FunctionPointers; +}; + } // end namespace clang #endif diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index 1a2a39411e58d..e60e5aad6c70d 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -305,6 +305,16 @@ class CompilerInvocation : public CompilerInvocationBase { /// executable), for finding the builtin compiler path. static std::string GetResourcesPath(const char *Argv0, void *MainAddr); + /// Populate \p Opts with the default set of pointer authentication-related + /// options given \p LangOpts and \p Triple. Return true if defaults are + /// available. + /// + /// Note: This is intended to be used by tools which must be aware of + /// pointer authentication-related code generation, e.g. lldb. + static bool setDefaultPointerAuthOptions(PointerAuthOptions &Opts, + const LangOptions &LangOpts, + const llvm::Triple &Triple); + /// Retrieve a module hash string that is suitable for uniquely /// identifying the conditions under which the module was built. std::string getModuleHash() const; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 2516ed4508242..d11e7a95d833d 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 a071b16fc37f9..2b301130ef7b7 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 6b676ac196db2..4b0e1561b4ef5 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 @@ class CGCallee { /// 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, + const CGPointerAuthInfo &pointerAuthInfo = /*FIXME*/ 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()); } @@ -128,12 +136,12 @@ class CGCallee { static CGCallee forDirect(llvm::Constant *functionPtr, const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { - return CGCallee(abstractInfo, functionPtr); + return CGCallee(abstractInfo, functionPtr, CGPointerAuthInfo()); } static CGCallee forDirect(llvm::FunctionCallee functionPtr, const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { - return CGCallee(abstractInfo, functionPtr.getCallee()); + return CGCallee(abstractInfo, functionPtr.getCallee(), CGPointerAuthInfo()); } static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr, @@ -173,7 +181,11 @@ class CGCallee { 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 @@ class CGCallee { 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 3dfe5e09c778d..534f46da74862 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 bc5f42d632bca..e6f865017bbbc 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::Constant>(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 e1fb0bdb85cfb..2c2e747ccf2e2 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) { + 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,36 @@ CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, llvm::ConstantInt::get(Int32Ty, Key), IntegerDiscriminator, AddressDiscriminator); } + +/// If applicable, sign a given constant function pointer with the ABI rules for +/// functionType. +llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *pointer, + QualType functionType, + GlobalDecl GD) { + assert(functionType->isFunctionType() || + functionType->isFunctionReferenceType() || + functionType->isFunctionPointerType()); + + if (auto pointerAuth = getFunctionPointerAuthInfo(functionType)) { + return getConstantSignedPointer( + pointer, pointerAuth.getKey(), nullptr, + cast_or_null<llvm::Constant>(pointerAuth.getDiscriminator())); + } + + return pointer; +} + +llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD, + llvm::Type *Ty) { + const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); + + // Annoyingly, K&R functions have prototypes in the clang AST, but + // expressions referring to them are unprototyped. + QualType FuncType = FD->getType(); + if (!FD->hasPrototype()) + if (const auto *Proto = FuncType->getAs<FunctionProtoType>()) + FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(), + Proto->getExtInfo()); + + return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType, GD); +} diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h new file mode 100644 index 0000000000000..e870c3145acba --- /dev/null +++ b/clang/lib/CodeGen/CGPointerAuthInfo.h @@ -0,0 +1,96 @@ +//===----- 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 "llvm/IR/Type.h" +#include "llvm/IR/Value.h" + +namespace clang { +namespace CodeGen { + +class CGPointerAuthInfo { +private: + PointerAuthenticationMode AuthenticationMode : 2; + bool IsIsaPointer : 1; + bool AuthenticatesNullValues : 1; + unsigned Key : 28; + 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; + } + + bool operator!=(const CGPointerAuthInfo &Other) const { + return Key != Other.Key || Discriminator != Other.Discriminator || + AuthenticationMode != Other.AuthenticationMode; + } + + bool operator==(const CGPointerAuthInfo &Other) const { + return !(*this != Other); + } +}; + +} // end namespace CodeGen +} // end namespace clang + +#endif diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 200c40da8bc43..f4a10c73b9f84 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,56 @@ 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); +} + +static llvm::Value *EmitPointerAuthCommon(CodeGenFunction &CGF, + const CGPointerAuthInfo &pointerAuth, + llvm::Value *pointer, + unsigned intrinsicID) { + if (!pointerAuth) + return pointer; + + auto key = CGF.Builder.getInt32(pointerAuth.getKey()); + + llvm::Value *discriminator = pointerAuth.getDiscriminator(); + if (!discriminator) { + discriminator = CGF.Builder.getSize(0); + } + + // Convert the pointer to intptr_t before signing it. + auto origType = pointer->getType(); + pointer = CGF.Builder.CreatePtrToInt(pointer, CGF.IntPtrTy); + + // call i64 @llvm.ptrauth.sign.i64(i64 %pointer, i32 %key, i64 %discriminator) + auto intrinsic = CGF.CGM.getIntrinsic(intrinsicID); + pointer = CGF.EmitRuntimeCall(intrinsic, {pointer, key, discriminator}); + + // Convert back to the original type. + pointer = CGF.Builder.CreateIntToPtr(pointer, origType); + return pointer; +} + +llvm::Value * +CodeGenFunction::EmitPointerAuthSign(const CGPointerAuthInfo &pointerAuth, + llvm::Value *pointer) { + if (!pointerAuth.shouldSign()) + return pointer; + return EmitPointerAuthCommon(*this, pointerAuth, pointer, + llvm::Intrinsic::ptrauth_sign); +} diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index cdb5ae6663405..36edac569decf 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4416,6 +4416,16 @@ class CodeGenFunction : public CodeGenTypeCache { } bool isPointerKnownNonNull(const Expr *E); + CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &schema, + llvm::Value *storageAddress, + GlobalDecl calleeDecl, + QualType calleeType); + llvm::Value *EmitPointerAuthSign(QualType pointeeType, llvm::Value *pointer); + llvm::Value *EmitPointerAuthSign(const CGPointerAuthInfo &info, + llvm::Value *pointer); + void EmitPointerAuthOperandBundle( + const CGPointerAuthInfo &info, + SmallVectorImpl<llvm::OperandBundleDef> &bundles); // Return the copy constructor name with the prefix "__copy_constructor_" // removed. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 04e1a392ef5d1..d3ae533e653ba 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -25,6 +25,7 @@ #include "clang/Basic/ABI.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/NoSanitizeList.h" +#include "clang/Basic/PointerAuthOptions.h" #include "clang/Basic/ProfileList.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/XRayLists.h" @@ -69,6 +70,7 @@ class Expr; class Stmt; class StringLiteral; class NamedDecl; +class PointerAuthSchema; class ValueDecl; class VarDecl; class LangOptions; @@ -937,11 +939,42 @@ class CodeGenModule : public CodeGenTypeCache { // 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, but will only cache the result if \p FD is passed. + llvm::Constant *getFunctionPointer(llvm::Constant *pointer, + QualType functionType, + GlobalDecl GD = GlobalDecl()); + + CGPointerAuthInfo getFunctionPointerAuthInfo(QualType functionType); + + CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type); + + CGPointerAuthInfo getPointerAuthInfoForType(QualType type); + + llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer, + const PointerAuthSchema &schema, + llvm::Constant *storageAddress, + GlobalDecl schemaDecl, + QualType schemaType); llvm::Constant * getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, llvm::Constant *StorageAddress, llvm::ConstantInt *OtherDiscriminator); + CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD); + // Return whether RTTI information should be emitted for this target. bool shouldEmitRTTI(bool ForEH = false) { return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice && diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index cde4a84673b6e..757460eca0340 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1458,6 +1458,39 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts, Opts.setProfileUse(CodeGenOptions::ProfileClangInstr); } +bool CompilerInvocation::setDefaultPointerAuthOptions( + PointerAuthOptions &Opts, const LangOptions &LangOpts, + const llvm::Triple &Triple) { + if (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); + } + return true; + } + + return false; +} + +static bool parsePointerAuthOptions(PointerAuthOptions &Opts, + ArgList &Args, + const LangOptions &LangOpts, + const llvm::Triple &Triple, + DiagnosticsEngine &Diags) { + if (!LangOpts.PointerAuthCalls) + return true; + + if (CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple)) + return true; + + Diags.Report(diag::err_drv_ptrauth_not_supported) + << Triple.str(); + return false; +} + void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, ArgumentConsumer Consumer, const llvm::Triple &T, @@ -2153,6 +2186,9 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); + if (!LangOpts->CUDAIsDevice) + parsePointerAuthOptions(Opts.PointerAuth, Args, *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 6aad9efb7a652..1a4bd02933ea2 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; \ diff --git a/clang/test/CodeGen/ptrauth-function-attributes.c b/clang/test/CodeGen/ptrauth-function-attributes.c new file mode 100644 index 0000000000000..eda9c8813ed1e --- /dev/null +++ b/clang/test/CodeGen/ptrauth-function-attributes.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,OFF +// RUN: %clang_cc1 -triple arm64e-apple-ios -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,OFF + +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS +// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS + +// ALL-LABEL: define void @test() #0 +void test() { +} + +// CALLS: attributes #0 = {{{.*}} "ptrauth-calls" {{.*}}} + +// OFF-NOT: attributes {{.*}} "ptrauth- diff --git a/clang/test/CodeGen/ptrauth-function-init-fail.c b/clang/test/CodeGen/ptrauth-function-init-fail.c new file mode 100644 index 0000000000000..012d4f7368eaf --- /dev/null +++ b/clang/test/CodeGen/ptrauth-function-init-fail.c @@ -0,0 +1,5 @@ +// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls %s -verify -emit-llvm -o - + +void f(void); + +int *pf = (int *)&f + 1; // expected-error{{cannot compile this static initializer yet}} diff --git a/clang/test/CodeGen/ptrauth-function-init.c b/clang/test/CodeGen/ptrauth-function-init.c new file mode 100644 index 0000000000000..7d75f5ff2a0c3 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-function-init.c @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s +// RUN: %clang_cc1 -xc++ %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CXX + +#ifdef __cplusplus +extern "C" { +#endif + +void f(void); + +#ifdef __cplusplus + +// CXX-LABEL: define internal void @__cxx_global_var_init() +// CXX: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr @_ZL2fp, align 8 + +__attribute__((used)) +void (*const fp)(void) = (void (*)(void))((int *)&f + 2); // Error in C mode. + +#endif + +// CHECK-LABEL: define void @t1() +void t1() { + // CHECK: [[PF:%.*]] = alloca ptr + // CHECK: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr [[PF]] + + void (*pf)(void) = (void (*)(void))((int *)&f + 2); + (void)pf; +} + +#ifdef __cplusplus +} +#endif diff --git a/clang/test/CodeGen/ptrauth-function-lvalue-cast.c b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c new file mode 100644 index 0000000000000..8ca5490195bac --- /dev/null +++ b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck %s + +typedef void (*fptr_t)(void); + +char *cptr; +void (*fptr)(void); + +// CHECK-LABEL: define void @test1 +void test1() { + // CHECK: [[LOAD:%.*]] = load ptr, ptr @cptr + // CHECK: call void [[LOAD]]() [ "ptrauth"(i32 0, i64 0) ] + // CHECK: ret void + + (*(fptr_t)cptr)(); +} + +// CHECK-LABEL: define i8 @test2 +char test2() { + return *(char *)fptr; + // CHECK: [[LOAD:%.*]] = load ptr, ptr @fptr + // CHECK: [[LOAD1:%.*]] = load i8, ptr [[LOAD]] + // CHECK: ret i8 [[LOAD1]] +} diff --git a/clang/test/CodeGen/ptrauth-weak_import.c b/clang/test/CodeGen/ptrauth-weak_import.c new file mode 100644 index 0000000000000..2fc8530d0677f --- /dev/null +++ b/clang/test/CodeGen/ptrauth-weak_import.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s + +extern void foo() __attribute__((weak_import)); + +// CHECK-LABEL: define void @bar() +// CHECK: br i1 icmp ne (ptr ptrauth (ptr @foo, i32 0), ptr null), label +void bar() { + if (foo) + foo(); +} diff --git a/clang/test/CodeGenCXX/ptrauth.cpp b/clang/test/CodeGenCXX/ptrauth.cpp new file mode 100644 index 0000000000000..d2d3317eb4a35 --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s + +void f(void); +auto &f_ref = f; + +// CHECK-LABEL: define void @_Z1gv( +// CHECK: call void ptrauth (ptr @_Z1fv, i32 0)() [ "ptrauth"(i32 0, i64 0) ] + +void g() { f_ref(); } + +void foo1(); + +void test_terminate() noexcept { + foo1(); +} + +// CHECK: define void @_ZSt9terminatev() #[[ATTR4:.*]] { + +namespace std { + void terminate() noexcept { + } +} + +// CHECK: attributes #[[ATTR4]] = {{{.*}}"ptrauth-calls"{{.*}}} >From 4cebec2cbad09e40ed0e6dace342d5975e88dc4e Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <ahata...@gmail.com> Date: Mon, 3 Jun 2024 09:11:41 -0700 Subject: [PATCH 2/6] Remove unused functions and add test case --- clang/lib/CodeGen/CodeGenFunction.cpp | 36 --------------------------- clang/lib/CodeGen/CodeGenFunction.h | 3 --- clang/test/CodeGen/ptrauth-function.c | 28 +++++++++++++++++++++ 3 files changed, 28 insertions(+), 39 deletions(-) create mode 100644 clang/test/CodeGen/ptrauth-function.c diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index f4a10c73b9f84..8103c78ba5443 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3064,39 +3064,3 @@ void CodeGenFunction::EmitPointerAuthOperandBundle( llvm::Value *args[] = {key, discriminator}; bundles.emplace_back("ptrauth", args); } - -static llvm::Value *EmitPointerAuthCommon(CodeGenFunction &CGF, - const CGPointerAuthInfo &pointerAuth, - llvm::Value *pointer, - unsigned intrinsicID) { - if (!pointerAuth) - return pointer; - - auto key = CGF.Builder.getInt32(pointerAuth.getKey()); - - llvm::Value *discriminator = pointerAuth.getDiscriminator(); - if (!discriminator) { - discriminator = CGF.Builder.getSize(0); - } - - // Convert the pointer to intptr_t before signing it. - auto origType = pointer->getType(); - pointer = CGF.Builder.CreatePtrToInt(pointer, CGF.IntPtrTy); - - // call i64 @llvm.ptrauth.sign.i64(i64 %pointer, i32 %key, i64 %discriminator) - auto intrinsic = CGF.CGM.getIntrinsic(intrinsicID); - pointer = CGF.EmitRuntimeCall(intrinsic, {pointer, key, discriminator}); - - // Convert back to the original type. - pointer = CGF.Builder.CreateIntToPtr(pointer, origType); - return pointer; -} - -llvm::Value * -CodeGenFunction::EmitPointerAuthSign(const CGPointerAuthInfo &pointerAuth, - llvm::Value *pointer) { - if (!pointerAuth.shouldSign()) - return pointer; - return EmitPointerAuthCommon(*this, pointerAuth, pointer, - llvm::Intrinsic::ptrauth_sign); -} diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 36edac569decf..b7babd4db88dc 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4420,9 +4420,6 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *storageAddress, GlobalDecl calleeDecl, QualType calleeType); - llvm::Value *EmitPointerAuthSign(QualType pointeeType, llvm::Value *pointer); - llvm::Value *EmitPointerAuthSign(const CGPointerAuthInfo &info, - llvm::Value *pointer); void EmitPointerAuthOperandBundle( const CGPointerAuthInfo &info, SmallVectorImpl<llvm::OperandBundleDef> &bundles); diff --git a/clang/test/CodeGen/ptrauth-function.c b/clang/test/CodeGen/ptrauth-function.c new file mode 100644 index 0000000000000..dc4f270e470f9 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-function.c @@ -0,0 +1,28 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck -check-prefix=CHECK %s + +void test_call(); + +// CHECK-LABEL: define void @test_direct_call() +void test_direct_call() { + // CHECK: call void @test_call(){{$}} + test_call(); +} + +void abort(); +// CHECK-LABEL: define void @test_direct_builtin_call() +void test_direct_builtin_call() { + // CHECK: call void @abort() {{#[0-9]+$}} + abort(); +} + +// CHECK-LABEL: define void @test_memcpy_inline( +// CHECK-NOT: call{{.*}}memcpy + +extern inline __attribute__((__always_inline__)) +void *memcpy(void *d, const void *s, unsigned long) { + return 0; +} + +void test_memcpy_inline(char *d, char *s) { + memcpy(d, s, 4); +} >From 6d578df40e91f14ea1903631bbff10b9f250f675 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <ahata...@gmail.com> Date: Wed, 12 Jun 2024 10:12:50 -0700 Subject: [PATCH 3/6] Address review comments - Remove unneeded declarations. - Fix includes. - Use `llvm::to_underlying`. - Fix variable names. - Fix size and type of bit-fields. - Add test case for `err_drv_ptrauth_not_supported`. --- clang/include/clang/Basic/LangOptions.h | 2 -- .../include/clang/Basic/PointerAuthOptions.h | 12 ++++---- clang/lib/CodeGen/CGCall.h | 4 +-- clang/lib/CodeGen/CGPointerAuth.cpp | 30 +++++++------------ clang/lib/CodeGen/CGPointerAuthInfo.h | 7 +++-- clang/lib/CodeGen/CodeGenFunction.cpp | 18 +++++------ clang/lib/CodeGen/CodeGenFunction.h | 9 ++---- clang/lib/CodeGen/CodeGenModule.h | 22 +++++--------- clang/lib/Frontend/CompilerInvocation.cpp | 3 +- clang/test/Driver/ptrauth.c | 9 ++++++ 10 files changed, 52 insertions(+), 64 deletions(-) create mode 100644 clang/test/Driver/ptrauth.c diff --git a/clang/include/clang/Basic/LangOptions.h b/clang/include/clang/Basic/LangOptions.h index 5216822e45b1b..75e88afbd9705 100644 --- a/clang/include/clang/Basic/LangOptions.h +++ b/clang/include/clang/Basic/LangOptions.h @@ -346,8 +346,6 @@ class LangOptionsBase { BKey }; - using PointerAuthenticationMode = ::clang::PointerAuthenticationMode; - enum class ThreadModelKind { /// POSIX Threads. POSIX, diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index 32b179e3f9460..9b34f4ebf70dc 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -16,12 +16,10 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/LangOptions.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Target/TargetOptions.h" -#include <map> -#include <memory> -#include <string> -#include <vector> +#include <optional> namespace clang { @@ -76,7 +74,7 @@ class PointerAuthSchema { IsIsaPointer(IsIsaPointer), AuthenticatesNullValues(AuthenticatesNullValues), SelectedAuthenticationMode(AuthenticationMode), - DiscriminationKind(OtherDiscrimination), Key(unsigned(Key)) { + DiscriminationKind(OtherDiscrimination), Key(llvm::to_underlying(Key)) { assert((getOtherDiscrimination() != Discrimination::Constant || ConstantDiscriminatorOrNone) && "constant discrimination requires a constant!"); @@ -126,7 +124,7 @@ class PointerAuthSchema { uint16_t getConstantDiscrimination() const { assert(getOtherDiscrimination() == Discrimination::Constant); - return (uint16_t)ConstantDiscriminator; + return ConstantDiscriminator; } unsigned getKey() const { @@ -134,7 +132,7 @@ class PointerAuthSchema { case Kind::None: llvm_unreachable("calling getKey() on disabled schema"); case Kind::ARM8_3: - return unsigned(getARM8_3Key()); + return llvm::to_underlying(getARM8_3Key()); } llvm_unreachable("bad key kind"); } diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index 4b0e1561b4ef5..a601f5f47c7d8 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -196,9 +196,9 @@ class CGCallee { KindOrFunctionPointer = SpecialKind(reinterpret_cast<uintptr_t>(functionPtr)); } - void setPointerAuthInfo(CGPointerAuthInfo pointerAuth) { + void setPointerAuthInfo(CGPointerAuthInfo PointerAuth) { assert(isOrdinary()); - OrdinaryInfo.PointerAuthInfo = pointerAuth; + OrdinaryInfo.PointerAuthInfo = PointerAuth; } bool isVirtual() const { diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 2c2e747ccf2e2..5162812cc54e1 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -20,7 +20,7 @@ using namespace CodeGen; /// Return the abstract pointer authentication schema for a pointer to the given /// function type. CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) { - auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers; + const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers; if (!Schema) return CGPointerAuthInfo(); @@ -62,33 +62,25 @@ CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, /// If applicable, sign a given constant function pointer with the ABI rules for /// functionType. -llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *pointer, - QualType functionType, +llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer, + QualType FunctionType, GlobalDecl GD) { - assert(functionType->isFunctionType() || - functionType->isFunctionReferenceType() || - functionType->isFunctionPointerType()); + assert(FunctionType->isFunctionType() || + FunctionType->isFunctionReferenceType() || + FunctionType->isFunctionPointerType()); - if (auto pointerAuth = getFunctionPointerAuthInfo(functionType)) { + if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) { return getConstantSignedPointer( - pointer, pointerAuth.getKey(), nullptr, - cast_or_null<llvm::Constant>(pointerAuth.getDiscriminator())); + Pointer, PointerAuth.getKey(), nullptr, + cast_or_null<llvm::Constant>(PointerAuth.getDiscriminator())); } - return pointer; + return Pointer; } llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD, llvm::Type *Ty) { - const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); - - // Annoyingly, K&R functions have prototypes in the clang AST, but - // expressions referring to them are unprototyped. + const auto *FD = cast<FunctionDecl>(GD.getDecl()); QualType FuncType = FD->getType(); - if (!FD->hasPrototype()) - if (const auto *Proto = FuncType->getAs<FunctionProtoType>()) - FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(), - Proto->getExtInfo()); - return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType, GD); } diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h index e870c3145acba..7e93773257cc0 100644 --- a/clang/lib/CodeGen/CGPointerAuthInfo.h +++ b/clang/lib/CodeGen/CGPointerAuthInfo.h @@ -14,6 +14,7 @@ #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" @@ -23,9 +24,9 @@ namespace CodeGen { class CGPointerAuthInfo { private: PointerAuthenticationMode AuthenticationMode : 2; - bool IsIsaPointer : 1; - bool AuthenticatesNullValues : 1; - unsigned Key : 28; + unsigned IsIsaPointer : 1; + unsigned AuthenticatesNullValues : 1; + unsigned Key : 4; llvm::Value *Discriminator; public: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 8103c78ba5443..fd855cc1128f8 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3049,18 +3049,18 @@ llvm::Value *CodeGenFunction::emitBoolVecConversion(llvm::Value *SrcVec, } void CodeGenFunction::EmitPointerAuthOperandBundle( - const CGPointerAuthInfo &pointerAuth, - SmallVectorImpl<llvm::OperandBundleDef> &bundles) { - if (!pointerAuth.isSigned()) + const CGPointerAuthInfo &PointerAuth, + SmallVectorImpl<llvm::OperandBundleDef> &Bundles) { + if (!PointerAuth.isSigned()) return; - auto key = Builder.getInt32(pointerAuth.getKey()); + auto Key = Builder.getInt32(PointerAuth.getKey()); - llvm::Value *discriminator = pointerAuth.getDiscriminator(); - if (!discriminator) { - discriminator = Builder.getSize(0); + llvm::Value *Discriminator = PointerAuth.getDiscriminator(); + if (!Discriminator) { + Discriminator = Builder.getSize(0); } - llvm::Value *args[] = {key, discriminator}; - bundles.emplace_back("ptrauth", args); + 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 b7babd4db88dc..a9c497bde6871 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4416,13 +4416,10 @@ class CodeGenFunction : public CodeGenTypeCache { } bool isPointerKnownNonNull(const Expr *E); - CGPointerAuthInfo EmitPointerAuthInfo(const PointerAuthSchema &schema, - llvm::Value *storageAddress, - GlobalDecl calleeDecl, - QualType calleeType); + void EmitPointerAuthOperandBundle( - const CGPointerAuthInfo &info, - SmallVectorImpl<llvm::OperandBundleDef> &bundles); + const CGPointerAuthInfo &Info, + SmallVectorImpl<llvm::OperandBundleDef> &Bundles); // Return the copy constructor name with the prefix "__copy_constructor_" // removed. diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index d3ae533e653ba..c4f8285093c90 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -25,7 +25,6 @@ #include "clang/Basic/ABI.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/NoSanitizeList.h" -#include "clang/Basic/PointerAuthOptions.h" #include "clang/Basic/ProfileList.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/XRayLists.h" @@ -953,28 +952,23 @@ class CodeGenModule : public CodeGenTypeCache { /// Return the ABI-correct function pointer value for a reference /// to the given function. This will apply a pointer signature if /// necessary, but will only cache the result if \p FD is passed. - llvm::Constant *getFunctionPointer(llvm::Constant *pointer, - QualType functionType, + llvm::Constant *getFunctionPointer(llvm::Constant *Pointer, + QualType FunctionType, GlobalDecl GD = GlobalDecl()); - CGPointerAuthInfo getFunctionPointerAuthInfo(QualType functionType); + CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T); - CGPointerAuthInfo getPointerAuthInfoForPointeeType(QualType type); + llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer, + const PointerAuthSchema &Schema, + llvm::Constant *StorageAddress, + GlobalDecl SchemaDecl, + QualType SchemaType); - CGPointerAuthInfo getPointerAuthInfoForType(QualType type); - - llvm::Constant *getConstantSignedPointer(llvm::Constant *pointer, - const PointerAuthSchema &schema, - llvm::Constant *storageAddress, - GlobalDecl schemaDecl, - QualType schemaType); llvm::Constant * getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, llvm::Constant *StorageAddress, llvm::ConstantInt *OtherDiscriminator); - CGPointerAuthInfo EmitPointerAuthInfo(const RecordDecl *RD); - // Return whether RTTI information should be emitted for this target. bool shouldEmitRTTI(bool ForEH = false) { return (ForEH || getLangOpts().RTTI) && !getLangOpts().CUDAIsDevice && diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 757460eca0340..01270c7284e95 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1476,7 +1476,6 @@ bool CompilerInvocation::setDefaultPointerAuthOptions( } static bool parsePointerAuthOptions(PointerAuthOptions &Opts, - ArgList &Args, const LangOptions &LangOpts, const llvm::Triple &Triple, DiagnosticsEngine &Diags) { @@ -2187,7 +2186,7 @@ bool CompilerInvocation::ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, Opts.EmitVersionIdentMetadata = Args.hasFlag(OPT_Qy, OPT_Qn, true); if (!LangOpts->CUDAIsDevice) - parsePointerAuthOptions(Opts.PointerAuth, Args, *LangOpts, T, Diags); + parsePointerAuthOptions(Opts.PointerAuth, *LangOpts, T, Diags); if (Args.hasArg(options::OPT_ffinite_loops)) Opts.FiniteLoops = CodeGenOptions::FiniteLoopsKind::Always; diff --git a/clang/test/Driver/ptrauth.c b/clang/test/Driver/ptrauth.c new file mode 100644 index 0000000000000..a12b451a7ee0d --- /dev/null +++ b/clang/test/Driver/ptrauth.c @@ -0,0 +1,9 @@ +// RUN: %clang -target arm64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS +// RUN: %clang -target aarch64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS +// RUN: %clang -target aarch64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS +// RUN: not %clang -target x86_64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID +// RUN: not %clang -target x86_64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID +// RUN: not %clang -target x86_64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID + +// PTRAUTH_CALLS: "-fptrauth-calls" +// INVALID: unsupported option '-fptrauth-calls' >From 0598b29454f22544ad008c90d182b70a62cd1d52 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <ahata...@gmail.com> Date: Wed, 12 Jun 2024 10:39:46 -0700 Subject: [PATCH 4/6] Declare operator== as a friend function instead of a member function --- clang/lib/CodeGen/CGPointerAuthInfo.h | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h index 7e93773257cc0..1cf4943e1e266 100644 --- a/clang/lib/CodeGen/CGPointerAuthInfo.h +++ b/clang/lib/CodeGen/CGPointerAuthInfo.h @@ -81,13 +81,15 @@ class CGPointerAuthInfo { return AuthenticationMode == PointerAuthenticationMode::SignAndAuth; } - bool operator!=(const CGPointerAuthInfo &Other) const { - return Key != Other.Key || Discriminator != Other.Discriminator || - AuthenticationMode != Other.AuthenticationMode; + friend bool operator!=(const CGPointerAuthInfo &LHS, + const CGPointerAuthInfo &RHS) { + return LHS.Key != RHS.Key || LHS.Discriminator != RHS.Discriminator || + LHS.AuthenticationMode != RHS.AuthenticationMode; } - bool operator==(const CGPointerAuthInfo &Other) const { - return !(*this != Other); + friend bool operator==(const CGPointerAuthInfo &LHS, + const CGPointerAuthInfo &RHS) { + return !(LHS != RHS); } }; >From cbb9bb03cded02e6efda5bd78dcab92e20ce1356 Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <ahata...@gmail.com> Date: Tue, 18 Jun 2024 11:49:54 -0700 Subject: [PATCH 5/6] Address review comments - Remove unused diagnostic. - Change the size of Key fields to 2 bits. - Stop passing the default argument to CGCallee's constructor. - Remove unused functions and variables. - Add a test for indirect calls. - Run tests on linux too. --- .../clang/Basic/DiagnosticDriverKinds.td | 3 -- .../include/clang/Basic/PointerAuthOptions.h | 2 +- .../clang/Frontend/CompilerInvocation.h | 5 ++- clang/lib/CodeGen/CGCall.h | 10 +++--- clang/lib/CodeGen/CGPointerAuth.cpp | 14 +++------ clang/lib/CodeGen/CGPointerAuthInfo.h | 2 +- clang/lib/CodeGen/CodeGenFunction.cpp | 5 ++- clang/lib/CodeGen/CodeGenModule.h | 11 ++----- clang/lib/Frontend/CompilerInvocation.cpp | 31 +++++++------------ .../CodeGen/ptrauth-function-attributes.c | 6 ++-- .../test/CodeGen/ptrauth-function-init-fail.c | 2 ++ clang/test/CodeGen/ptrauth-function-init.c | 11 +++++-- .../CodeGen/ptrauth-function-lvalue-cast.c | 5 +-- clang/test/CodeGen/ptrauth-function.c | 16 ++++++++-- clang/test/CodeGen/ptrauth-weak_import.c | 3 +- clang/test/CodeGenCXX/ptrauth.cpp | 5 +-- clang/test/Driver/ptrauth.c | 9 ------ 17 files changed, 63 insertions(+), 77 deletions(-) delete mode 100644 clang/test/Driver/ptrauth.c diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index ab002c24eb08c..1ca2cb85565a1 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -351,9 +351,6 @@ def err_drv_omp_host_ir_file_not_found : Error< "target regions but cannot be found">; def err_drv_omp_host_target_not_supported : Error< "target '%0' is not a supported OpenMP host target">; -def err_drv_ptrauth_not_supported : Error< - "target '%0' does not support native pointer authentication">; - def err_drv_expecting_fopenmp_with_fopenmp_targets : Error< "'-fopenmp-targets' must be used in conjunction with a '-fopenmp' option " "compatible with offloading; e.g., '-fopenmp=libomp' or '-fopenmp=libiomp5'">; diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index 9b34f4ebf70dc..aaad4a2b2b5ae 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -58,7 +58,7 @@ class PointerAuthSchema { unsigned AuthenticatesNullValues : 1; PointerAuthenticationMode SelectedAuthenticationMode : 2; Discrimination DiscriminationKind : 2; - unsigned Key : 4; + unsigned Key : 2; unsigned ConstantDiscriminator : 16; public: diff --git a/clang/include/clang/Frontend/CompilerInvocation.h b/clang/include/clang/Frontend/CompilerInvocation.h index e60e5aad6c70d..9daa0a1ecf948 100644 --- a/clang/include/clang/Frontend/CompilerInvocation.h +++ b/clang/include/clang/Frontend/CompilerInvocation.h @@ -306,12 +306,11 @@ class CompilerInvocation : public CompilerInvocationBase { static std::string GetResourcesPath(const char *Argv0, void *MainAddr); /// Populate \p Opts with the default set of pointer authentication-related - /// options given \p LangOpts and \p Triple. Return true if defaults are - /// available. + /// options given \p LangOpts and \p Triple. /// /// Note: This is intended to be used by tools which must be aware of /// pointer authentication-related code generation, e.g. lldb. - static bool setDefaultPointerAuthOptions(PointerAuthOptions &Opts, + static void setDefaultPointerAuthOptions(PointerAuthOptions &Opts, const LangOptions &LangOpts, const llvm::Triple &Triple); diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index a601f5f47c7d8..412b44a8c753a 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -109,9 +109,9 @@ class CGCallee { /// Construct a callee. Call this constructor directly when this /// isn't a direct call. - CGCallee( - const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr, - const CGPointerAuthInfo &pointerAuthInfo = /*FIXME*/ CGPointerAuthInfo()) + CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr, + /* FIXME: make parameter pointerAuthInfo mandatory */ + const CGPointerAuthInfo &pointerAuthInfo = CGPointerAuthInfo()) : KindOrFunctionPointer( SpecialKind(reinterpret_cast<uintptr_t>(functionPtr))) { OrdinaryInfo.AbstractInfo = abstractInfo; @@ -136,12 +136,12 @@ class CGCallee { static CGCallee forDirect(llvm::Constant *functionPtr, const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { - return CGCallee(abstractInfo, functionPtr, CGPointerAuthInfo()); + return CGCallee(abstractInfo, functionPtr); } static CGCallee forDirect(llvm::FunctionCallee functionPtr, const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { - return CGCallee(abstractInfo, functionPtr.getCallee(), CGPointerAuthInfo()); + return CGCallee(abstractInfo, functionPtr.getCallee()); } static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr, diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 5162812cc54e1..fa0694ec2e152 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -60,20 +60,16 @@ CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, IntegerDiscriminator, AddressDiscriminator); } -/// If applicable, sign a given constant function pointer with the ABI rules for -/// functionType. llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer, - QualType FunctionType, - GlobalDecl GD) { + QualType FunctionType) { assert(FunctionType->isFunctionType() || FunctionType->isFunctionReferenceType() || FunctionType->isFunctionPointerType()); - if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) { + if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) return getConstantSignedPointer( - Pointer, PointerAuth.getKey(), nullptr, - cast_or_null<llvm::Constant>(PointerAuth.getDiscriminator())); - } + Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr, + cast_or_null<llvm::Constant>(PointerAuth.getDiscriminator())); return Pointer; } @@ -82,5 +78,5 @@ 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, GD); + return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType); } diff --git a/clang/lib/CodeGen/CGPointerAuthInfo.h b/clang/lib/CodeGen/CGPointerAuthInfo.h index 1cf4943e1e266..0a0c11fb423f2 100644 --- a/clang/lib/CodeGen/CGPointerAuthInfo.h +++ b/clang/lib/CodeGen/CGPointerAuthInfo.h @@ -26,7 +26,7 @@ class CGPointerAuthInfo { PointerAuthenticationMode AuthenticationMode : 2; unsigned IsIsaPointer : 1; unsigned AuthenticatesNullValues : 1; - unsigned Key : 4; + unsigned Key : 2; llvm::Value *Discriminator; public: diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index fd855cc1128f8..650c5662539f9 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -3054,12 +3054,11 @@ void CodeGenFunction::EmitPointerAuthOperandBundle( if (!PointerAuth.isSigned()) return; - auto Key = Builder.getInt32(PointerAuth.getKey()); + auto *Key = Builder.getInt32(PointerAuth.getKey()); llvm::Value *Discriminator = PointerAuth.getDiscriminator(); - if (!Discriminator) { + if (!Discriminator) Discriminator = Builder.getSize(0); - } llvm::Value *Args[] = {Key, Discriminator}; Bundles.emplace_back("ptrauth", Args); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index c4f8285093c90..9913304757caa 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -951,19 +951,12 @@ class CodeGenModule : public CodeGenTypeCache { /// Return the ABI-correct function pointer value for a reference /// to the given function. This will apply a pointer signature if - /// necessary, but will only cache the result if \p FD is passed. + /// necessary. llvm::Constant *getFunctionPointer(llvm::Constant *Pointer, - QualType FunctionType, - GlobalDecl GD = GlobalDecl()); + QualType FunctionType); CGPointerAuthInfo getFunctionPointerAuthInfo(QualType T); - llvm::Constant *getConstantSignedPointer(llvm::Constant *Pointer, - const PointerAuthSchema &Schema, - llvm::Constant *StorageAddress, - GlobalDecl SchemaDecl, - QualType SchemaType); - 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 01270c7284e95..a6d9f42ace9cc 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1458,36 +1458,27 @@ static void setPGOUseInstrumentor(CodeGenOptions &Opts, Opts.setProfileUse(CodeGenOptions::ProfileClangInstr); } -bool CompilerInvocation::setDefaultPointerAuthOptions( +void CompilerInvocation::setDefaultPointerAuthOptions( PointerAuthOptions &Opts, const LangOptions &LangOpts, const llvm::Triple &Triple) { - if (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); - } - return true; + 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); } - - return false; } -static bool parsePointerAuthOptions(PointerAuthOptions &Opts, +static void parsePointerAuthOptions(PointerAuthOptions &Opts, const LangOptions &LangOpts, const llvm::Triple &Triple, DiagnosticsEngine &Diags) { if (!LangOpts.PointerAuthCalls) - return true; - - if (CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple)) - return true; + return; - Diags.Report(diag::err_drv_ptrauth_not_supported) - << Triple.str(); - return false; + CompilerInvocation::setDefaultPointerAuthOptions(Opts, LangOpts, Triple); } void CompilerInvocationBase::GenerateCodeGenArgs(const CodeGenOptions &Opts, diff --git a/clang/test/CodeGen/ptrauth-function-attributes.c b/clang/test/CodeGen/ptrauth-function-attributes.c index eda9c8813ed1e..7ec30498b9d35 100644 --- a/clang/test/CodeGen/ptrauth-function-attributes.c +++ b/clang/test/CodeGen/ptrauth-function-attributes.c @@ -1,10 +1,10 @@ -// RUN: %clang_cc1 -triple arm64-apple-ios -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,OFF // RUN: %clang_cc1 -triple arm64e-apple-ios -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,OFF +// RUN: %clang_cc1 -triple aarch64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,OFF // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS -// RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm %s -o - | FileCheck %s --check-prefixes=ALL,CALLS -// ALL-LABEL: define void @test() #0 +// ALL: define {{(dso_local )?}}void @test() #0 void test() { } diff --git a/clang/test/CodeGen/ptrauth-function-init-fail.c b/clang/test/CodeGen/ptrauth-function-init-fail.c index 012d4f7368eaf..4522f6a14c4a8 100644 --- a/clang/test/CodeGen/ptrauth-function-init-fail.c +++ b/clang/test/CodeGen/ptrauth-function-init-fail.c @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple arm64e-apple-ios -fptrauth-calls %s -verify -emit-llvm -o - +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls %s -verify -emit-llvm -o - void f(void); +// FIXME: We need a better diagnostic here. int *pf = (int *)&f + 1; // expected-error{{cannot compile this static initializer yet}} diff --git a/clang/test/CodeGen/ptrauth-function-init.c b/clang/test/CodeGen/ptrauth-function-init.c index 7d75f5ff2a0c3..bf8ee53364ecc 100644 --- a/clang/test/CodeGen/ptrauth-function-init.c +++ b/clang/test/CodeGen/ptrauth-function-init.c @@ -1,5 +1,7 @@ // RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s +// RUN: %clang_cc1 %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s // RUN: %clang_cc1 -xc++ %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CXX +// RUN: %clang_cc1 -xc++ %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CXX #ifdef __cplusplus extern "C" { @@ -9,15 +11,18 @@ void f(void); #ifdef __cplusplus -// CXX-LABEL: define internal void @__cxx_global_var_init() +// CXX: define {{(dso_local )?}}internal void @__cxx_global_var_init() // CXX: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr @_ZL2fp, align 8 +// This is rejected in C mode as adding a non-zero constant to a signed pointer +// is unrepresentable in relocations. In C++ mode, this can be done dynamically +// by the global constructor. __attribute__((used)) -void (*const fp)(void) = (void (*)(void))((int *)&f + 2); // Error in C mode. +void (*const fp)(void) = (void (*)(void))((int *)&f + 2); #endif -// CHECK-LABEL: define void @t1() +// CHECK: define {{(dso_local )?}}void @t1() void t1() { // CHECK: [[PF:%.*]] = alloca ptr // CHECK: store ptr getelementptr inbounds (i32, ptr ptrauth (ptr @f, i32 0), i64 2), ptr [[PF]] diff --git a/clang/test/CodeGen/ptrauth-function-lvalue-cast.c b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c index 8ca5490195bac..8d8af18fcafbe 100644 --- a/clang/test/CodeGen/ptrauth-function-lvalue-cast.c +++ b/clang/test/CodeGen/ptrauth-function-lvalue-cast.c @@ -1,11 +1,12 @@ // RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck %s +// RUN: %clang_cc1 %s -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck %s typedef void (*fptr_t)(void); char *cptr; void (*fptr)(void); -// CHECK-LABEL: define void @test1 +// CHECK: define {{(dso_local )?}}void @test1 void test1() { // CHECK: [[LOAD:%.*]] = load ptr, ptr @cptr // CHECK: call void [[LOAD]]() [ "ptrauth"(i32 0, i64 0) ] @@ -14,7 +15,7 @@ void test1() { (*(fptr_t)cptr)(); } -// CHECK-LABEL: define i8 @test2 +// CHECK: define {{(dso_local )?}}i8 @test2 char test2() { return *(char *)fptr; // CHECK: [[LOAD:%.*]] = load ptr, ptr @fptr diff --git a/clang/test/CodeGen/ptrauth-function.c b/clang/test/CodeGen/ptrauth-function.c index dc4f270e470f9..eea3f7ed73747 100644 --- a/clang/test/CodeGen/ptrauth-function.c +++ b/clang/test/CodeGen/ptrauth-function.c @@ -1,21 +1,31 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck -check-prefix=CHECK %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck -check-prefix=CHECK %s void test_call(); -// CHECK-LABEL: define void @test_direct_call() +// CHECK: define {{(dso_local )?}}void @test_direct_call() void test_direct_call() { // CHECK: call void @test_call(){{$}} test_call(); } +// CHECK: define {{(dso_local )?}}void @test_indirect_call(ptr noundef %[[FP:.*]]) +void test_indirect_call(void (*fp(void))) { + // CHECK: %[[FP_ADDR:.*]] = alloca ptr, align 8 + // CHECK: store ptr %[[FP]], ptr %[[FP_ADDR]], align 8 + // CHECK: %[[V0:.*]] = load ptr, ptr %[[FP_ADDR]], align 8 + // CHECK: %[[CALL:.*]] = call ptr %[[V0]]() [ "ptrauth"(i32 0, i64 0) ] + fp(); +} + void abort(); -// CHECK-LABEL: define void @test_direct_builtin_call() +// CHECK: define {{(dso_local )?}}void @test_direct_builtin_call() void test_direct_builtin_call() { // CHECK: call void @abort() {{#[0-9]+$}} abort(); } -// CHECK-LABEL: define void @test_memcpy_inline( +// CHECK-LABEL: define {{(dso_local )?}}void @test_memcpy_inline( // CHECK-NOT: call{{.*}}memcpy extern inline __attribute__((__always_inline__)) diff --git a/clang/test/CodeGen/ptrauth-weak_import.c b/clang/test/CodeGen/ptrauth-weak_import.c index 2fc8530d0677f..618042d575a1c 100644 --- a/clang/test/CodeGen/ptrauth-weak_import.c +++ b/clang/test/CodeGen/ptrauth-weak_import.c @@ -1,8 +1,9 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm %s -o - | FileCheck %s extern void foo() __attribute__((weak_import)); -// CHECK-LABEL: define void @bar() +// CHECK: define {{(dso_local )?}}void @bar() // CHECK: br i1 icmp ne (ptr ptrauth (ptr @foo, i32 0), ptr null), label void bar() { if (foo) diff --git a/clang/test/CodeGenCXX/ptrauth.cpp b/clang/test/CodeGenCXX/ptrauth.cpp index d2d3317eb4a35..b0c069f43969b 100644 --- a/clang/test/CodeGenCXX/ptrauth.cpp +++ b/clang/test/CodeGenCXX/ptrauth.cpp @@ -1,9 +1,10 @@ // RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -emit-llvm -std=c++11 -fexceptions -fcxx-exceptions -o - %s | FileCheck %s void f(void); auto &f_ref = f; -// CHECK-LABEL: define void @_Z1gv( +// CHECK: define {{(dso_local )?}}void @_Z1gv( // CHECK: call void ptrauth (ptr @_Z1fv, i32 0)() [ "ptrauth"(i32 0, i64 0) ] void g() { f_ref(); } @@ -14,7 +15,7 @@ void test_terminate() noexcept { foo1(); } -// CHECK: define void @_ZSt9terminatev() #[[ATTR4:.*]] { +// CHECK: define {{(dso_local )?}}void @_ZSt9terminatev() #[[ATTR4:.*]] { namespace std { void terminate() noexcept { diff --git a/clang/test/Driver/ptrauth.c b/clang/test/Driver/ptrauth.c deleted file mode 100644 index a12b451a7ee0d..0000000000000 --- a/clang/test/Driver/ptrauth.c +++ /dev/null @@ -1,9 +0,0 @@ -// RUN: %clang -target arm64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS -// RUN: %clang -target aarch64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS -// RUN: %clang -target aarch64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix PTRAUTH_CALLS -// RUN: not %clang -target x86_64-apple-macosx -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID -// RUN: not %clang -target x86_64-linux-gnu -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID -// RUN: not %clang -target x86_64-windows-msvc -fptrauth-calls -c %s -### 2>&1 | FileCheck %s --check-prefix INVALID - -// PTRAUTH_CALLS: "-fptrauth-calls" -// INVALID: unsupported option '-fptrauth-calls' >From 99b2bf2e1f70ed6f374a380f91a707c2acd8a318 Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha <ah...@bougacha.org> Date: Thu, 20 Jun 2024 12:23:41 -0700 Subject: [PATCH 6/6] Adjust test/ConstantInt following rebase. --- clang/lib/CodeGen/CGExprConstant.cpp | 2 +- clang/lib/CodeGen/CGPointerAuth.cpp | 2 +- clang/test/CodeGen/ptrauth-weak_import.c | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index e6f865017bbbc..dffb8ce83b643 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -2034,7 +2034,7 @@ ConstantLValueEmitter::tryEmitBase(const APValue::LValueBase &base) { C = applyOffset(C); C = CGM.getConstantSignedPointer( C, AuthInfo.getKey(), nullptr, - cast_or_null<llvm::Constant>(AuthInfo.getDiscriminator())); + cast_or_null<llvm::ConstantInt>(AuthInfo.getDiscriminator())); return ConstantLValue(C, /*applied offset*/ true); } diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index fa0694ec2e152..f0819b0467489 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -69,7 +69,7 @@ llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer, if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) return getConstantSignedPointer( Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr, - cast_or_null<llvm::Constant>(PointerAuth.getDiscriminator())); + cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator())); return Pointer; } diff --git a/clang/test/CodeGen/ptrauth-weak_import.c b/clang/test/CodeGen/ptrauth-weak_import.c index 618042d575a1c..1f53747a2640e 100644 --- a/clang/test/CodeGen/ptrauth-weak_import.c +++ b/clang/test/CodeGen/ptrauth-weak_import.c @@ -4,7 +4,8 @@ extern void foo() __attribute__((weak_import)); // CHECK: define {{(dso_local )?}}void @bar() -// CHECK: br i1 icmp ne (ptr ptrauth (ptr @foo, i32 0), ptr null), label +// CHECK: [[TMP1:%.*]] = icmp ne ptr ptrauth (ptr @foo, i32 0), null +// CHECK: br i1 [[TMP1]], label void bar() { if (foo) foo(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits