Index: llvm/docs/LangRef.rst =================================================================== --- llvm/docs/LangRef.rst +++ llvm/docs/LangRef.rst @@ -3828,6 +3828,33 @@ This is currently only supported for ELF binary formats. +.. _ptrauth + +Authenticated Pointers +---------------------- + +``ptrauth (TYPE1* CST, i32 KEY, TYPE2* ADDRDISC, i16 DISC) + +A '``ptrauth``' constant represents a pointer with a cryptographic +authentication signature embedded into some bits. Its type is the same as the +first argument. + + +If the address disciminator is ``null`` then the expression is equivalent to + +.. code-block:llvm + %tmp = call i64 @llvm.ptrauth.sign.i64(i64 ptrtoint(TYPE1 *CST to i64), i32 KEY, i64 DISC) + %val = inttoptr i64 %tmp to TYPE1* + +If the address discriminator is present, then it is + +.. code-block:llvm + %tmp1 = call i64 @llvm.ptrauth.blend.i64(i64 ptrtoint(TYPE2* ADDRDISC to i64), i64 DISC) + %tmp2 = call i64 @llvm.ptrauth.sign.i64(i64 ptrtoint(TYPE1* CST to i64), i64 %tmp1) + %val = inttoptr i64 %tmp2 to TYPE1* + + %tmp = call i64 @llvm.ptrauth.blend.i64 + .. _constantexprs: Constant Expressions Index: llvm/include/llvm-c/Core.h =================================================================== --- llvm/include/llvm-c/Core.h +++ llvm/include/llvm-c/Core.h @@ -282,6 +282,7 @@ LLVMInlineAsmValueKind, LLVMInstructionValueKind, + LLVMConstantPtrAuthValueKind, } LLVMValueKind; typedef enum { Index: llvm/include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- llvm/include/llvm/Bitcode/LLVMBitCodes.h +++ llvm/include/llvm/Bitcode/LLVMBitCodes.h @@ -376,6 +376,8 @@ CST_CODE_CE_GEP_WITH_INRANGE_INDEX = 24, // [opty, flags, n x operands] CST_CODE_CE_UNOP = 25, // CE_UNOP: [opcode, opval] CST_CODE_POISON = 26, // POISON + CST_CODE_SIGNED_PTR = 27, // CE_SIGNED_PTR: [ptrty, ptr, key, + // addrdiscty, addrdisc, disc] }; /// CastOpcodes - These are values used in the bitcode files to encode which Index: llvm/include/llvm/IR/AutoUpgrade.h =================================================================== --- llvm/include/llvm/IR/AutoUpgrade.h +++ llvm/include/llvm/IR/AutoUpgrade.h @@ -49,7 +49,7 @@ /// This checks for global variables which should be upgraded. It it requires /// upgrading, returns a pointer to the upgraded variable. - GlobalVariable *UpgradeGlobalVariable(GlobalVariable *GV); + bool UpgradeGlobalVariable(GlobalVariable *GV, GlobalVariable *&NewGV); /// This checks for module flags which should be upgraded. It returns true if /// module is modified. Index: llvm/include/llvm/IR/Constants.h =================================================================== --- llvm/include/llvm/IR/Constants.h +++ llvm/include/llvm/IR/Constants.h @@ -924,6 +924,75 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(DSOLocalEquivalent, Value) +/// A signed pointer +/// +class ConstantPtrAuth final : public Constant { + friend struct ConstantPtrAuthKeyType; + friend class Constant; + + ConstantPtrAuth(Constant *Ptr, ConstantInt *Key, Constant *AddrDisc, + ConstantInt *Disc); + + void *operator new(size_t s) { return User::operator new(s, 4); } + + void destroyConstantImpl(); + Value *handleOperandChangeImpl(Value *From, Value *To); + +public: + /// Return a pointer authenticated with the specified parameters. + static ConstantPtrAuth *get(Constant *Ptr, ConstantInt *Key, + Constant *AddrDisc, ConstantInt *Disc); + + /// Produce a new ptrauth expression signing the given value using + /// the same schema as is stored in one. + ConstantPtrAuth *getWithSameSchema(Constant *Pointer) const; + + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + + /// The pointer that is authenticated in this authenticated global reference. + Constant *getPointer() const { return (Constant *)Op<0>().get(); } + + /// The Key ID, an i32 constant. + ConstantInt *getKey() const { return (ConstantInt *)Op<1>().get(); } + + /// The address discriminator if any, or the null constant. + /// If present, this must be a value equivalent to the storage location of + /// the only user of the authenticated ptrauth global. + Constant *getAddrDiscriminator() const { return (Constant *)Op<2>().get(); } + + /// The discriminator. + ConstantInt *getDiscriminator() const { return (ConstantInt *)Op<3>().get(); } + + /// Whether there is any non-null address discriminator. + bool hasAddressDiversity() const { + return !getAddrDiscriminator()->isNullValue(); + } + + /// Whether the address uses a special address discriminator. + /// These discriminators can't be used in real pointer-auth values; they + /// can only be used in "prototype" values that indicate how some real + /// schema is supposed to be produced. + bool hasSpecialAddressDiscriminator(uint64_t value) const; + + /// Check whether an authentication operation with key \p KeyV and (possibly + /// blended) discriminator \p DiscriminatorV is compatible with this + /// authenticated global reference. + bool isCompatibleWith(const Value *Key, const Value *Discriminator, + const DataLayout &DL) const; + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static bool classof(const Value *V) { + return V->getValueID() == ConstantPtrAuthVal; + } +}; + +template <> +struct OperandTraits + : public FixedNumOperandTraits {}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPtrAuth, Constant) + //===----------------------------------------------------------------------===// /// A constant value that is initialized with an expression using /// other constant values. Index: llvm/include/llvm/IR/Value.def =================================================================== --- llvm/include/llvm/IR/Value.def +++ llvm/include/llvm/IR/Value.def @@ -78,6 +78,7 @@ HANDLE_GLOBAL_VALUE(GlobalIFunc) HANDLE_GLOBAL_VALUE(GlobalVariable) HANDLE_CONSTANT(BlockAddress) +HANDLE_CONSTANT(ConstantPtrAuth) HANDLE_CONSTANT(ConstantExpr) HANDLE_CONSTANT_EXCLUDE_LLVM_C_API(DSOLocalEquivalent) Index: llvm/lib/AsmParser/LLLexer.cpp =================================================================== --- llvm/lib/AsmParser/LLLexer.cpp +++ llvm/lib/AsmParser/LLLexer.cpp @@ -726,6 +726,7 @@ KEYWORD(x); KEYWORD(blockaddress); KEYWORD(dso_local_equivalent); + KEYWORD(ptrauth); // Metadata types. KEYWORD(distinct); Index: llvm/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/lib/AsmParser/LLParser.cpp +++ llvm/lib/AsmParser/LLParser.cpp @@ -3508,6 +3508,48 @@ ID.Kind = ValID::t_Constant; return false; } + case lltok::kw_ptrauth: { + // ValID ::= 'ptrauth' '(' * @foo ',' i32 ',' + // * addrdisc ',' i16 ')' + Lex.Lex(); + + Constant *Ptr, *Key, *AddrDisc, *Disc; + + if (parseToken(lltok::lparen, + "expected '(' in signed pointer expression") || + parseGlobalTypeAndValue(Ptr) || + parseToken(lltok::comma, + "expected comma in signed pointer expression") || + parseGlobalTypeAndValue(Key) || + parseToken(lltok::comma, + "expected comma in signed pointer expression") || + parseGlobalTypeAndValue(AddrDisc) || + parseToken(lltok::comma, + "expected comma in signed pointer expression") || + parseGlobalTypeAndValue(Disc) || + parseToken(lltok::rparen, "expected ')' in signed pointer expression")) + return true; + + if (!Ptr->getType()->isPointerTy()) + return error(ID.Loc, "signed pointer must be a pointer"); + + auto KeyC = dyn_cast(Key); + if (!KeyC || KeyC->getBitWidth() != 32) + return error(ID.Loc, "signed pointer key must be i32 constant integer"); + + if (!AddrDisc->getType()->isPointerTy()) + return error(ID.Loc, + "signed pointer address discriminator must be a pointer"); + + auto DiscC = dyn_cast(Disc); + if (!DiscC || DiscC->getBitWidth() != 16) + return error(ID.Loc, + "signed pointer discriminator must be i16 constant integer"); + + ID.ConstantVal = ConstantPtrAuth::get(Ptr, KeyC, AddrDisc, DiscC); + ID.Kind = ValID::t_Constant; + return false; + } case lltok::kw_trunc: case lltok::kw_zext: Index: llvm/lib/AsmParser/LLToken.h =================================================================== --- llvm/lib/AsmParser/LLToken.h +++ llvm/lib/AsmParser/LLToken.h @@ -363,6 +363,8 @@ kw_blockaddress, kw_dso_local_equivalent, + kw_ptrauth, + kw_freeze, // Metadata types. Index: llvm/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -2876,6 +2876,28 @@ V = BlockAddress::get(Fn, BB); break; } + case bitc::CST_CODE_SIGNED_PTR: { + if (Record.size() < 6) + return error("Invalid record"); + Type *PtrTy = getTypeByID(Record[0]); + if (!PtrTy) + return error("Invalid record"); + Constant *Ptr = ValueList.getConstantFwdRef(Record[1], PtrTy); + if (!Ptr) + return error("Invalid record"); + + Type *AddrDiscTy = getTypeByID(Record[3]); + if (!PtrTy) + return error("Invalid record"); + Constant *AddrDisc = ValueList.getConstantFwdRef(Record[4], AddrDiscTy); + if (!AddrDisc) + return error("Invalid record"); + + auto *Key = ConstantInt::get(Type::getInt32Ty(Context), Record[2]); + auto *Disc = ConstantInt::get(Type::getInt16Ty(Context), Record[5]); + V = ConstantPtrAuth::get(Ptr, Key, AddrDisc, Disc); + break; + } } assert(V->getType() == flattenPointerTypes(CurFullTy) && @@ -3044,12 +3066,15 @@ // Look for global variables which need to be renamed. std::vector> UpgradedVariables; - for (GlobalVariable &GV : TheModule->globals()) - if (GlobalVariable *Upgraded = UpgradeGlobalVariable(&GV)) + for (GlobalVariable &GV : TheModule->globals()) { + GlobalVariable *Upgraded = nullptr; + if (UpgradeGlobalVariable(&GV, Upgraded)) UpgradedVariables.emplace_back(&GV, Upgraded); + } for (auto &Pair : UpgradedVariables) { Pair.first->eraseFromParent(); - TheModule->getGlobalList().push_back(Pair.second); + if (Pair.second) + TheModule->getGlobalList().push_back(Pair.second); } // Force deallocation of memory for these vectors to favor the client that Index: llvm/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2598,6 +2598,14 @@ Record.push_back(VE.getTypeID(BA->getFunction()->getType())); Record.push_back(VE.getValueID(BA->getFunction())); Record.push_back(VE.getGlobalBasicBlockID(BA->getBasicBlock())); + } else if (const ConstantPtrAuth *SP = dyn_cast(C)) { + Code = bitc::CST_CODE_SIGNED_PTR; + Record.push_back(VE.getTypeID(SP->getPointer()->getType())); + Record.push_back(VE.getValueID(SP->getPointer())); + Record.push_back(SP->getKey()->getZExtValue()); + Record.push_back(VE.getTypeID(SP->getAddrDiscriminator()->getType())); + Record.push_back(VE.getValueID(SP->getAddrDiscriminator())); + Record.push_back(SP->getDiscriminator()->getZExtValue()); } else { #ifndef NDEBUG C->dump(); Index: llvm/lib/IR/AsmWriter.cpp =================================================================== --- llvm/lib/IR/AsmWriter.cpp +++ llvm/lib/IR/AsmWriter.cpp @@ -1462,6 +1462,22 @@ return; } + if (const ConstantPtrAuth *SP = dyn_cast(CV)) { + Out << "ptrauth ("; + + for (unsigned i = 0; i < SP->getNumOperands(); ++i) { + TypePrinter.print(SP->getOperand(i)->getType(), Out); + Out << ' '; + WriteAsOperandInternal(Out, SP->getOperand(i), &TypePrinter, Machine, + Context); + if (i != SP->getNumOperands() - 1) + Out << ", "; + } + + Out << ')'; + return; + } + if (const ConstantArray *CA = dyn_cast(CV)) { Type *ETy = CA->getType()->getElementType(); Out << '['; Index: llvm/lib/IR/AutoUpgrade.cpp =================================================================== --- llvm/lib/IR/AutoUpgrade.cpp +++ llvm/lib/IR/AutoUpgrade.cpp @@ -978,17 +978,63 @@ return Upgraded; } -GlobalVariable *llvm::UpgradeGlobalVariable(GlobalVariable *GV) { +bool llvm::UpgradeGlobalVariable(GlobalVariable *GV, GlobalVariable *&NewGV) { + if (GV->getSection() == "llvm.ptrauth") { + auto &Ctx = GV->getContext(); + + if (!GV->hasInitializer()) + return false; + + auto *Init = GV->getInitializer(); + auto *Ty = dyn_cast(GV->getInitializer()->getType()); + if (!Ty) + return false; + + auto *I64Ty = Type::getInt64Ty(Ctx); + auto *I32Ty = Type::getInt32Ty(Ctx); + auto *P0I8Ty = Type::getInt8PtrTy(Ctx); + // Check that the struct matches its expected shape: + // { i8*, i32, i64, i64 } + if (!Ty->isLayoutIdentical( + StructType::get(Ctx, {P0I8Ty, I32Ty, I64Ty, I64Ty}))) + return false; + + auto Pointer = cast(Init->getOperand(0)); + Pointer = Pointer->stripPointerCasts(); + + auto *Key = dyn_cast(Init->getOperand(1)); + if (!Key) + return false; + + auto *AddrDiscriminator = cast(Init->getOperand(2)); + if (!isa(AddrDiscriminator) && + !isa(AddrDiscriminator)) + return false; + + auto *Discriminator = dyn_cast(Init->getOperand(3)); + if (!Discriminator) + return false; + + auto *I16Ty = Type::getInt16Ty(Ctx); + AddrDiscriminator = ConstantExpr::getIntToPtr(AddrDiscriminator, P0I8Ty); + Discriminator = ConstantInt::get(I16Ty, Discriminator->getZExtValue()); + auto *SP = + ConstantPtrAuth::get(Pointer, Key, AddrDiscriminator, Discriminator); + + GV->replaceAllUsesWith(ConstantExpr::getBitCast(SP, GV->getType())); + return true; + } + if (!(GV->hasName() && (GV->getName() == "llvm.global_ctors" || GV->getName() == "llvm.global_dtors")) || !GV->hasInitializer()) - return nullptr; + return false; ArrayType *ATy = dyn_cast(GV->getValueType()); if (!ATy) - return nullptr; + return false; StructType *STy = dyn_cast(ATy->getElementType()); if (!STy || STy->getNumElements() != 2) - return nullptr; + return false; LLVMContext &C = GV->getContext(); IRBuilder<> IRB(C); @@ -1005,8 +1051,9 @@ } Constant *NewInit = ConstantArray::get(ArrayType::get(EltTy, N), NewCtors); - return new GlobalVariable(NewInit->getType(), false, GV->getLinkage(), - NewInit, GV->getName()); + NewGV = new GlobalVariable(NewInit->getType(), false, GV->getLinkage(), + NewInit, GV->getName()); + return true; } // Handles upgrading SSE2/AVX2/AVX512BW PSLLDQ intrinsics by converting them Index: llvm/lib/IR/ConstantFold.cpp =================================================================== --- llvm/lib/IR/ConstantFold.cpp +++ llvm/lib/IR/ConstantFold.cpp @@ -1685,9 +1685,9 @@ if (V1 == V2) return ICmpInst::ICMP_EQ; if (!isa(V1) && !isa(V1) && - !isa(V1)) { + !isa(V1) && !isa(V1)) { if (!isa(V2) && !isa(V2) && - !isa(V2)) { + !isa(V2) && !isa(V2)) { // We distilled this down to a simple case, use the standard constant // folder. ConstantInt *R = nullptr; @@ -1766,6 +1766,8 @@ "Canonicalization guarantee!"); return ICmpInst::ICMP_NE; } + } else if (const ConstantPtrAuth *SP = dyn_cast(V1)) { + return ICmpInst::BAD_ICMP_PREDICATE; } else { // Ok, the LHS is known to be a constantexpr. The RHS can be any of a // constantexpr, a global, block address, or a simple constant. Index: llvm/lib/IR/Constants.cpp =================================================================== --- llvm/lib/IR/Constants.cpp +++ llvm/lib/IR/Constants.cpp @@ -519,6 +519,9 @@ case Constant::DSOLocalEquivalentVal: delete static_cast(C); break; + case Constant::ConstantPtrAuthVal: + delete static_cast(C); + break; case Constant::UndefValueVal: delete static_cast(C); break; @@ -1880,6 +1883,127 @@ return nullptr; } +//---- ConstantPtrAuth::get() implementations. +// + +static bool areEquivalentAddrDiscriminators(const Value *V1, const Value *V2, + const DataLayout &DL) { + APInt V1Off(DL.getPointerSizeInBits(), 0); + APInt V2Off(DL.getPointerSizeInBits(), 0); + + if (auto *V1Cast = dyn_cast(V1)) + V1 = V1Cast->getPointerOperand(); + if (auto *V2Cast = dyn_cast(V2)) + V2 = V2Cast->getPointerOperand(); + auto *V1Base = V1->stripAndAccumulateConstantOffsets( + DL, V1Off, /*AllowNonInbounds=*/true); + auto *V2Base = V2->stripAndAccumulateConstantOffsets( + DL, V2Off, /*AllowNonInbounds=*/true); + return V1Base == V2Base && V1Off == V2Off; +} + +static bool areEquivalentDiscriminators(const ConstantInt *D1, + const Value *D2) { + if (auto D2C = dyn_cast(D2)) + return D2C->getZExtValue() == D1->getZExtValue(); + return false; +} + +bool ConstantPtrAuth::isCompatibleWith(const Value *Key, + const Value *Discriminator, + const DataLayout &DL) const { + // If the keys are different, there's no chance for this to be compatible. + if (Key != getKey()) + return false; + + // If the discriminators are the same, this is compatible iff there is no + // address discriminator. + if (areEquivalentDiscriminators(getDiscriminator(), Discriminator)) + return getAddrDiscriminator()->isNullValue(); + + // If we don't have a non-address discriminator, we don't need a blend in + // the first place: accept the address discriminator as the discriminator. + if (getDiscriminator()->isNullValue() && + areEquivalentAddrDiscriminators(getAddrDiscriminator(), Discriminator, + DL)) + return true; + + // Otherwise, we don't know. + return false; +} + +bool ConstantPtrAuth::hasSpecialAddressDiscriminator(uint64_t value) const { + auto *CastV = dyn_cast(getAddrDiscriminator()); + if (!CastV || CastV->getOpcode() != Instruction::IntToPtr) + return false; + + auto IntVal = dyn_cast(CastV->getOperand(0)); + if (!IntVal) + return false; + + return IntVal->getValue() == value; +} + +ConstantPtrAuth *ConstantPtrAuth::getWithSameSchema(Constant *Pointer) const { + return get(Pointer, getKey(), getAddrDiscriminator(), getDiscriminator()); +} + +ConstantPtrAuth *ConstantPtrAuth::get(Constant *Ptr, ConstantInt *Key, + Constant *AddrDisc, ConstantInt *Disc) { + Constant *ArgVec[] = {Ptr, Key, AddrDisc, Disc}; + ConstantPtrAuthKeyType MapKey(ArgVec); + LLVMContextImpl *pImpl = Ptr->getContext().pImpl; + return pImpl->ConstantPtrAuths.getOrCreate(Ptr->getType(), MapKey); +} + +ConstantPtrAuth::ConstantPtrAuth(Constant *Ptr, ConstantInt *Key, + Constant *AddrDisc, ConstantInt *Disc) + : Constant(Ptr->getType(), Value::ConstantPtrAuthVal, &Op<0>(), 4) { +#ifndef NDEBUG + assert(Ptr->getType()->isPointerTy()); + assert(Key->getBitWidth() == 32); + assert(AddrDisc->getType()->isPointerTy()); + assert(Disc->getBitWidth() == 16); +#endif + setOperand(0, Ptr); + setOperand(1, Key); + setOperand(2, AddrDisc); + setOperand(3, Disc); +} + +/// Remove the constant from the constant table. +void ConstantPtrAuth::destroyConstantImpl() { + getType()->getContext().pImpl->ConstantPtrAuths.remove(this); +} + +Value *ConstantPtrAuth::handleOperandChangeImpl(Value *From, Value *ToV) { + assert(isa(ToV) && "Cannot make Constant refer to non-constant!"); + Constant *To = cast(ToV); + + SmallVector Values; + Values.reserve(getNumOperands()); // Build replacement array. + + // Fill values with the modified operands of the constant array. Also, + // compute whether this turns into an all-zeros array. + unsigned NumUpdated = 0; + + Use *OperandList = getOperandList(); + unsigned OperandNo = 0; + for (Use *O = OperandList, *E = OperandList + getNumOperands(); O != E; ++O) { + Constant *Val = cast(O->get()); + if (Val == From) { + OperandNo = (O - OperandList); + Val = To; + ++NumUpdated; + } + Values.push_back(Val); + } + + // FIXME: shouldn't we check it's not already there? + return getContext().pImpl->ConstantPtrAuths.replaceOperandsInPlace( + Values, this, From, To, NumUpdated, OperandNo); +} + //---- ConstantExpr::get() implementations. // Index: llvm/lib/IR/ConstantsContext.h =================================================================== --- llvm/lib/IR/ConstantsContext.h +++ llvm/lib/IR/ConstantsContext.h @@ -24,6 +24,7 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/GlobalVariable.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -393,6 +394,7 @@ template struct ConstantAggrKeyType; struct InlineAsmKeyType; struct ConstantExprKeyType; +struct ConstantPtrAuthKeyType; template struct ConstantInfo; template <> struct ConstantInfo { @@ -415,6 +417,10 @@ using ValType = ConstantAggrKeyType; using TypeClass = VectorType; }; +template <> struct ConstantInfo { + using ValType = ConstantPtrAuthKeyType; + using TypeClass = Type; +}; template struct ConstantAggrKeyType { ArrayRef Operands; @@ -640,6 +646,47 @@ } }; +struct ConstantPtrAuthKeyType { + ArrayRef Operands; + + ConstantPtrAuthKeyType(ArrayRef Operands) : Operands(Operands) {} + + ConstantPtrAuthKeyType(ArrayRef Operands, const ConstantPtrAuth *) + : Operands(Operands) {} + + ConstantPtrAuthKeyType(const ConstantPtrAuth *C, + SmallVectorImpl &Storage) { + assert(Storage.empty() && "Expected empty storage"); + for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) + Storage.push_back(cast(C->getOperand(I))); + Operands = Storage; + } + + bool operator==(const ConstantPtrAuthKeyType &X) const { + return Operands == X.Operands; + } + + bool operator==(const ConstantPtrAuth *C) const { + if (Operands.size() != C->getNumOperands()) + return false; + for (unsigned I = 0, E = Operands.size(); I != E; ++I) + if (Operands[I] != C->getOperand(I)) + return false; + return true; + } + + unsigned getHash() const { + return hash_combine_range(Operands.begin(), Operands.end()); + } + + using TypeClass = typename ConstantInfo::TypeClass; + + ConstantPtrAuth *create(TypeClass *Ty) const { + return new ConstantPtrAuth(Operands[0], cast(Operands[1]), + Operands[2], cast(Operands[3])); + } +}; + // Free memory for a given constant. Assumes the constant has already been // removed from all relevant maps. void deleteConstant(Constant *C); Index: llvm/lib/IR/LLVMContextImpl.h =================================================================== --- llvm/lib/IR/LLVMContextImpl.h +++ llvm/lib/IR/LLVMContextImpl.h @@ -1404,6 +1404,8 @@ DenseMap DSOLocalEquivalents; + ConstantUniqueMap ConstantPtrAuths; + ConstantUniqueMap ExprConstants; ConstantUniqueMap InlineAsms; Index: llvm/lib/IR/Verifier.cpp =================================================================== --- llvm/lib/IR/Verifier.cpp +++ llvm/lib/IR/Verifier.cpp @@ -517,6 +517,7 @@ void visitConstantExprsRecursively(const Constant *EntryC); void visitConstantExpr(const ConstantExpr *CE); + void visitConstantPtrAuth(const ConstantPtrAuth *SP); void verifyStatepoint(const CallBase &Call); void verifyFrameRecoverIndices(); void verifySiblingFuncletUnwinds(); @@ -2042,6 +2043,9 @@ if (const auto *CE = dyn_cast(C)) visitConstantExpr(CE); + if (const auto *SP = dyn_cast(C)) + visitConstantPtrAuth(SP); + if (const auto *GV = dyn_cast(C)) { // Global Values get visited separately, but we do need to make sure // that the global value is in the correct module @@ -2082,6 +2086,20 @@ } } +void Verifier::visitConstantPtrAuth(const ConstantPtrAuth *SP) { + Assert(SP->getPointer()->getType()->isPointerTy(), + "signed pointer must be a pointer"); + + Assert(SP->getKey()->getBitWidth() == 32, + "signed pointer key must be i32 constant integer"); + + Assert(SP->getAddrDiscriminator()->getType()->isPointerTy(), + "signed pointer address discriminator must be a pointer"); + + Assert(SP->getDiscriminator()->getBitWidth() == 16, + "signed pointer discriminator must be i16 constant integer"); +} + bool Verifier::verifyAttributeCount(AttributeList Attrs, unsigned Params) { // There shouldn't be more attribute sets than there are parameters plus the // function and return value. @@ -4372,6 +4390,8 @@ } else if (isa(I.getOperand(i))) { Assert(CBI && &CBI->getCalledOperandUse() == &I.getOperandUse(i), "Cannot take the address of an inline asm!", &I); + } else if (auto SP = dyn_cast(I.getOperand(i))) { + visitConstantExprsRecursively(SP); } else if (ConstantExpr *CE = dyn_cast(I.getOperand(i))) { if (CE->getType()->isPtrOrPtrVectorTy() || !DL.getNonIntegralAddressSpaces().empty()) { Index: llvm/test/Assembler/invalid-ptrauth-const1.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/invalid-ptrauth-const1.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +@var = global i32 0 + +; CHECK: error: signed pointer must be a pointer +@auth_var = global i32* ptrauth (i32 42, i32 0, i8* null, i16 65535) Index: llvm/test/Assembler/invalid-ptrauth-const2.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/invalid-ptrauth-const2.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +@var = global i32 0 + +; CHECK: error: signed pointer key must be i32 constant integer +@auth_var = global i32* ptrauth (i32* @var, i32 ptrtoint(i32* @var to i32), i8* null, i16 65535) Index: llvm/test/Assembler/invalid-ptrauth-const3.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/invalid-ptrauth-const3.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +@var = global i32 0 + +; CHECK: error: signed pointer address discriminator must be a pointer +@auth_var = global i32* ptrauth (i32* @var, i32 2, i8 0, i16 65535) Index: llvm/test/Assembler/invalid-ptrauth-const4.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/invalid-ptrauth-const4.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +@var = global i32 0 + +; CHECK: error: signed pointer address discriminator must be a pointer +@auth_var = global i32* ptrauth (i32* @var, i32 2, i8 0, i16 65535) Index: llvm/test/Assembler/invalid-ptrauth-const5.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/invalid-ptrauth-const5.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +@var = global i32 0 + +; CHECK: error: signed pointer discriminator must be i16 constant integer +@auth_var = global i32* ptrauth (i32* @var, i32 2, i8* null, i16 ptrtoint(i32* @var to i16)) Index: llvm/test/Assembler/invalid-ptrauth-const6.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/invalid-ptrauth-const6.ll @@ -0,0 +1,6 @@ +; RUN: not llvm-as < %s 2>&1 | FileCheck %s + +@var = global i32 0 + +; CHECK: error: signed pointer address discriminator must be a pointer +@auth_var = global i32* ptrauth (i32* @var, i32 2, i8 0, i32 1000000) Index: llvm/test/Assembler/ptrauth-const.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/ptrauth-const.ll @@ -0,0 +1,13 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +@var = global i32 0 + +; CHECK: @auth_var = global i32* ptrauth (i32* @var, i32 0, i8* null, i16 -1) +@auth_var = global i32* ptrauth (i32* @var, i32 0, i8* null, i16 65535) + + +; CHECK: @addrdisc_var = global i32* ptrauth (i32* @var, i32 0, i32** @addrdisc_var, i16 1234) +@addrdisc_var = global i32* ptrauth (i32* @var, i32 0, i32** @addrdisc_var, i16 1234) + +; CHECK: @keyed_var = global i32* ptrauth (i32* @var, i32 3, i8* null, i16 0) +@keyed_var = global i32* ptrauth (i32* @var, i32 3, i8* null, i16 0) Index: llvm/test/Bitcode/compatibility.ll =================================================================== --- llvm/test/Bitcode/compatibility.ll +++ llvm/test/Bitcode/compatibility.ll @@ -203,6 +203,10 @@ @llvm.global_dtors = appending global [1 x %pri.func.data] [%pri.func.data { i32 0, void ()* @g.f1, i8* @g.used3 }], section "llvm.metadata" ; CHECK: @llvm.global_dtors = appending global [1 x %pri.func.data] [%pri.func.data { i32 0, void ()* @g.f1, i8* @g.used3 }], section "llvm.metadata" +; ptrauth constant +@auth_var = global i32* ptrauth (i32* @g1, i32 0, i8* null, i16 65535) +; CHECK: @auth_var = global i32* ptrauth (i32* @g1, i32 0, i8* null, i16 -1) + ;; Aliases ; Format: @ = [Linkage] [Visibility] [DLLStorageClass] [ThreadLocal] ; [unnamed_addr] alias @ @@ -1861,6 +1865,7 @@ ; CHECK: declare void @byval_type2({ i8, i8* }* byval({ i8, i8* })) ; CHECK: declare void @byval_named_type([8 x i8]* byval([8 x i8])) + ; CHECK: attributes #0 = { alignstack=4 } ; CHECK: attributes #1 = { alignstack=8 } ; CHECK: attributes #2 = { alwaysinline } Index: llvm/test/Bitcode/upgrade-ptrauth-global.ll =================================================================== --- /dev/null +++ llvm/test/Bitcode/upgrade-ptrauth-global.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s + +@var = global i32 0 + +@var.auth1 = constant { i8*, i32, i64, i64 } { i8* bitcast(i32* @var to i8*), + i32 0, + i64 0, + i64 1234 }, section "llvm.ptrauth" +@var_auth = global i32* bitcast({i8*, i32, i64, i64}* @var.auth1 to i32*) +; CHECK: @var_auth = global i32* ptrauth (i32* @var, i32 0, i8* null, i16 1234)