brintos

brintos / llvm-project-archived public Read only

0
0
Text · 29.8 KiB · a49a0c9 Raw
767 lines · cpp
1//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains common routines relating to the emission of10// pointer authentication operations.11//12//===----------------------------------------------------------------------===//13 14#include "CodeGenFunction.h"15#include "CodeGenModule.h"16#include "clang/CodeGen/CodeGenABITypes.h"17#include "clang/CodeGen/ConstantInitBuilder.h"18#include "llvm/Analysis/ValueTracking.h"19#include "llvm/Support/SipHash.h"20 21using namespace clang;22using namespace CodeGen;23 24/// Given a pointer-authentication schema, return a concrete "other"25/// discriminator for it.26llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator(27    const PointerAuthSchema &Schema, GlobalDecl Decl, QualType Type) {28  switch (Schema.getOtherDiscrimination()) {29  case PointerAuthSchema::Discrimination::None:30    return nullptr;31 32  case PointerAuthSchema::Discrimination::Type:33    assert(!Type.isNull() && "type not provided for type-discriminated schema");34    return llvm::ConstantInt::get(35        IntPtrTy, getContext().getPointerAuthTypeDiscriminator(Type));36 37  case PointerAuthSchema::Discrimination::Decl:38    assert(Decl.getDecl() &&39           "declaration not provided for decl-discriminated schema");40    return llvm::ConstantInt::get(IntPtrTy,41                                  getPointerAuthDeclDiscriminator(Decl));42 43  case PointerAuthSchema::Discrimination::Constant:44    return llvm::ConstantInt::get(IntPtrTy, Schema.getConstantDiscrimination());45  }46  llvm_unreachable("bad discrimination kind");47}48 49uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM,50                                                  QualType FunctionType) {51  return CGM.getContext().getPointerAuthTypeDiscriminator(FunctionType);52}53 54uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM,55                                                  GlobalDecl Declaration) {56  return CGM.getPointerAuthDeclDiscriminator(Declaration);57}58 59/// Return the "other" decl-specific discriminator for the given decl.60uint16_t61CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) {62  uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration];63 64  if (EntityHash == 0) {65    StringRef Name = getMangledName(Declaration);66    EntityHash = llvm::getPointerAuthStableSipHash(Name);67  }68 69  return EntityHash;70}71 72/// Return the abstract pointer authentication schema for a pointer to the given73/// function type.74CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {75  const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;76  if (!Schema)77    return CGPointerAuthInfo();78 79  assert(!Schema.isAddressDiscriminated() &&80         "function pointers cannot use address-specific discrimination");81 82  llvm::Constant *Discriminator = nullptr;83  if (T->isFunctionPointerType() || T->isFunctionReferenceType())84    T = T->getPointeeType();85  if (T->isFunctionType())86    Discriminator = getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), T);87 88  return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),89                           /*IsaPointer=*/false, /*AuthenticatesNull=*/false,90                           Discriminator);91}92 93llvm::Value *94CodeGenFunction::EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,95                                                   llvm::Value *Discriminator) {96  StorageAddress = Builder.CreatePtrToInt(StorageAddress, IntPtrTy);97  auto Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_blend);98  return Builder.CreateCall(Intrinsic, {StorageAddress, Discriminator});99}100 101/// Emit the concrete pointer authentication informaton for the102/// given authentication schema.103CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo(104    const PointerAuthSchema &Schema, llvm::Value *StorageAddress,105    GlobalDecl SchemaDecl, QualType SchemaType) {106  if (!Schema)107    return CGPointerAuthInfo();108 109  llvm::Value *Discriminator =110      CGM.getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType);111 112  if (Schema.isAddressDiscriminated()) {113    assert(StorageAddress &&114           "address not provided for address-discriminated schema");115 116    if (Discriminator)117      Discriminator =118          EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);119    else120      Discriminator = Builder.CreatePtrToInt(StorageAddress, IntPtrTy);121  }122 123  return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),124                           Schema.isIsaPointer(),125                           Schema.authenticatesNullValues(), Discriminator);126}127 128CGPointerAuthInfo129CodeGenFunction::EmitPointerAuthInfo(PointerAuthQualifier Qual,130                                     Address StorageAddress) {131  assert(Qual && "don't call this if you don't know that the Qual is present");132  if (Qual.hasKeyNone())133    return CGPointerAuthInfo();134 135  llvm::Value *Discriminator = nullptr;136  if (unsigned Extra = Qual.getExtraDiscriminator())137    Discriminator = llvm::ConstantInt::get(IntPtrTy, Extra);138 139  if (Qual.isAddressDiscriminated()) {140    assert(StorageAddress.isValid() &&141           "address discrimination without address");142    llvm::Value *StoragePtr = StorageAddress.emitRawPointer(*this);143    if (Discriminator)144      Discriminator =145          EmitPointerAuthBlendDiscriminator(StoragePtr, Discriminator);146    else147      Discriminator = Builder.CreatePtrToInt(StoragePtr, IntPtrTy);148  }149 150  return CGPointerAuthInfo(Qual.getKey(), Qual.getAuthenticationMode(),151                           Qual.isIsaPointer(), Qual.authenticatesNullValues(),152                           Discriminator);153}154 155/// Return the natural pointer authentication for values of the given156/// pointee type.157static CGPointerAuthInfo158getPointerAuthInfoForPointeeType(CodeGenModule &CGM, QualType PointeeType) {159  if (PointeeType.isNull())160    return CGPointerAuthInfo();161 162  // Function pointers use the function-pointer schema by default.163  if (PointeeType->isFunctionType())164    return CGM.getFunctionPointerAuthInfo(PointeeType);165 166  // Normal data pointers never use direct pointer authentication by default.167  return CGPointerAuthInfo();168}169 170CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {171  return ::getPointerAuthInfoForPointeeType(*this, T);172}173 174/// Return the natural pointer authentication for values of the given175/// pointer type.176static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,177                                                   QualType PointerType) {178  assert(PointerType->isSignableType(CGM.getContext()));179 180  // Block pointers are currently not signed.181  if (PointerType->isBlockPointerType())182    return CGPointerAuthInfo();183 184  auto PointeeType = PointerType->getPointeeType();185 186  if (PointeeType.isNull())187    return CGPointerAuthInfo();188 189  return ::getPointerAuthInfoForPointeeType(CGM, PointeeType);190}191 192CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {193  return ::getPointerAuthInfoForType(*this, T);194}195 196static std::pair<llvm::Value *, CGPointerAuthInfo>197emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV,198                            SourceLocation Loc) {199  llvm::Value *Value = CGF.EmitLoadOfScalar(LV, Loc);200  CGPointerAuthInfo AuthInfo;201  if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth())202    AuthInfo = CGF.EmitPointerAuthInfo(PtrAuth, LV.getAddress());203  else204    AuthInfo = getPointerAuthInfoForType(CGF.CGM, LV.getType());205  return {Value, AuthInfo};206}207 208/// Retrieve a pointer rvalue and its ptrauth info. When possible, avoid209/// needlessly resigning the pointer.210std::pair<llvm::Value *, CGPointerAuthInfo>211CodeGenFunction::EmitOrigPointerRValue(const Expr *E) {212  assert(E->getType()->isSignableType(getContext()));213 214  E = E->IgnoreParens();215  if (const auto *Load = dyn_cast<ImplicitCastExpr>(E)) {216    if (Load->getCastKind() == CK_LValueToRValue) {217      E = Load->getSubExpr()->IgnoreParens();218 219      // We're semantically required to not emit loads of certain DREs naively.220      if (const auto *RefExpr = dyn_cast<DeclRefExpr>(E)) {221        if (ConstantEmission Result = tryEmitAsConstant(RefExpr)) {222          // Fold away a use of an intermediate variable.223          if (!Result.isReference())224            return {Result.getValue(),225                    getPointerAuthInfoForType(CGM, RefExpr->getType())};226 227          // Fold away a use of an intermediate reference.228          LValue LV = Result.getReferenceLValue(*this, RefExpr);229          return emitLoadOfOrigPointerRValue(*this, LV, RefExpr->getLocation());230        }231      }232 233      // Otherwise, load and use the pointer234      LValue LV = EmitCheckedLValue(E, CodeGenFunction::TCK_Load);235      return emitLoadOfOrigPointerRValue(*this, LV, E->getExprLoc());236    }237  }238 239  // Fallback: just use the normal rules for the type.240  llvm::Value *Value = EmitScalarExpr(E);241  return {Value, getPointerAuthInfoForType(CGM, E->getType())};242}243 244llvm::Value *245CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier DestQualifier,246                                        const Expr *E,247                                        Address DestStorageAddress) {248  assert(DestQualifier);249  auto [Value, CurAuthInfo] = EmitOrigPointerRValue(E);250 251  CGPointerAuthInfo DestAuthInfo =252      EmitPointerAuthInfo(DestQualifier, DestStorageAddress);253  return emitPointerAuthResign(Value, E->getType(), CurAuthInfo, DestAuthInfo,254                               isPointerKnownNonNull(E));255}256 257llvm::Value *CodeGenFunction::EmitPointerAuthQualify(258    PointerAuthQualifier DestQualifier, llvm::Value *Value,259    QualType PointerType, Address DestStorageAddress, bool IsKnownNonNull) {260  assert(DestQualifier);261 262  CGPointerAuthInfo CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType);263  CGPointerAuthInfo DestAuthInfo =264      EmitPointerAuthInfo(DestQualifier, DestStorageAddress);265  return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo,266                               IsKnownNonNull);267}268 269llvm::Value *CodeGenFunction::EmitPointerAuthUnqualify(270    PointerAuthQualifier CurQualifier, llvm::Value *Value, QualType PointerType,271    Address CurStorageAddress, bool IsKnownNonNull) {272  assert(CurQualifier);273 274  CGPointerAuthInfo CurAuthInfo =275      EmitPointerAuthInfo(CurQualifier, CurStorageAddress);276  CGPointerAuthInfo DestAuthInfo = getPointerAuthInfoForType(CGM, PointerType);277  return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo,278                               IsKnownNonNull);279}280 281static bool isZeroConstant(const llvm::Value *Value) {282  if (const auto *CI = dyn_cast<llvm::ConstantInt>(Value))283    return CI->isZero();284  return false;285}286 287static bool equalAuthPolicies(const CGPointerAuthInfo &Left,288                              const CGPointerAuthInfo &Right) {289  assert((Left.isSigned() || Right.isSigned()) &&290         "shouldn't be called if neither is signed");291  if (Left.isSigned() != Right.isSigned())292    return false;293  return Left.getKey() == Right.getKey() &&294         Left.getAuthenticationMode() == Right.getAuthenticationMode() &&295         Left.isIsaPointer() == Right.isIsaPointer() &&296         Left.authenticatesNullValues() == Right.authenticatesNullValues() &&297         Left.getDiscriminator() == Right.getDiscriminator();298}299 300// Return the discriminator or return zero if the discriminator is null.301static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info,302                                           CGBuilderTy &Builder) {303  llvm::Value *Discriminator = Info.getDiscriminator();304  return Discriminator ? Discriminator : Builder.getSize(0);305}306 307llvm::Value *308CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value,309                                           const CGPointerAuthInfo &CurAuth,310                                           const CGPointerAuthInfo &NewAuth) {311  assert(CurAuth && NewAuth);312 313  if (CurAuth.getAuthenticationMode() !=314          PointerAuthenticationMode::SignAndAuth ||315      NewAuth.getAuthenticationMode() !=316          PointerAuthenticationMode::SignAndAuth) {317    llvm::Value *AuthedValue = EmitPointerAuthAuth(CurAuth, Value);318    return EmitPointerAuthSign(NewAuth, AuthedValue);319  }320  // Convert the pointer to intptr_t before signing it.321  auto *OrigType = Value->getType();322  Value = Builder.CreatePtrToInt(Value, IntPtrTy);323 324  auto *CurKey = Builder.getInt32(CurAuth.getKey());325  auto *NewKey = Builder.getInt32(NewAuth.getKey());326 327  llvm::Value *CurDiscriminator = getDiscriminatorOrZero(CurAuth, Builder);328  llvm::Value *NewDiscriminator = getDiscriminatorOrZero(NewAuth, Builder);329 330  // call i64 @llvm.ptrauth.resign(i64 %pointer,331  //                               i32 %curKey, i64 %curDiscriminator,332  //                               i32 %newKey, i64 %newDiscriminator)333  auto *Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_resign);334  Value = EmitRuntimeCall(335      Intrinsic, {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator});336 337  // Convert back to the original type.338  Value = Builder.CreateIntToPtr(Value, OrigType);339  return Value;340}341 342llvm::Value *CodeGenFunction::emitPointerAuthResign(343    llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo,344    const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) {345  // Fast path: if neither schema wants a signature, we're done.346  if (!CurAuthInfo && !NewAuthInfo)347    return Value;348 349  llvm::Value *Null = nullptr;350  // If the value is obviously null, we're done.351  if (auto *PointerValue = dyn_cast<llvm::PointerType>(Value->getType())) {352    Null = CGM.getNullPointer(PointerValue, Type);353  } else {354    assert(Value->getType()->isIntegerTy());355    Null = llvm::ConstantInt::get(IntPtrTy, 0);356  }357  if (Value == Null)358    return Value;359 360  // If both schemas sign the same way, we're done.361  if (equalAuthPolicies(CurAuthInfo, NewAuthInfo)) {362    const llvm::Value *CurD = CurAuthInfo.getDiscriminator();363    const llvm::Value *NewD = NewAuthInfo.getDiscriminator();364    if (CurD == NewD)365      return Value;366 367    if ((CurD == nullptr && isZeroConstant(NewD)) ||368        (NewD == nullptr && isZeroConstant(CurD)))369      return Value;370  }371 372  llvm::BasicBlock *InitBB = Builder.GetInsertBlock();373  llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr;374 375  // Null pointers have to be mapped to null, and the ptrauth_resign376  // intrinsic doesn't do that.377  if (!IsKnownNonNull && !llvm::isKnownNonZero(Value, CGM.getDataLayout())) {378    ContBB = createBasicBlock("resign.cont");379    ResignBB = createBasicBlock("resign.nonnull");380 381    auto *IsNonNull = Builder.CreateICmpNE(Value, Null);382    Builder.CreateCondBr(IsNonNull, ResignBB, ContBB);383    EmitBlock(ResignBB);384  }385 386  // Perform the auth/sign/resign operation.387  if (!NewAuthInfo)388    Value = EmitPointerAuthAuth(CurAuthInfo, Value);389  else if (!CurAuthInfo)390    Value = EmitPointerAuthSign(NewAuthInfo, Value);391  else392    Value = emitPointerAuthResignCall(Value, CurAuthInfo, NewAuthInfo);393 394  // Clean up with a phi if we branched before.395  if (ContBB) {396    EmitBlock(ContBB);397    auto *Phi = Builder.CreatePHI(Value->getType(), 2);398    Phi->addIncoming(Null, InitBB);399    Phi->addIncoming(Value, ResignBB);400    Value = Phi;401  }402 403  return Value;404}405 406void CodeGenFunction::EmitPointerAuthCopy(PointerAuthQualifier Qual, QualType T,407                                          Address DestAddress,408                                          Address SrcAddress) {409  assert(Qual);410  llvm::Value *Value = Builder.CreateLoad(SrcAddress);411 412  // If we're using address-discrimination, we have to re-sign the value.413  if (Qual.isAddressDiscriminated()) {414    CGPointerAuthInfo SrcPtrAuth = EmitPointerAuthInfo(Qual, SrcAddress);415    CGPointerAuthInfo DestPtrAuth = EmitPointerAuthInfo(Qual, DestAddress);416    Value = emitPointerAuthResign(Value, T, SrcPtrAuth, DestPtrAuth,417                                  /*IsKnownNonNull=*/false);418  }419 420  Builder.CreateStore(Value, DestAddress);421}422 423llvm::Constant *424CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,425                                        llvm::Constant *StorageAddress,426                                        llvm::ConstantInt *OtherDiscriminator) {427  llvm::Constant *AddressDiscriminator;428  if (StorageAddress) {429    assert(StorageAddress->getType() == DefaultPtrTy);430    AddressDiscriminator = StorageAddress;431  } else {432    AddressDiscriminator = llvm::Constant::getNullValue(DefaultPtrTy);433  }434 435  llvm::ConstantInt *IntegerDiscriminator;436  if (OtherDiscriminator) {437    assert(OtherDiscriminator->getType() == Int64Ty);438    IntegerDiscriminator = OtherDiscriminator;439  } else {440    IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0);441  }442 443  return llvm::ConstantPtrAuth::get(444      Pointer, llvm::ConstantInt::get(Int32Ty, Key), IntegerDiscriminator,445      AddressDiscriminator,446      /*DeactivationSymbol=*/llvm::Constant::getNullValue(DefaultPtrTy));447}448 449/// Does a given PointerAuthScheme require us to sign a value450bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) {451  auto AuthenticationMode = Schema.getAuthenticationMode();452  return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||453         AuthenticationMode == PointerAuthenticationMode::SignAndAuth;454}455 456/// Sign a constant pointer using the given scheme, producing a constant457/// with the same IR type.458llvm::Constant *CodeGenModule::getConstantSignedPointer(459    llvm::Constant *Pointer, const PointerAuthSchema &Schema,460    llvm::Constant *StorageAddress, GlobalDecl SchemaDecl,461    QualType SchemaType) {462  assert(shouldSignPointer(Schema));463  llvm::ConstantInt *OtherDiscriminator =464      getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType);465 466  return getConstantSignedPointer(Pointer, Schema.getKey(), StorageAddress,467                                  OtherDiscriminator);468}469 470llvm::Constant *471CodeGen::getConstantSignedPointer(CodeGenModule &CGM, llvm::Constant *Pointer,472                                  unsigned Key, llvm::Constant *StorageAddress,473                                  llvm::ConstantInt *OtherDiscriminator) {474  return CGM.getConstantSignedPointer(Pointer, Key, StorageAddress,475                                      OtherDiscriminator);476}477 478/// If applicable, sign a given constant function pointer with the ABI rules for479/// functionType.480llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,481                                                  QualType FunctionType) {482  assert(FunctionType->isFunctionType() ||483         FunctionType->isFunctionReferenceType() ||484         FunctionType->isFunctionPointerType());485 486  if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType))487    return getConstantSignedPointer(488        Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr,489        cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));490 491  return Pointer;492}493 494llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,495                                                  llvm::Type *Ty) {496  const auto *FD = cast<FunctionDecl>(GD.getDecl());497  QualType FuncType = FD->getType();498 499  // Annoyingly, K&R functions have prototypes in the clang AST, but500  // expressions referring to them are unprototyped.501  if (!FD->hasPrototype())502    if (const auto *Proto = FuncType->getAs<FunctionProtoType>())503      FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(),504                                                Proto->getExtInfo());505 506  return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);507}508 509CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {510  assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");511  const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;512  if (!Schema)513    return CGPointerAuthInfo();514 515  assert(!Schema.isAddressDiscriminated() &&516         "function pointers cannot use address-specific discrimination");517 518  llvm::ConstantInt *Discriminator =519      getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT);520  return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),521                           /* IsIsaPointer */ false,522                           /* AuthenticatesNullValues */ false, Discriminator);523}524 525llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,526                                                        QualType FT) {527  if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))528    return getConstantSignedPointer(529        Pointer, PointerAuth.getKey(), nullptr,530        cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));531 532  if (const auto *MFT = dyn_cast<MemberPointerType>(FT.getTypePtr())) {533    if (MFT->hasPointeeToToCFIUncheckedCalleeFunctionType())534      Pointer = llvm::NoCFIValue::get(cast<llvm::GlobalValue>(Pointer));535  }536 537  return Pointer;538}539 540llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,541                                                        llvm::Type *Ty) {542  QualType FT = FD->getType();543  FT = getContext().getMemberPointerType(FT, /*Qualifier=*/std::nullopt,544                                         cast<CXXMethodDecl>(FD)->getParent());545  return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT);546}547 548std::optional<PointerAuthQualifier>549CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {550  auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;551  if (!DefaultAuthentication)552    return std::nullopt;553  const CXXRecordDecl *PrimaryBase =554      Context.baseForVTableAuthentication(ThisClass);555 556  unsigned Key = DefaultAuthentication.getKey();557  bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated();558  auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination();559  unsigned TypeBasedDiscriminator =560      Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase);561  unsigned Discriminator;562  if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) {563    Discriminator = TypeBasedDiscriminator;564  } else if (DefaultDiscrimination ==565             PointerAuthSchema::Discrimination::Constant) {566    Discriminator = DefaultAuthentication.getConstantDiscrimination();567  } else {568    assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None);569    Discriminator = 0;570  }571  if (auto ExplicitAuthentication =572          PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) {573    auto ExplicitAddressDiscrimination =574        ExplicitAuthentication->getAddressDiscrimination();575    auto ExplicitDiscriminator =576        ExplicitAuthentication->getExtraDiscrimination();577 578    unsigned ExplicitKey = ExplicitAuthentication->getKey();579    if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey)580      return std::nullopt;581 582    if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) {583      if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent)584        Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA;585      else {586        assert(ExplicitKey ==587               VTablePointerAuthenticationAttr::ProcessDependent);588        Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB;589      }590    }591 592    if (ExplicitAddressDiscrimination !=593        VTablePointerAuthenticationAttr::DefaultAddressDiscrimination)594      AddressDiscriminated =595          ExplicitAddressDiscrimination ==596          VTablePointerAuthenticationAttr::AddressDiscrimination;597 598    if (ExplicitDiscriminator ==599        VTablePointerAuthenticationAttr::TypeDiscrimination)600      Discriminator = TypeBasedDiscriminator;601    else if (ExplicitDiscriminator ==602             VTablePointerAuthenticationAttr::CustomDiscrimination)603      Discriminator = ExplicitAuthentication->getCustomDiscriminationValue();604    else if (ExplicitDiscriminator ==605             VTablePointerAuthenticationAttr::NoExtraDiscrimination)606      Discriminator = 0;607  }608  return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator,609                                      PointerAuthenticationMode::SignAndAuth,610                                      /* IsIsaPointer */ false,611                                      /* AuthenticatesNullValues */ false);612}613 614std::optional<PointerAuthQualifier>615CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) {616  if (!Record->getDefinition() || !Record->isPolymorphic())617    return std::nullopt;618 619  auto Existing = VTablePtrAuthInfos.find(Record);620  std::optional<PointerAuthQualifier> Authentication;621  if (Existing != VTablePtrAuthInfos.end()) {622    Authentication = Existing->getSecond();623  } else {624    Authentication = computeVTPointerAuthentication(Record);625    VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));626  }627  return Authentication;628}629 630std::optional<CGPointerAuthInfo>631CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,632                                        const CXXRecordDecl *Record,633                                        llvm::Value *StorageAddress) {634  auto Authentication = getVTablePointerAuthentication(Record);635  if (!Authentication)636    return std::nullopt;637 638  llvm::Value *Discriminator = nullptr;639  if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator())640    Discriminator = llvm::ConstantInt::get(IntPtrTy, ExtraDiscriminator);641 642  if (Authentication->isAddressDiscriminated()) {643    assert(StorageAddress &&644           "address not provided for address-discriminated schema");645    if (Discriminator)646      Discriminator =647          CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);648    else649      Discriminator = CGF->Builder.CreatePtrToInt(StorageAddress, IntPtrTy);650  }651 652  return CGPointerAuthInfo(Authentication->getKey(),653                           PointerAuthenticationMode::SignAndAuth,654                           /* IsIsaPointer */ false,655                           /* AuthenticatesNullValues */ false, Discriminator);656}657 658llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,659                                                       QualType SourceType,660                                                       QualType DestType) {661  CGPointerAuthInfo CurAuthInfo, NewAuthInfo;662  if (SourceType->isSignableType(getContext()))663    CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);664 665  if (DestType->isSignableType(getContext()))666    NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);667 668  if (!CurAuthInfo && !NewAuthInfo)669    return ResultPtr;670 671  // If only one side of the cast is a function pointer, then we still need to672  // resign to handle casts to/from opaque pointers.673  if (!CurAuthInfo && DestType->isFunctionPointerType())674    CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType);675 676  if (!NewAuthInfo && SourceType->isFunctionPointerType())677    NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);678 679  return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo,680                               /*IsKnownNonNull=*/false);681}682 683Address CodeGenFunction::authPointerToPointerCast(Address Ptr,684                                                  QualType SourceType,685                                                  QualType DestType) {686  CGPointerAuthInfo CurAuthInfo, NewAuthInfo;687  if (SourceType->isSignableType(getContext()))688    CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);689 690  if (DestType->isSignableType(getContext()))691    NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);692 693  if (!CurAuthInfo && !NewAuthInfo)694    return Ptr;695 696  if (!CurAuthInfo && DestType->isFunctionPointerType()) {697    // When casting a non-signed pointer to a function pointer, just set the698    // auth info on Ptr to the assumed schema. The pointer will be resigned to699    // the effective type when used.700    Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType));701    return Ptr;702  }703 704  if (!NewAuthInfo && SourceType->isFunctionPointerType()) {705    NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);706    Ptr = Ptr.getResignedAddress(NewAuthInfo, *this);707    Ptr.setPointerAuthInfo(CGPointerAuthInfo());708    return Ptr;709  }710 711  return Ptr;712}713 714Address CodeGenFunction::getAsNaturalAddressOf(Address Addr,715                                               QualType PointeeTy) {716  CGPointerAuthInfo Info =717      PointeeTy.isNull() ? CGPointerAuthInfo()718                         : CGM.getPointerAuthInfoForPointeeType(PointeeTy);719  return Addr.getResignedAddress(Info, *this);720}721 722Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo,723                                    CodeGenFunction &CGF) const {724  assert(isValid() && "pointer isn't valid");725  CGPointerAuthInfo CurInfo = getPointerAuthInfo();726  llvm::Value *Val;727 728  // Nothing to do if neither the current or the new ptrauth info needs signing.729  if (!CurInfo.isSigned() && !NewInfo.isSigned())730    return Address(getBasePointer(), getElementType(), getAlignment(),731                   isKnownNonNull());732 733  assert(ElementType && "Effective type has to be set");734  assert(!Offset && "unexpected non-null offset");735 736  // If the current and the new ptrauth infos are the same and the offset is737  // null, just cast the base pointer to the effective type.738  if (CurInfo == NewInfo && !hasOffset())739    Val = getBasePointer();740  else741    Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo,742                                    NewInfo, isKnownNonNull());743 744  return Address(Val, getElementType(), getAlignment(), NewInfo,745                 /*Offset=*/nullptr, isKnownNonNull());746}747 748llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const {749  return CGF.getAsNaturalPointerTo(*this, QualType());750}751 752llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {753  assert(isSimple());754  return emitResignedPointer(getType(), CGF);755}756 757llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,758                                         CodeGenFunction &CGF) const {759  assert(isSimple());760  return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer();761}762 763llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {764  assert(isSimple());765  return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;766}767