mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
640 lines
24 KiB
C++
640 lines
24 KiB
C++
//===--- GenPointerAuth.cpp - IRGen for pointer authentication ------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file implements general support for pointer authentication in Swift.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "GenPointerAuth.h"
|
|
#include "Callee.h"
|
|
#include "ConstantBuilder.h"
|
|
#include "GenType.h"
|
|
#include "IRGenFunction.h"
|
|
#include "IRGenMangler.h"
|
|
#include "IRGenModule.h"
|
|
#include "swift/AST/GenericEnvironment.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
#include "swift/SIL/TypeLowering.h"
|
|
#include "clang/CodeGen/CodeGenABITypes.h"
|
|
#include "llvm/ADT/APInt.h"
|
|
#include "llvm/Support/SipHash.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
using namespace swift;
|
|
using namespace irgen;
|
|
|
|
/**************************** INTRINSIC OPERATIONS ****************************/
|
|
|
|
/// Return the key and discriminator value for the given auth info,
|
|
/// as demanded by the ptrauth intrinsics.
|
|
static std::pair<llvm::Constant*, llvm::Value*>
|
|
getPointerAuthPair(IRGenFunction &IGF, const PointerAuthInfo &authInfo) {
|
|
auto key = llvm::ConstantInt::get(IGF.IGM.Int32Ty, authInfo.getKey());
|
|
llvm::Value *discriminator = authInfo.getDiscriminator();
|
|
if (discriminator->getType()->isPointerTy()) {
|
|
discriminator = IGF.Builder.CreatePtrToInt(discriminator, IGF.IGM.Int64Ty);
|
|
}
|
|
return { key, discriminator };
|
|
}
|
|
|
|
llvm::Value *irgen::emitPointerAuthBlend(IRGenFunction &IGF,
|
|
llvm::Value *address,
|
|
llvm::Value *other) {
|
|
address = IGF.Builder.CreatePtrToInt(address, IGF.IGM.Int64Ty);
|
|
return IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_blend,
|
|
{address, other});
|
|
}
|
|
|
|
llvm::Value *irgen::emitPointerAuthStrip(IRGenFunction &IGF,
|
|
llvm::Value *fnPtr,
|
|
unsigned Key) {
|
|
auto fnVal = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
|
|
auto keyArg = llvm::ConstantInt::get(IGF.IGM.Int32Ty, Key);
|
|
auto strippedPtr = IGF.Builder.CreateIntrinsicCall(
|
|
llvm::Intrinsic::ptrauth_strip, {fnVal, keyArg});
|
|
return IGF.Builder.CreateIntToPtr(strippedPtr, fnPtr->getType());
|
|
}
|
|
|
|
FunctionPointer irgen::emitPointerAuthResign(IRGenFunction &IGF,
|
|
const FunctionPointer &fn,
|
|
const PointerAuthInfo &newAuthInfo) {
|
|
llvm::Value *fnPtr = emitPointerAuthResign(IGF, fn.getRawPointer(),
|
|
fn.getAuthInfo(), newAuthInfo);
|
|
return FunctionPointer::createSigned(fn.getKind(), fnPtr, newAuthInfo,
|
|
fn.getSignature());
|
|
}
|
|
|
|
llvm::Value *irgen::emitPointerAuthResign(IRGenFunction &IGF,
|
|
llvm::Value *fnPtr,
|
|
const PointerAuthInfo &oldAuthInfo,
|
|
const PointerAuthInfo &newAuthInfo) {
|
|
// If the signatures match, there's nothing to do.
|
|
if (oldAuthInfo == newAuthInfo)
|
|
return fnPtr;
|
|
|
|
// If the pointer is not currently signed, sign it.
|
|
if (!oldAuthInfo.isSigned()) {
|
|
return emitPointerAuthSign(IGF, fnPtr, newAuthInfo);
|
|
}
|
|
|
|
// If the pointer is not supposed to be signed, auth it.
|
|
if (!newAuthInfo.isSigned()) {
|
|
return emitPointerAuthAuth(IGF, fnPtr, oldAuthInfo);
|
|
}
|
|
|
|
// Otherwise, auth and resign it.
|
|
auto origTy = fnPtr->getType();
|
|
fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
|
|
|
|
auto oldPair = getPointerAuthPair(IGF, oldAuthInfo);
|
|
auto newPair = getPointerAuthPair(IGF, newAuthInfo);
|
|
|
|
llvm::Value *args[] = {
|
|
fnPtr, oldPair.first, oldPair.second, newPair.first, newPair.second
|
|
};
|
|
fnPtr =
|
|
IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_resign, args);
|
|
return IGF.Builder.CreateIntToPtr(fnPtr, origTy);
|
|
}
|
|
|
|
llvm::Value *irgen::emitPointerAuthAuth(IRGenFunction &IGF, llvm::Value *fnPtr,
|
|
const PointerAuthInfo &oldAuthInfo) {
|
|
auto origTy = fnPtr->getType();
|
|
fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
|
|
|
|
auto oldPair = getPointerAuthPair(IGF, oldAuthInfo);
|
|
|
|
llvm::Value *args[] = {
|
|
fnPtr, oldPair.first, oldPair.second
|
|
};
|
|
fnPtr = IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_auth, args);
|
|
return IGF.Builder.CreateIntToPtr(fnPtr, origTy);
|
|
}
|
|
|
|
llvm::Value *irgen::emitPointerAuthSign(IRGenFunction &IGF, llvm::Value *fnPtr,
|
|
const PointerAuthInfo &newAuthInfo) {
|
|
if (!newAuthInfo.isSigned())
|
|
return fnPtr;
|
|
|
|
// Special-case constants.
|
|
if (auto constantFnPtr = dyn_cast<llvm::Constant>(fnPtr)) {
|
|
if (auto constantDiscriminator =
|
|
dyn_cast<llvm::Constant>(newAuthInfo.getDiscriminator())) {
|
|
llvm::Constant *address = nullptr;
|
|
llvm::ConstantInt *other = nullptr;
|
|
if (constantDiscriminator->getType()->isPointerTy()) {
|
|
address = constantDiscriminator;
|
|
} else if (auto otherDiscriminator =
|
|
dyn_cast<llvm::ConstantInt>(constantDiscriminator)) {
|
|
other = otherDiscriminator;
|
|
}
|
|
return IGF.IGM.getConstantSignedPointer(constantFnPtr,
|
|
newAuthInfo.getKey(),
|
|
address, other);
|
|
}
|
|
}
|
|
|
|
auto origTy = fnPtr->getType();
|
|
fnPtr = IGF.Builder.CreatePtrToInt(fnPtr, IGF.IGM.Int64Ty);
|
|
|
|
auto newPair = getPointerAuthPair(IGF, newAuthInfo);
|
|
|
|
llvm::Value *args[] = {
|
|
fnPtr, newPair.first, newPair.second
|
|
};
|
|
fnPtr = IGF.Builder.CreateIntrinsicCall(llvm::Intrinsic::ptrauth_sign, args);
|
|
return IGF.Builder.CreateIntToPtr(fnPtr, origTy);
|
|
}
|
|
|
|
/******************************* DISCRIMINATORS *******************************/
|
|
|
|
struct IRGenModule::PointerAuthCachesType {
|
|
llvm::DenseMap<SILDeclRef, llvm::ConstantInt*> Decls;
|
|
llvm::DenseMap<CanType, llvm::ConstantInt*> Types;
|
|
llvm::DenseMap<CanType, llvm::ConstantInt*> YieldTypes;
|
|
llvm::DenseMap<AssociatedTypeDecl *, llvm::ConstantInt*> AssociatedTypes;
|
|
llvm::DenseMap<AssociatedConformance, llvm::ConstantInt*> AssociatedConformances;
|
|
};
|
|
|
|
IRGenModule::PointerAuthCachesType &IRGenModule::getPointerAuthCaches() {
|
|
if (!PointerAuthCaches)
|
|
PointerAuthCaches = new PointerAuthCachesType();
|
|
return *PointerAuthCaches;
|
|
}
|
|
|
|
void IRGenModule::destroyPointerAuthCaches() {
|
|
delete PointerAuthCaches;
|
|
}
|
|
|
|
static const PointerAuthSchema &getFunctionPointerSchema(IRGenModule &IGM,
|
|
CanSILFunctionType fnType) {
|
|
auto &options = IGM.getOptions().PointerAuth;
|
|
switch (fnType->getRepresentation()) {
|
|
case SILFunctionTypeRepresentation::CXXMethod:
|
|
case SILFunctionTypeRepresentation::CFunctionPointer:
|
|
return options.FunctionPointers;
|
|
|
|
case SILFunctionTypeRepresentation::Thin:
|
|
case SILFunctionTypeRepresentation::Thick:
|
|
case SILFunctionTypeRepresentation::Method:
|
|
case SILFunctionTypeRepresentation::WitnessMethod:
|
|
case SILFunctionTypeRepresentation::Closure:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorGetter:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorSetter:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorEquals:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorHash:
|
|
if (fnType->isAsync()) {
|
|
return options.AsyncSwiftFunctionPointers;
|
|
} else if (fnType->isCalleeAllocatedCoroutine()) {
|
|
return options.CoroSwiftFunctionPointers;
|
|
}
|
|
|
|
return options.SwiftFunctionPointers;
|
|
|
|
case SILFunctionTypeRepresentation::ObjCMethod:
|
|
case SILFunctionTypeRepresentation::Block:
|
|
llvm_unreachable("not just a function pointer");
|
|
}
|
|
llvm_unreachable("bad representation");
|
|
}
|
|
|
|
PointerAuthInfo PointerAuthInfo::forFunctionPointer(IRGenModule &IGM,
|
|
CanSILFunctionType fnType) {
|
|
auto &schema = getFunctionPointerSchema(IGM, fnType);
|
|
|
|
// If the target doesn't sign function pointers, we're done.
|
|
if (!schema) return PointerAuthInfo();
|
|
|
|
assert(!schema.isAddressDiscriminated() &&
|
|
"function pointer cannot be address-discriminated");
|
|
|
|
auto discriminator = getOtherDiscriminator(IGM, schema, fnType);
|
|
return PointerAuthInfo(schema.getKey(), discriminator);
|
|
}
|
|
|
|
PointerAuthInfo PointerAuthInfo::emit(IRGenFunction &IGF,
|
|
const PointerAuthSchema &schema,
|
|
llvm::Value *storageAddress,
|
|
const PointerAuthEntity &entity) {
|
|
if (!schema) return PointerAuthInfo();
|
|
|
|
unsigned key = schema.getKey();
|
|
|
|
// Produce the 'other' discriminator.
|
|
auto otherDiscriminator = getOtherDiscriminator(IGF.IGM, schema, entity);
|
|
llvm::Value *discriminator = otherDiscriminator;
|
|
|
|
// Factor in the address.
|
|
if (schema.isAddressDiscriminated()) {
|
|
assert(storageAddress &&
|
|
"no storage address for address-discriminated schema");
|
|
|
|
if (!otherDiscriminator->isZero()) {
|
|
discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator);
|
|
} else {
|
|
discriminator =
|
|
IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.Int64Ty);
|
|
}
|
|
}
|
|
|
|
return PointerAuthInfo(key, discriminator);
|
|
}
|
|
|
|
PointerAuthInfo
|
|
PointerAuthInfo::emit(IRGenFunction &IGF,
|
|
clang::PointerAuthQualifier pointerAuthQual,
|
|
llvm::Value *storageAddress) {
|
|
unsigned key = pointerAuthQual.getKey();
|
|
|
|
// Produce the 'other' discriminator.
|
|
auto otherDiscriminator = pointerAuthQual.getExtraDiscriminator();
|
|
llvm::Value *discriminator =
|
|
llvm::ConstantInt::get(IGF.IGM.Int64Ty, otherDiscriminator);
|
|
|
|
// Factor in the address.
|
|
if (pointerAuthQual.isAddressDiscriminated()) {
|
|
assert(storageAddress &&
|
|
"no storage address for address-discriminated schema");
|
|
|
|
if (otherDiscriminator != 0) {
|
|
discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator);
|
|
} else {
|
|
discriminator =
|
|
IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.Int64Ty);
|
|
}
|
|
}
|
|
|
|
return PointerAuthInfo(key, discriminator);
|
|
}
|
|
|
|
PointerAuthInfo PointerAuthInfo::emit(IRGenFunction &IGF,
|
|
const PointerAuthSchema &schema,
|
|
llvm::Value *storageAddress,
|
|
llvm::ConstantInt *otherDiscriminator) {
|
|
if (!schema)
|
|
return PointerAuthInfo();
|
|
|
|
unsigned key = schema.getKey();
|
|
|
|
llvm::Value *discriminator = otherDiscriminator;
|
|
|
|
// Factor in the address.
|
|
if (schema.isAddressDiscriminated()) {
|
|
assert(storageAddress &&
|
|
"no storage address for address-discriminated schema");
|
|
|
|
if (!otherDiscriminator->isZero()) {
|
|
discriminator = emitPointerAuthBlend(IGF, storageAddress, discriminator);
|
|
} else {
|
|
discriminator =
|
|
IGF.Builder.CreatePtrToInt(storageAddress, IGF.IGM.Int64Ty);
|
|
}
|
|
}
|
|
|
|
return PointerAuthInfo(key, discriminator);
|
|
}
|
|
|
|
llvm::ConstantInt *
|
|
PointerAuthInfo::getOtherDiscriminator(IRGenModule &IGM,
|
|
const PointerAuthSchema &schema,
|
|
const PointerAuthEntity &entity) {
|
|
assert(schema);
|
|
switch (schema.getOtherDiscrimination()) {
|
|
case PointerAuthSchema::Discrimination::None:
|
|
return llvm::ConstantInt::get(IGM.Int64Ty, 0);
|
|
|
|
case PointerAuthSchema::Discrimination::Decl:
|
|
return entity.getDeclDiscriminator(IGM);
|
|
|
|
case PointerAuthSchema::Discrimination::Type:
|
|
return entity.getTypeDiscriminator(IGM);
|
|
|
|
case PointerAuthSchema::Discrimination::Constant:
|
|
return llvm::ConstantInt::get(IGM.Int64Ty,
|
|
schema.getConstantDiscrimination());
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
static llvm::ConstantInt *getDiscriminatorForString(IRGenModule &IGM,
|
|
StringRef string) {
|
|
return llvm::ConstantInt::get(IGM.Int64Ty,
|
|
llvm::getPointerAuthStableSipHash(string));
|
|
}
|
|
|
|
static std::string mangle(AssociatedTypeDecl *assocType) {
|
|
return IRGenMangler(assocType->getASTContext())
|
|
.mangleAssociatedTypeAccessFunctionDiscriminator(assocType);
|
|
}
|
|
|
|
static std::string mangle(const AssociatedConformance &association) {
|
|
return IRGenMangler(association.getAssociatedRequirement()->getASTContext())
|
|
.mangleAssociatedTypeWitnessTableAccessFunctionDiscriminator(association);
|
|
}
|
|
|
|
llvm::ConstantInt *
|
|
PointerAuthEntity::getDeclDiscriminator(IRGenModule &IGM) const {
|
|
switch (StoredKind) {
|
|
case Kind::None:
|
|
case Kind::CanSILFunctionType:
|
|
case Kind::CoroutineYieldTypes:
|
|
llvm_unreachable("no declaration for schema using decl discrimination");
|
|
|
|
case Kind::Special: {
|
|
auto getSpecialDiscriminator = [](Special special) -> uint16_t {
|
|
switch (special) {
|
|
case Special::HeapDestructor:
|
|
return SpecialPointerAuthDiscriminators::HeapDestructor;
|
|
case Special::TypeDescriptor:
|
|
case Special::TypeDescriptorAsArgument:
|
|
return SpecialPointerAuthDiscriminators::TypeDescriptor;
|
|
case Special::ProtocolConformanceDescriptor:
|
|
case Special::ProtocolConformanceDescriptorAsArgument:
|
|
return SpecialPointerAuthDiscriminators::ProtocolConformanceDescriptor;
|
|
case Special::ProtocolDescriptorAsArgument:
|
|
return SpecialPointerAuthDiscriminators::ProtocolDescriptor;
|
|
case Special::OpaqueTypeDescriptorAsArgument:
|
|
return SpecialPointerAuthDiscriminators::OpaqueTypeDescriptor;
|
|
case Special::ContextDescriptorAsArgument:
|
|
return SpecialPointerAuthDiscriminators::ContextDescriptor;
|
|
case Special::PartialApplyCapture:
|
|
return PointerAuthDiscriminator_PartialApplyCapture;
|
|
case Special::KeyPathDestroy:
|
|
return SpecialPointerAuthDiscriminators::KeyPathDestroy;
|
|
case Special::KeyPathCopy:
|
|
return SpecialPointerAuthDiscriminators::KeyPathCopy;
|
|
case Special::KeyPathEquals:
|
|
return SpecialPointerAuthDiscriminators::KeyPathEquals;
|
|
case Special::KeyPathHash:
|
|
return SpecialPointerAuthDiscriminators::KeyPathHash;
|
|
case Special::KeyPathGetter:
|
|
return SpecialPointerAuthDiscriminators::KeyPathGetter;
|
|
case Special::KeyPathNonmutatingSetter:
|
|
return SpecialPointerAuthDiscriminators::KeyPathNonmutatingSetter;
|
|
case Special::KeyPathMutatingSetter:
|
|
return SpecialPointerAuthDiscriminators::KeyPathMutatingSetter;
|
|
case Special::KeyPathGetLayout:
|
|
return SpecialPointerAuthDiscriminators::KeyPathGetLayout;
|
|
case Special::KeyPathInitializer:
|
|
return SpecialPointerAuthDiscriminators::KeyPathInitializer;
|
|
case Special::KeyPathMetadataAccessor:
|
|
return SpecialPointerAuthDiscriminators::KeyPathMetadataAccessor;
|
|
case Special::DynamicReplacementKey:
|
|
return SpecialPointerAuthDiscriminators::DynamicReplacementKey;
|
|
case Special::TypeLayoutString:
|
|
return SpecialPointerAuthDiscriminators::TypeLayoutString;
|
|
case Special::BlockCopyHelper:
|
|
case Special::BlockDisposeHelper:
|
|
llvm_unreachable("no known discriminator for these foreign entities");
|
|
case Special::CoroAllocationFunction:
|
|
return SpecialPointerAuthDiscriminators::CoroAllocationFunction;
|
|
case Special::CoroDeallocationFunction:
|
|
return SpecialPointerAuthDiscriminators::CoroDeallocationFunction;
|
|
case Special::CoroFrameAllocationFunction:
|
|
return SpecialPointerAuthDiscriminators::CoroFrameAllocationFunction;
|
|
case Special::CoroFrameDeallocationFunction:
|
|
return SpecialPointerAuthDiscriminators::CoroFrameDeallocationFunction;
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
};
|
|
auto specialKind = Storage.get<Special>(StoredKind);
|
|
return llvm::ConstantInt::get(IGM.Int64Ty,
|
|
getSpecialDiscriminator(specialKind));
|
|
}
|
|
|
|
case Kind::ValueWitness: {
|
|
auto getValueWitnessDiscriminator = [](ValueWitness witness) -> uint16_t {
|
|
switch (witness) {
|
|
#define WANT_ALL_VALUE_WITNESSES
|
|
#define DATA_VALUE_WITNESS(LOWER, UPPER, TYPE)
|
|
#define FUNCTION_VALUE_WITNESS(LOWER, ID, RET, PARAMS) \
|
|
case ValueWitness::ID: return SpecialPointerAuthDiscriminators::ID;
|
|
#include "swift/ABI/ValueWitness.def"
|
|
case ValueWitness::Size:
|
|
case ValueWitness::Flags:
|
|
case ValueWitness::Stride:
|
|
case ValueWitness::ExtraInhabitantCount:
|
|
llvm_unreachable("not a function value witness");
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
};
|
|
auto witness = Storage.get<ValueWitness>(StoredKind);
|
|
return llvm::ConstantInt::get(IGM.Int64Ty,
|
|
getValueWitnessDiscriminator(witness));
|
|
}
|
|
|
|
case Kind::AssociatedType: {
|
|
auto association = Storage.get<AssociatedTypeDecl *>(StoredKind);
|
|
llvm::ConstantInt *&cache =
|
|
IGM.getPointerAuthCaches().AssociatedTypes[association];
|
|
if (cache) return cache;
|
|
|
|
auto mangling = mangle(association);
|
|
cache = getDiscriminatorForString(IGM, mangling);
|
|
return cache;
|
|
}
|
|
|
|
case Kind::AssociatedConformance: {
|
|
auto conformance = Storage.get<AssociatedConformance>(StoredKind);
|
|
llvm::ConstantInt *&cache =
|
|
IGM.getPointerAuthCaches().AssociatedConformances[conformance];
|
|
if (cache) return cache;
|
|
|
|
auto mangling = mangle(conformance);
|
|
cache = getDiscriminatorForString(IGM, mangling);
|
|
return cache;
|
|
}
|
|
|
|
case Kind::SILDeclRef: {
|
|
auto constant = Storage.get<SILDeclRef>(StoredKind);
|
|
llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Decls[constant];
|
|
if (cache) return cache;
|
|
|
|
// Getting the discriminator for a foreign SILDeclRef just means
|
|
// converting it to a foreign declaration and asking Clang IRGen
|
|
// for the corresponding discriminator, but that's not completely
|
|
// trivial.
|
|
assert(!constant.isForeign &&
|
|
"discriminator for foreign declaration not supported yet!");
|
|
|
|
auto mangling = constant.mangle();
|
|
cache = getDiscriminatorForString(IGM, mangling);
|
|
return cache;
|
|
}
|
|
case Kind::SILFunction: {
|
|
auto fn = Storage.get<SILFunction*>(StoredKind);
|
|
return getDiscriminatorForString(IGM, fn->getName());
|
|
}
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
static llvm::ConstantInt *getTypeDiscriminator(IRGenModule &IGM,
|
|
CanSILFunctionType type) {
|
|
return llvm::ConstantInt::get(
|
|
IGM.Int64Ty, type->getPointerAuthDiscriminator(&IGM.getSILModule()));
|
|
}
|
|
|
|
static llvm::ConstantInt *
|
|
getCoroutineYieldTypesDiscriminator(IRGenModule &IGM, CanSILFunctionType type) {
|
|
return llvm::ConstantInt::get(
|
|
IGM.Int64Ty, type->getCoroutineYieldTypesDiscriminator(IGM.getSILModule()));
|
|
}
|
|
|
|
llvm::ConstantInt *
|
|
PointerAuthEntity::getTypeDiscriminator(IRGenModule &IGM) const {
|
|
auto getTypeDiscriminator = [&](CanSILFunctionType fnType) {
|
|
switch (fnType->getRepresentation()) {
|
|
// Swift function types are type-discriminated.
|
|
case SILFunctionTypeRepresentation::Thick:
|
|
case SILFunctionTypeRepresentation::Thin:
|
|
case SILFunctionTypeRepresentation::Method:
|
|
case SILFunctionTypeRepresentation::WitnessMethod:
|
|
case SILFunctionTypeRepresentation::Closure:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorGetter:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorSetter:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorEquals:
|
|
case SILFunctionTypeRepresentation::KeyPathAccessorHash: {
|
|
llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Types[fnType];
|
|
if (cache) return cache;
|
|
|
|
cache = ::getTypeDiscriminator(IGM, fnType);
|
|
return cache;
|
|
}
|
|
|
|
// C function pointers are undiscriminated.
|
|
case SILFunctionTypeRepresentation::CXXMethod:
|
|
case SILFunctionTypeRepresentation::CFunctionPointer:
|
|
return llvm::ConstantInt::get(IGM.Int64Ty, 0);
|
|
|
|
case SILFunctionTypeRepresentation::ObjCMethod:
|
|
case SILFunctionTypeRepresentation::Block: {
|
|
llvm_unreachable("not type discriminated");
|
|
}
|
|
}
|
|
llvm_unreachable("invalid representation");
|
|
};
|
|
|
|
switch (StoredKind) {
|
|
case Kind::None:
|
|
case Kind::Special:
|
|
case Kind::ValueWitness:
|
|
case Kind::AssociatedType:
|
|
case Kind::AssociatedConformance:
|
|
case Kind::SILFunction:
|
|
llvm_unreachable("no type for schema using type discrimination");
|
|
|
|
case Kind::CoroutineYieldTypes: {
|
|
auto fnType = Storage.get<CanSILFunctionType>(StoredKind);
|
|
|
|
llvm::ConstantInt *&cache = IGM.getPointerAuthCaches().Types[fnType];
|
|
if (cache)
|
|
return cache;
|
|
|
|
cache = getCoroutineYieldTypesDiscriminator(IGM, fnType);
|
|
return cache;
|
|
}
|
|
|
|
case Kind::CanSILFunctionType: {
|
|
auto fnType = Storage.get<CanSILFunctionType>(StoredKind);
|
|
return getTypeDiscriminator(fnType);
|
|
}
|
|
|
|
case Kind::SILDeclRef: {
|
|
SILDeclRef decl = Storage.get<SILDeclRef>(StoredKind);
|
|
auto fnType = IGM.getSILTypes().getConstantFunctionType(
|
|
TypeExpansionContext::minimal(), decl);
|
|
return getTypeDiscriminator(fnType);
|
|
}
|
|
}
|
|
llvm_unreachable("bad kind");
|
|
}
|
|
|
|
llvm::Constant *
|
|
IRGenModule::getConstantSignedFunctionPointer(llvm::Constant *fn,
|
|
CanSILFunctionType fnType) {
|
|
if (auto &schema = getFunctionPointerSchema(*this, fnType)) {
|
|
return getConstantSignedPointer(fn, schema, fnType, nullptr);
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
llvm::Constant *
|
|
IRGenModule::getConstantSignedCFunctionPointer(llvm::Constant *fn) {
|
|
if (auto &schema = getOptions().PointerAuth.FunctionPointers) {
|
|
assert(!schema.hasOtherDiscrimination());
|
|
return getConstantSignedPointer(fn, schema, PointerAuthEntity(), nullptr);
|
|
}
|
|
return fn;
|
|
}
|
|
|
|
llvm::Constant *
|
|
IRGenModule::getConstantSignedPointer(llvm::Constant *pointer, unsigned key,
|
|
llvm::Constant *storageAddress,
|
|
llvm::ConstantInt *otherDiscriminator) {
|
|
return clang::CodeGen::getConstantSignedPointer(getClangCGM(), pointer, key,
|
|
storageAddress,
|
|
otherDiscriminator);
|
|
}
|
|
|
|
llvm::Constant *IRGenModule::getConstantSignedPointer(llvm::Constant *pointer,
|
|
const PointerAuthSchema &schema,
|
|
const PointerAuthEntity &entity,
|
|
llvm::Constant *storageAddress) {
|
|
// If the schema doesn't sign pointers, do nothing.
|
|
if (!schema)
|
|
return pointer;
|
|
|
|
auto otherDiscriminator =
|
|
PointerAuthInfo::getOtherDiscriminator(*this, schema, entity);
|
|
return getConstantSignedPointer(pointer, schema.getKey(), storageAddress,
|
|
otherDiscriminator);
|
|
}
|
|
|
|
void ConstantAggregateBuilderBase::addSignedPointer(llvm::Constant *pointer,
|
|
const PointerAuthSchema &schema,
|
|
const PointerAuthEntity &entity) {
|
|
// If the schema doesn't sign pointers, do nothing.
|
|
if (!schema)
|
|
return add(pointer);
|
|
|
|
auto otherDiscriminator =
|
|
PointerAuthInfo::getOtherDiscriminator(IGM(), schema, entity);
|
|
addSignedPointer(pointer, schema.getKey(), schema.isAddressDiscriminated(),
|
|
otherDiscriminator);
|
|
}
|
|
|
|
void ConstantAggregateBuilderBase::addSignedPointer(llvm::Constant *pointer,
|
|
const PointerAuthSchema &schema,
|
|
uint16_t otherDiscriminator) {
|
|
// If the schema doesn't sign pointers, do nothing.
|
|
if (!schema)
|
|
return add(pointer);
|
|
|
|
addSignedPointer(pointer, schema.getKey(), schema.isAddressDiscriminated(),
|
|
llvm::ConstantInt::get(IGM().Int64Ty, otherDiscriminator));
|
|
}
|
|
|
|
llvm::ConstantInt *IRGenModule::getMallocTypeId(llvm::Function *fn) {
|
|
if (!getOptions().EmitTypeMallocForCoroFrame) {
|
|
// Even when typed malloc isn't enabled, a type id may be required for ABI
|
|
// reasons (e.g. as an argument to swift_coro_alloc). Use a cheaply
|
|
// materialized value.
|
|
return llvm::ConstantInt::get(Int64Ty, 0);
|
|
}
|
|
return getDiscriminatorForString(*this, fn->getName());
|
|
}
|
|
|
|
llvm::ConstantInt* IRGenFunction::getMallocTypeId() {
|
|
return IGM.getMallocTypeId(CurFn);
|
|
}
|