diff --git a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp index 6d2dd0ecbccf3..e79457f925db6 100644 --- a/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp +++ b/llvm/lib/Target/AArch64/AArch64AsmPrinter.cpp @@ -169,6 +169,11 @@ class AArch64AsmPrinter : public AsmPrinter { // adrp-add followed by PAC sign) void LowerMOVaddrPAC(const MachineInstr &MI); + // Emit the sequence for LOADgotAUTH (load signed pointer from signed ELF GOT + // and authenticate it with, if FPAC bit is not set, check+trap sequence after + // authenticating) + void LowerLOADgotAUTH(const MachineInstr &MI); + /// tblgen'erated driver function for lowering simple MI->MC /// pseudo instructions. bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst); @@ -873,6 +878,22 @@ void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) { OutStreamer->addBlankLine(); } + + // With signed ELF GOT enabled, the linker looks at the symbol type to + // choose between keys IA (for STT_FUNC) and DA (for other types). Symbols + // for functions not defined in the module have STT_NOTYPE type by default. + // This makes linker to emit signing schema with DA key (instead of IA) for + // corresponding R_AARCH64_AUTH_GLOB_DAT dynamic reloc. To avoid that, force + // all function symbols used in the module to have STT_FUNC type. See + // https://github.com/ARM-software/abi-aa/blob/main/pauthabielf64/pauthabielf64.rst#default-signing-schema + const auto *PtrAuthELFGOTFlag = mdconst::extract_or_null( + M.getModuleFlag("ptrauth-elf-got")); + if (PtrAuthELFGOTFlag && PtrAuthELFGOTFlag->getZExtValue() == 1) + for (const GlobalValue &GV : M.global_values()) + if (!GV.use_empty() && isa(GV) && + !GV.getName().starts_with("llvm.")) + OutStreamer->emitSymbolAttribute(getSymbol(&GV), + MCSA_ELF_TypeFunction); } // Emit stack and fault map information. @@ -2068,6 +2089,10 @@ void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) { void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) { const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC; + const bool IsELFSignedGOT = MI.getParent() + ->getParent() + ->getInfo() + ->hasELFSignedGOT(); MachineOperand GAOp = MI.getOperand(0); const uint64_t KeyC = MI.getOperand(1).getImm(); assert(KeyC <= AArch64PACKey::LAST && @@ -2084,9 +2109,17 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) { // Emit: // target materialization: // - via GOT: - // adrp x16, :got:target - // ldr x16, [x16, :got_lo12:target] - // add offset to x16 if offset != 0 + // - unsigned GOT: + // adrp x16, :got:target + // ldr x16, [x16, :got_lo12:target] + // add offset to x16 if offset != 0 + // - ELF signed GOT: + // adrp x17, :got:target + // add x17, x17, :got_auth_lo12:target + // ldr x16, [x17] + // aut{i|d}a x16, x17 + // check+trap sequence (if no FPAC) + // add offset to x16 if offset != 0 // // - direct: // adrp x16, target @@ -2129,13 +2162,48 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) { MCInstLowering.lowerOperand(GAMOLo, GAMCLo); EmitToStreamer( - MCInstBuilder(AArch64::ADRP).addReg(AArch64::X16).addOperand(GAMCHi)); + MCInstBuilder(AArch64::ADRP) + .addReg(IsGOTLoad && IsELFSignedGOT ? AArch64::X17 : AArch64::X16) + .addOperand(GAMCHi)); if (IsGOTLoad) { - EmitToStreamer(MCInstBuilder(AArch64::LDRXui) - .addReg(AArch64::X16) - .addReg(AArch64::X16) - .addOperand(GAMCLo)); + if (IsELFSignedGOT) { + EmitToStreamer(MCInstBuilder(AArch64::ADDXri) + .addReg(AArch64::X17) + .addReg(AArch64::X17) + .addOperand(GAMCLo) + .addImm(0)); + + EmitToStreamer(MCInstBuilder(AArch64::LDRXui) + .addReg(AArch64::X16) + .addReg(AArch64::X17) + .addImm(0)); + + assert(GAOp.isGlobal()); + assert(GAOp.getGlobal()->getValueType() != nullptr); + unsigned AuthOpcode = GAOp.getGlobal()->getValueType()->isFunctionTy() + ? AArch64::AUTIA + : AArch64::AUTDA; + + EmitToStreamer(MCInstBuilder(AuthOpcode) + .addReg(AArch64::X16) + .addReg(AArch64::X16) + .addReg(AArch64::X17)); + + if (!STI->hasFPAC()) { + auto AuthKey = (AuthOpcode == AArch64::AUTIA ? AArch64PACKey::IA + : AArch64PACKey::DA); + + emitPtrauthCheckAuthenticatedValue(AArch64::X16, AArch64::X17, AuthKey, + /*ShouldTrap=*/true, + /*OnFailure=*/nullptr); + } + } else { + EmitToStreamer(MCInstBuilder(AArch64::LDRXui) + .addReg(AArch64::X16) + .addReg(AArch64::X16) + .addOperand(GAMCLo)); + } } else { EmitToStreamer(MCInstBuilder(AArch64::ADDXri) .addReg(AArch64::X16) @@ -2203,6 +2271,69 @@ void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) { EmitToStreamer(MIB); } +void AArch64AsmPrinter::LowerLOADgotAUTH(const MachineInstr &MI) { + Register DstReg = MI.getOperand(0).getReg(); + Register AuthResultReg = STI->hasFPAC() ? DstReg : AArch64::X16; + const MachineOperand &GAMO = MI.getOperand(1); + assert(GAMO.getOffset() == 0); + + MachineOperand GAHiOp(GAMO); + MachineOperand GALoOp(GAMO); + GAHiOp.addTargetFlag(AArch64II::MO_PAGE); + GALoOp.addTargetFlag(AArch64II::MO_PAGEOFF | AArch64II::MO_NC); + + MCOperand GAMCHi, GAMCLo; + MCInstLowering.lowerOperand(GAHiOp, GAMCHi); + MCInstLowering.lowerOperand(GALoOp, GAMCLo); + + EmitToStreamer( + MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(GAMCHi)); + + EmitToStreamer(MCInstBuilder(AArch64::ADDXri) + .addReg(AArch64::X17) + .addReg(AArch64::X17) + .addOperand(GAMCLo) + .addImm(0)); + + EmitToStreamer(MCInstBuilder(AArch64::LDRXui) + .addReg(AuthResultReg) + .addReg(AArch64::X17) + .addImm(0)); + + assert(GAMO.isGlobal()); + MCSymbol *UndefWeakSym; + if (GAMO.getGlobal()->hasExternalWeakLinkage()) { + UndefWeakSym = createTempSymbol("undef_weak"); + EmitToStreamer( + MCInstBuilder(AArch64::CBZX) + .addReg(AuthResultReg) + .addExpr(MCSymbolRefExpr::create(UndefWeakSym, OutContext))); + } + + assert(GAMO.getGlobal()->getValueType() != nullptr); + unsigned AuthOpcode = GAMO.getGlobal()->getValueType()->isFunctionTy() + ? AArch64::AUTIA + : AArch64::AUTDA; + EmitToStreamer(MCInstBuilder(AuthOpcode) + .addReg(AuthResultReg) + .addReg(AuthResultReg) + .addReg(AArch64::X17)); + + if (GAMO.getGlobal()->hasExternalWeakLinkage()) + OutStreamer->emitLabel(UndefWeakSym); + + if (!STI->hasFPAC()) { + auto AuthKey = + (AuthOpcode == AArch64::AUTIA ? AArch64PACKey::IA : AArch64PACKey::DA); + + emitPtrauthCheckAuthenticatedValue(AuthResultReg, AArch64::X17, AuthKey, + /*ShouldTrap=*/true, + /*OnFailure=*/nullptr); + + emitMovXReg(DstReg, AuthResultReg); + } +} + const MCExpr * AArch64AsmPrinter::lowerBlockAddressConstant(const BlockAddress &BA) { const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant(BA); @@ -2381,6 +2512,10 @@ void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { LowerMOVaddrPAC(*MI); return; + case AArch64::LOADgotAUTH: + LowerLOADgotAUTH(*MI); + return; + case AArch64::BRA: case AArch64::BLRA: emitPtrauthBranch(MI); diff --git a/llvm/lib/Target/AArch64/AArch64FastISel.cpp b/llvm/lib/Target/AArch64/AArch64FastISel.cpp index 6c874fcabcc30..d1e5d10829d55 100644 --- a/llvm/lib/Target/AArch64/AArch64FastISel.cpp +++ b/llvm/lib/Target/AArch64/AArch64FastISel.cpp @@ -454,6 +454,9 @@ unsigned AArch64FastISel::materializeGV(const GlobalValue *GV) { if (!Subtarget->useSmallAddressing() && !Subtarget->isTargetMachO()) return 0; + if (FuncInfo.MF->getInfo()->hasELFSignedGOT()) + return 0; + unsigned OpFlags = Subtarget->ClassifyGlobalReference(GV, TM); EVT DestEVT = TLI.getValueType(DL, GV->getType(), true); diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index e8c02c0987974..0814380b18848 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -9599,6 +9599,11 @@ SDValue AArch64TargetLowering::getGOT(NodeTy *N, SelectionDAG &DAG, SDValue GotAddr = getTargetNode(N, Ty, DAG, AArch64II::MO_GOT | Flags); // FIXME: Once remat is capable of dealing with instructions with register // operands, expand this into two nodes instead of using a wrapper node. + if (DAG.getMachineFunction() + .getInfo() + ->hasELFSignedGOT()) + return SDValue(DAG.getMachineNode(AArch64::LOADgotAUTH, DL, Ty, GotAddr), + 0); return DAG.getNode(AArch64ISD::LOADgot, DL, Ty, GotAddr); } diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 250d6144f7531..424848252f6aa 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -1942,8 +1942,15 @@ let Predicates = [HasPAuth] in { Sched<[WriteI, ReadI]> { let isReMaterializable = 1; let isCodeGenOnly = 1; - let Size = 40; // 12 fixed + 28 variable, for pointer offset, and discriminator - let Defs = [X16,X17]; + let Size = 68; // 12 fixed + 56 variable, for pointer offset, discriminator and + // ELF signed GOT signed pointer authentication (if no FPAC) + let Defs = [X16,X17,NZCV]; + } + + def LOADgotAUTH : Pseudo<(outs GPR64common:$dst), (ins i64imm:$addr), []>, + Sched<[WriteI, ReadI]> { + let Defs = [X16,X17,NZCV]; + let Size = 44; } // Load a signed global address from a special $auth_ptr$ stub slot. diff --git a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp b/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp index 48672241f905d..9f234b0f91705 100644 --- a/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp +++ b/llvm/lib/Target/AArch64/AArch64MCInstLower.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "AArch64MCInstLower.h" +#include "AArch64MachineFunctionInfo.h" #include "MCTargetDesc/AArch64MCExpr.h" #include "Utils/AArch64BaseInfo.h" #include "llvm/CodeGen/AsmPrinter.h" @@ -185,9 +186,12 @@ MCOperand AArch64MCInstLower::lowerSymbolOperandELF(const MachineOperand &MO, MCSymbol *Sym) const { uint32_t RefFlags = 0; - if (MO.getTargetFlags() & AArch64II::MO_GOT) - RefFlags |= AArch64MCExpr::VK_GOT; - else if (MO.getTargetFlags() & AArch64II::MO_TLS) { + if (MO.getTargetFlags() & AArch64II::MO_GOT) { + const MachineFunction *MF = MO.getParent()->getParent()->getParent(); + RefFlags |= (MF->getInfo()->hasELFSignedGOT() + ? AArch64MCExpr::VK_GOT_AUTH + : AArch64MCExpr::VK_GOT); + } else if (MO.getTargetFlags() & AArch64II::MO_TLS) { TLSModel::Model Model; if (MO.isGlobal()) { const GlobalValue *GV = MO.getGlobal(); diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp index e96c5a953ff2b..f08506979a1ae 100644 --- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.cpp @@ -72,6 +72,18 @@ static bool ShouldSignWithBKey(const Function &F, const AArch64Subtarget &STI) { return Key == "b_key"; } +static bool hasELFSignedGOTHelper(const Function &F, + const AArch64Subtarget *STI) { + if (!Triple(STI->getTargetTriple()).isOSBinFormatELF()) + return false; + const Module *M = F.getParent(); + const auto *Flag = mdconst::extract_or_null( + M->getModuleFlag("ptrauth-elf-got")); + if (Flag && Flag->getZExtValue() == 1) + return true; + return false; +} + AArch64FunctionInfo::AArch64FunctionInfo(const Function &F, const AArch64Subtarget *STI) { // If we already know that the function doesn't have a redzone, set @@ -80,6 +92,7 @@ AArch64FunctionInfo::AArch64FunctionInfo(const Function &F, HasRedZone = false; std::tie(SignReturnAddress, SignReturnAddressAll) = GetSignReturnAddress(F); SignWithBKey = ShouldSignWithBKey(F, *STI); + HasELFSignedGOT = hasELFSignedGOTHelper(F, STI); // TODO: skip functions that have no instrumented allocas for optimization IsMTETagged = F.hasFnAttribute(Attribute::SanitizeMemTag); diff --git a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h index 85b9733e95c52..a77fdaf19bcf5 100644 --- a/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h +++ b/llvm/lib/Target/AArch64/AArch64MachineFunctionInfo.h @@ -177,6 +177,11 @@ class AArch64FunctionInfo final : public MachineFunctionInfo { /// SignWithBKey modifies the default PAC-RET mode to signing with the B key. bool SignWithBKey = false; + /// HasELFSignedGOT is true if the target binary format is ELF and the IR + /// module containing the corresponding function has "ptrauth-elf-got" flag + /// set to 1. + bool HasELFSignedGOT = false; + /// SigningInstrOffset captures the offset of the PAC-RET signing instruction /// within the prologue, so it can be re-used for authentication in the /// epilogue when using PC as a second salt (FEAT_PAuth_LR) @@ -509,6 +514,8 @@ class AArch64FunctionInfo final : public MachineFunctionInfo { bool shouldSignWithBKey() const { return SignWithBKey; } + bool hasELFSignedGOT() const { return HasELFSignedGOT; } + MCSymbol *getSigningInstrLabel() const { return SignInstrLabel; } void setSigningInstrLabel(MCSymbol *Label) { SignInstrLabel = Label; } diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 5a487be5723ce..712f6de52941c 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -897,6 +897,7 @@ class AArch64Operand : public MCParsedAsmOperand { if (DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || ELFRefKind == AArch64MCExpr::VK_LO12 || ELFRefKind == AArch64MCExpr::VK_GOT_LO12 || + ELFRefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || @@ -1008,19 +1009,20 @@ class AArch64Operand : public MCParsedAsmOperand { int64_t Addend; if (AArch64AsmParser::classifySymbolRef(Expr, ELFRefKind, DarwinRefKind, Addend)) { - return DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF - || DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF - || (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF && Addend == 0) - || ELFRefKind == AArch64MCExpr::VK_LO12 - || ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 - || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 - || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC - || ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 - || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 - || ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC - || ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 - || ELFRefKind == AArch64MCExpr::VK_SECREL_HI12 - || ELFRefKind == AArch64MCExpr::VK_SECREL_LO12; + return DarwinRefKind == MCSymbolRefExpr::VK_PAGEOFF || + DarwinRefKind == MCSymbolRefExpr::VK_TLVPPAGEOFF || + (DarwinRefKind == MCSymbolRefExpr::VK_GOTPAGEOFF && Addend == 0) || + ELFRefKind == AArch64MCExpr::VK_LO12 || + ELFRefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TPREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12 || + ELFRefKind == AArch64MCExpr::VK_TPREL_LO12_NC || + ELFRefKind == AArch64MCExpr::VK_TLSDESC_LO12 || + ELFRefKind == AArch64MCExpr::VK_SECREL_HI12 || + ELFRefKind == AArch64MCExpr::VK_SECREL_LO12; } // If it's a constant, it should be a real immediate in range. @@ -3309,6 +3311,7 @@ ParseStatus AArch64AsmParser::tryParseAdrpLabel(OperandVector &Operands) { DarwinRefKind != MCSymbolRefExpr::VK_TLVPPAGE && ELFRefKind != AArch64MCExpr::VK_ABS_PAGE_NC && ELFRefKind != AArch64MCExpr::VK_GOT_PAGE && + ELFRefKind != AArch64MCExpr::VK_GOT_AUTH_PAGE && ELFRefKind != AArch64MCExpr::VK_GOT_PAGE_LO15 && ELFRefKind != AArch64MCExpr::VK_GOTTPREL_PAGE && ELFRefKind != AArch64MCExpr::VK_TLSDESC_PAGE) { @@ -4428,6 +4431,8 @@ bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) { .Case("got", AArch64MCExpr::VK_GOT_PAGE) .Case("gotpage_lo15", AArch64MCExpr::VK_GOT_PAGE_LO15) .Case("got_lo12", AArch64MCExpr::VK_GOT_LO12) + .Case("got_auth", AArch64MCExpr::VK_GOT_AUTH_PAGE) + .Case("got_auth_lo12", AArch64MCExpr::VK_GOT_AUTH_LO12) .Case("gottprel", AArch64MCExpr::VK_GOTTPREL_PAGE) .Case("gottprel_lo12", AArch64MCExpr::VK_GOTTPREL_LO12_NC) .Case("gottprel_g1", AArch64MCExpr::VK_GOTTPREL_G1) @@ -5801,6 +5806,7 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc, // Only allow these with ADDXri/ADDWri if ((ELFRefKind == AArch64MCExpr::VK_LO12 || + ELFRefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_HI12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12 || ELFRefKind == AArch64MCExpr::VK_DTPREL_LO12_NC || diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index afea08ab09250..9502b1d10f9a2 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -2967,7 +2967,9 @@ bool AArch64InstructionSelector::select(MachineInstr &I) { } if (OpFlags & AArch64II::MO_GOT) { - I.setDesc(TII.get(AArch64::LOADgot)); + I.setDesc(TII.get(MF.getInfo()->hasELFSignedGOT() + ? AArch64::LOADgotAUTH + : AArch64::LOADgot)); I.getOperand(1).setTargetFlags(OpFlags); } else if (TM.getCodeModel() == CodeModel::Large && !TM.isPositionIndependent()) { diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp index 83aac6fdae729..b5f5a58d96288 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64ELFObjectWriter.cpp @@ -165,6 +165,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, } if (SymLoc == AArch64MCExpr::VK_GOT && !IsNC) return R_CLS(ADR_GOT_PAGE); + if (SymLoc == AArch64MCExpr::VK_GOT_AUTH && !IsNC) { + if (IsILP32) { + Ctx.reportError(Fixup.getLoc(), + "ILP32 ADRP AUTH relocation not supported " + "(LP64 eqv: AUTH_ADR_GOT_PAGE)"); + return ELF::R_AARCH64_NONE; + } + return ELF::R_AARCH64_AUTH_ADR_GOT_PAGE; + } if (SymLoc == AArch64MCExpr::VK_GOTTPREL && !IsNC) return R_CLS(TLSIE_ADR_GOTTPREL_PAGE21); if (SymLoc == AArch64MCExpr::VK_TLSDESC && !IsNC) @@ -240,6 +249,15 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, return R_CLS(TLSLE_ADD_TPREL_LO12); if (RefKind == AArch64MCExpr::VK_TLSDESC_LO12) return R_CLS(TLSDESC_ADD_LO12); + if (RefKind == AArch64MCExpr::VK_GOT_AUTH_LO12 && IsNC) { + if (IsILP32) { + Ctx.reportError(Fixup.getLoc(), + "ILP32 ADD AUTH relocation not supported " + "(LP64 eqv: AUTH_GOT_ADD_LO12_NC)"); + return ELF::R_AARCH64_NONE; + } + return ELF::R_AARCH64_AUTH_GOT_ADD_LO12_NC; + } if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(ADD_ABS_LO12_NC); @@ -332,17 +350,23 @@ unsigned AArch64ELFObjectWriter::getRelocType(MCContext &Ctx, case AArch64::fixup_aarch64_ldst_imm12_scale8: if (SymLoc == AArch64MCExpr::VK_ABS && IsNC) return R_CLS(LDST64_ABS_LO12_NC); - if (SymLoc == AArch64MCExpr::VK_GOT && IsNC) { + if ((SymLoc == AArch64MCExpr::VK_GOT || + SymLoc == AArch64MCExpr::VK_GOT_AUTH) && + IsNC) { AArch64MCExpr::VariantKind AddressLoc = AArch64MCExpr::getAddressFrag(RefKind); + bool IsAuth = (SymLoc == AArch64MCExpr::VK_GOT_AUTH); if (!IsILP32) { if (AddressLoc == AArch64MCExpr::VK_LO15) return ELF::R_AARCH64_LD64_GOTPAGE_LO15; - return ELF::R_AARCH64_LD64_GOT_LO12_NC; + return (IsAuth ? ELF::R_AARCH64_AUTH_LD64_GOT_LO12_NC + : ELF::R_AARCH64_LD64_GOT_LO12_NC); } - Ctx.reportError(Fixup.getLoc(), "ILP32 64-bit load/store " - "relocation not supported (LP64 eqv: " - "LD64_GOT_LO12_NC)"); + Ctx.reportError(Fixup.getLoc(), + Twine("ILP32 64-bit load/store " + "relocation not supported (LP64 eqv: ") + + (IsAuth ? "AUTH_GOT_LO12_NC" : "LD64_GOT_LO12_NC") + + Twine(')')); return ELF::R_AARCH64_NONE; } if (SymLoc == AArch64MCExpr::VK_DTPREL && !IsNC) diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp index fb8eb9f47da17..3430b9002894f 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.cpp @@ -30,6 +30,7 @@ const AArch64MCExpr *AArch64MCExpr::create(const MCExpr *Expr, VariantKind Kind, } StringRef AArch64MCExpr::getVariantKindName() const { + // clang-format off switch (static_cast(getKind())) { case VK_CALL: return ""; case VK_LO12: return ":lo12:"; @@ -82,9 +83,13 @@ StringRef AArch64MCExpr::getVariantKindName() const { case VK_TLSDESC_PAGE: return ":tlsdesc:"; case VK_SECREL_LO12: return ":secrel_lo12:"; case VK_SECREL_HI12: return ":secrel_hi12:"; + case VK_GOT_AUTH: return ":got_auth:"; + case VK_GOT_AUTH_PAGE: return ":got_auth:"; + case VK_GOT_AUTH_LO12: return ":got_auth_lo12:"; default: llvm_unreachable("Invalid ELF symbol kind"); } + // clang-format on } void AArch64MCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const { diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h index cf3a90f95a2c1..699992782f67b 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCExpr.h @@ -24,6 +24,7 @@ namespace llvm { class AArch64MCExpr : public MCTargetExpr { public: enum VariantKind { + // clang-format off // Symbol locations specifying (roughly speaking) what calculation should be // performed to construct the final address for the relocated // symbol. E.g. direct, via the GOT, ... @@ -38,6 +39,7 @@ class AArch64MCExpr : public MCTargetExpr { VK_SECREL = 0x009, VK_AUTH = 0x00a, VK_AUTHADDR = 0x00b, + VK_GOT_AUTH = 0x00c, VK_SymLocBits = 0x00f, // Variants specifying which part of the final address calculation is @@ -88,6 +90,8 @@ class AArch64MCExpr : public MCTargetExpr { VK_GOT_LO12 = VK_GOT | VK_PAGEOFF | VK_NC, VK_GOT_PAGE = VK_GOT | VK_PAGE, VK_GOT_PAGE_LO15 = VK_GOT | VK_LO15 | VK_NC, + VK_GOT_AUTH_LO12 = VK_GOT_AUTH | VK_PAGEOFF | VK_NC, + VK_GOT_AUTH_PAGE = VK_GOT_AUTH | VK_PAGE, VK_DTPREL_G2 = VK_DTPREL | VK_G2, VK_DTPREL_G1 = VK_DTPREL | VK_G1, VK_DTPREL_G1_NC = VK_DTPREL | VK_G1 | VK_NC, @@ -114,6 +118,7 @@ class AArch64MCExpr : public MCTargetExpr { VK_SECREL_HI12 = VK_SECREL | VK_HI12, VK_INVALID = 0xfff + // clang-format on }; private: diff --git a/llvm/test/CodeGen/AArch64/ptrauth-basic-pic.ll b/llvm/test/CodeGen/AArch64/ptrauth-basic-pic.ll new file mode 100644 index 0000000000000..517a0a86ef14b --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-basic-pic.ll @@ -0,0 +1,127 @@ +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=0 -fast-isel=0 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth -mattr=+fpac %s -o - | FileCheck %s --check-prefixes=CHECK,NOTRAP +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=0 -fast-isel=0 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth %s -o - | FileCheck %s --check-prefixes=CHECK,TRAP + +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=0 -fast-isel=1 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth -mattr=+fpac %s -o - | FileCheck %s --check-prefixes=CHECK,NOTRAP +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=0 -fast-isel=1 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth %s -o - | FileCheck %s --check-prefixes=CHECK,TRAP + +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=1 -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth -mattr=+fpac %s -o - | FileCheck %s --check-prefixes=CHECK,NOTRAP +; RUN: llc -mtriple=aarch64-linux-gnu -global-isel=1 -global-isel-abort=1 -verify-machineinstrs \ +; RUN: -relocation-model=pic -mattr=+pauth %s -o - | FileCheck %s --check-prefixes=CHECK,TRAP + +;; Note: for FastISel, we fall back to SelectionDAG + +@var = global i32 0 + +define i32 @get_globalvar() { +; CHECK-LABEL: get_globalvar: +; CHECK: adrp x17, :got_auth:var +; CHECK-NEXT: add x17, x17, :got_auth_lo12:var +; NOTRAP-NEXT: ldr x8, [x17] +; NOTRAP-NEXT: autda x8, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_0 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_0: +; TRAP-NEXT: mov x8, x16 +; CHECK-NEXT: ldr w0, [x8] +; CHECK-NEXT: ret + + %val = load i32, ptr @var + ret i32 %val +} + +define ptr @get_globalvaraddr() { +; CHECK-LABEL: get_globalvaraddr: +; CHECK: adrp x17, :got_auth:var +; CHECK-NEXT: add x17, x17, :got_auth_lo12:var +; NOTRAP-NEXT: ldr x0, [x17] +; NOTRAP-NEXT: autda x0, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_1 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_1: +; TRAP-NEXT: mov x0, x16 +; CHECK-NEXT: ret + + %val = load i32, ptr @var + ret ptr @var +} + +declare i32 @foo() + +define ptr @resign_globalfunc() { +; CHECK-LABEL: resign_globalfunc: +; CHECK: adrp x17, :got_auth:foo +; CHECK-NEXT: add x17, x17, :got_auth_lo12:foo +; CHECK-NEXT: ldr x16, [x17] +; CHECK-NEXT: autia x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_2 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: .Lauth_success_2: +; CHECK-NEXT: mov x17, #42 +; CHECK-NEXT: pacia x16, x17 +; CHECK-NEXT: mov x0, x16 +; CHECK-NEXT: ret + + ret ptr ptrauth (ptr @foo, i32 0, i64 42) +} + +define ptr @resign_globalvar() { +; CHECK-LABEL: resign_globalvar: +; CHECK: adrp x17, :got_auth:var +; CHECK-NEXT: add x17, x17, :got_auth_lo12:var +; CHECK-NEXT: ldr x16, [x17] +; CHECK-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_3 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_3: +; CHECK-NEXT: mov x17, #43 +; CHECK-NEXT: pacdb x16, x17 +; CHECK-NEXT: mov x0, x16 +; CHECK-NEXT: ret + + ret ptr ptrauth (ptr @var, i32 3, i64 43) +} + +define ptr @resign_globalvar_offset() { +; CHECK-LABEL: resign_globalvar_offset: +; CHECK: adrp x17, :got_auth:var +; CHECK-NEXT: add x17, x17, :got_auth_lo12:var +; CHECK-NEXT: ldr x16, [x17] +; CHECK-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_4 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_4: +; CHECK-NEXT: add x16, x16, #16 +; CHECK-NEXT: mov x17, #44 +; CHECK-NEXT: pacda x16, x17 +; CHECK-NEXT: mov x0, x16 +; CHECK-NEXT: ret + + ret ptr ptrauth (ptr getelementptr (i8, ptr @var, i64 16), i32 2, i64 44) +} + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} diff --git a/llvm/test/CodeGen/AArch64/ptrauth-elf-globals-pic.ll b/llvm/test/CodeGen/AArch64/ptrauth-elf-globals-pic.ll new file mode 100644 index 0000000000000..23357cd802574 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-elf-globals-pic.ll @@ -0,0 +1,46 @@ +; RUN: llc -mtriple=arm64 -global-isel=0 -fast-isel=0 -relocation-model=pic -o - %s \ +; RUN: -mcpu=cyclone -mattr=+pauth -mattr=+fpac | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=arm64 -global-isel=0 -fast-isel=0 -relocation-model=pic -o - %s \ +; RUN: -mcpu=cyclone -mattr=+pauth | FileCheck --check-prefixes=CHECK,TRAP %s + +; RUN: llc -mtriple=arm64 -global-isel=0 -fast-isel=1 -relocation-model=pic -o - %s \ +; RUN: -mcpu=cyclone -mattr=+pauth -mattr=+fpac | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=arm64 -global-isel=0 -fast-isel=1 -relocation-model=pic -o - %s \ +; RUN: -mcpu=cyclone -mattr=+pauth | FileCheck --check-prefixes=CHECK,TRAP %s + +; RUN: llc -mtriple=arm64 -global-isel=1 -global-isel-abort=1 -relocation-model=pic -o - %s \ +; RUN: -mcpu=cyclone -mattr=+pauth -mattr=+fpac | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=arm64 -global-isel=1 -global-isel-abort=1 -relocation-model=pic -o - %s \ +; RUN: -mcpu=cyclone -mattr=+pauth | FileCheck --check-prefixes=CHECK,TRAP %s + +;; Note: for FastISel, we fall back to SelectionDAG + +@var8 = external global i8, align 1 + +define i8 @test_i8(i8 %new) { + %val = load i8, ptr @var8, align 1 + store i8 %new, ptr @var8 + ret i8 %val + +; CHECK-LABEL: test_i8: +; CHECK: adrp x17, :got_auth:var8 +; CHECK-NEXT: add x17, x17, :got_auth_lo12:var8 +; NOTRAP-NEXT: ldr x9, [x17] +; NOTRAP-NEXT: autda x9, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_0 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_0: +; TRAP-NEXT: mov x9, x16 +; CHECK-NEXT: ldrb w8, [x9] +; CHECK-NEXT: strb w0, [x9] +; CHECK-NEXT: mov x0, x8 +; CHECK-NEXT: ret +} + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} diff --git a/llvm/test/CodeGen/AArch64/ptrauth-elf-got-function-symbols.ll b/llvm/test/CodeGen/AArch64/ptrauth-elf-got-function-symbols.ll new file mode 100644 index 0000000000000..e75acceaa0d12 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-elf-got-function-symbols.ll @@ -0,0 +1,42 @@ +; RUN: llc -mtriple aarch64-linux-pauthtest -mattr +pauth -filetype=asm %s -o - | \ +; RUN: FileCheck %s --check-prefix=ASM +; RUN: llc -mtriple aarch64-linux-pauthtest -mattr +pauth -filetype=obj %s -o - | \ +; RUN: llvm-readelf -s - | FileCheck %s --check-prefix=OBJ + +; ASM: .type foo,@function +; ASM-LABEL: foo: +; ASM: adrp x17, :got_auth:bar +; ASM-NEXT: add x17, x17, :got_auth_lo12:bar +; ASM-NEXT: ldr x16, [x17] +; ASM-NEXT: autia x16, x17 +; ASM-NEXT: mov x17, x16 +; ASM-NEXT: xpaci x17 +; ASM-NEXT: cmp x16, x17 +; ASM-NEXT: b.eq .Lauth_success_0 +; ASM-NEXT: brk #0xc470 +; ASM-NEXT: .Lauth_success_0: +; ASM-NEXT: paciza x16 +; ASM-NEXT: adrp x8, .Lfptr +; ASM-NEXT: str x16, [x8, :lo12:.Lfptr] +; ASM-NEXT: ret +; ASM: .type .Lfptr,@object +; ASM-NEXT: .local .Lfptr +; ASM-NEXT: .comm .Lfptr,8,8 +; ASM: .type bar,@function + +; OBJ: Symbol table '.symtab' contains [[#]] entries: +; OBJ-NEXT: Num: Value Size Type Bind Vis Ndx Name +; OBJ: 0000000000000000 0 FUNC GLOBAL DEFAULT UND bar + +@fptr = private global ptr null + +define void @foo() { + store ptr ptrauth (ptr @bar, i32 0), ptr @fptr + ret void +} + +declare i32 @bar() + +!llvm.module.flags = !{!0} + +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} diff --git a/llvm/test/CodeGen/AArch64/ptrauth-extern-weak.ll b/llvm/test/CodeGen/AArch64/ptrauth-extern-weak.ll new file mode 100644 index 0000000000000..5d0a3f556c4c2 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-extern-weak.ll @@ -0,0 +1,74 @@ +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=0 -relocation-model=pic \ +; RUN: -mattr=+pauth -mattr=+fpac -o - %s | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=0 -relocation-model=pic \ +; RUN: -mattr=+pauth -o - %s | FileCheck --check-prefixes=CHECK,TRAP %s + +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=1 -relocation-model=pic \ +; RUN: -mattr=+pauth -mattr=+fpac -o - %s | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=0 -fast-isel=1 -relocation-model=pic \ +; RUN: -mattr=+pauth -o - %s | FileCheck --check-prefixes=CHECK,TRAP %s + +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=1 -global-isel-abort=1 -relocation-model=pic \ +; RUN: -mattr=+pauth -mattr=+fpac -o - %s | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -global-isel=1 -global-isel-abort=1 -relocation-model=pic \ +; RUN: -mattr=+pauth -o - %s | FileCheck --check-prefixes=CHECK,TRAP %s + +;; Note: for FastISel, we fall back to SelectionDAG + +declare extern_weak dso_local i32 @var() + +define ptr @foo() { +; The usual ADRP/ADD pair can't be used for a weak reference because it must +; evaluate to 0 if the symbol is undefined. We use a GOT entry for PIC +; otherwise a litpool entry. + ret ptr @var + +; CHECK-LABEL: foo: +; CHECK: adrp x17, :got_auth:var +; CHECK-NEXT: add x17, x17, :got_auth_lo12:var +; NOTRAP-NEXT: ldr x0, [x17] +; NOTRAP-NEXT: cbz x0, .Lundef_weak0 +; NOTRAP-NEXT: autia x0, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: cbz x16, .Lundef_weak0 +; TRAP-NEXT: autia x16, x17 +; CHECK-NEXT: .Lundef_weak0: +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_0 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: .Lauth_success_0: +; TRAP-NEXT: mov x0, x16 +; CHECK-NEXT: ret +} + +@arr_var = extern_weak global [10 x i32] + +define ptr @bar() { + %addr = getelementptr [10 x i32], ptr @arr_var, i32 0, i32 5 + ret ptr %addr + +; CHECK-LABEL: bar: +; CHECK: adrp x17, :got_auth:arr_var +; CHECK-NEXT: add x17, x17, :got_auth_lo12:arr_var +; NOTRAP-NEXT: ldr x8, [x17] +; NOTRAP-NEXT: cbz x8, .Lundef_weak1 +; NOTRAP-NEXT: autda x8, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: cbz x16, .Lundef_weak1 +; TRAP-NEXT: autda x16, x17 +; CHECK-NEXT: .Lundef_weak1: +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_1 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_1: +; TRAP-NEXT: mov x8, x16 +; CHECK-NEXT: add x0, x8, #20 +; CHECK-NEXT: ret +} + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} diff --git a/llvm/test/CodeGen/AArch64/ptrauth-got-abuse.ll b/llvm/test/CodeGen/AArch64/ptrauth-got-abuse.ll new file mode 100644 index 0000000000000..3c4747c321856 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-got-abuse.ll @@ -0,0 +1,88 @@ +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=0 -fast-isel=0 \ +; RUN: -relocation-model=pic -mattr=+pauth -mattr=+fpac -o - %s | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=0 -fast-isel=0 \ +; RUN: -relocation-model=pic -mattr=+pauth -o - %s | FileCheck --check-prefixes=CHECK,TRAP %s + +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=0 -fast-isel=1 \ +; RUN: -relocation-model=pic -mattr=+pauth -mattr=+fpac -o - %s | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=0 -fast-isel=1 \ +; RUN: -relocation-model=pic -mattr=+pauth -o - %s | FileCheck --check-prefixes=CHECK,TRAP %s + +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=1 -global-isel-abort=1 \ +; RUN: -relocation-model=pic -mattr=+pauth -mattr=+fpac -o - %s | FileCheck --check-prefixes=CHECK,NOTRAP %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=1 -global-isel-abort=1 \ +; RUN: -relocation-model=pic -mattr=+pauth -o - %s | FileCheck --check-prefixes=CHECK,TRAP %s + +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=0 -fast-isel=0 \ +; RUN: -relocation-model=pic -filetype=obj -mattr=+pauth -o /dev/null %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=0 -fast-isel=1 \ +; RUN: -relocation-model=pic -filetype=obj -mattr=+pauth -o /dev/null %s +; RUN: llc -mtriple=aarch64-none-linux-gnu -asm-verbose=false -global-isel=1 -global-isel-abort=1 \ +; RUN: -relocation-model=pic -filetype=obj -mattr=+pauth -o /dev/null %s + +;; Note: for FastISel, we fall back to SelectionDAG + +declare void @consume(i32) +declare void @func() + +define void @aliasee_func() { + ret void +} +@alias_func = alias void (), ptr @aliasee_func + +@aliasee_global = global i32 42 +@alias_global = alias i32, ptr @aliasee_global + +define void @foo() nounwind { +; CHECK-LABEL: foo: +entry: + call void @consume(i32 ptrtoint (ptr @func to i32)) +; CHECK: adrp x17, :got_auth:func +; CHECK-NEXT: add x17, x17, :got_auth_lo12:func +; NOTRAP-NEXT: ldr x[[TMP0:[0-9]+]], [x17] +; NOTRAP-NEXT: autia x[[TMP0]], x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autia x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_0 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: .Lauth_success_0: +; TRAP-NEXT: mov x[[TMP0:[0-9]+]], x16 + + call void @consume(i32 ptrtoint (ptr @alias_func to i32)) +; CHECK: adrp x17, :got_auth:alias_func +; CHECK-NEXT: add x17, x17, :got_auth_lo12:alias_func +; NOTRAP-NEXT: ldr x[[TMP1:[0-9]+]], [x17] +; NOTRAP-NEXT: autia x[[TMP1]], x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autia x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_1 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: .Lauth_success_1: +; TRAP-NEXT: mov x[[TMP1:[0-9]+]], x16 + + call void @consume(i32 ptrtoint (ptr @alias_global to i32)) +; CHECK: adrp x17, :got_auth:alias_global +; CHECK-NEXT: add x17, x17, :got_auth_lo12:alias_global +; NOTRAP-NEXT: ldr x[[TMP2:[0-9]+]], [x17] +; NOTRAP-NEXT: autda x[[TMP2]], x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_2 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_2: +; TRAP-NEXT: mov x[[TMP2:[0-9]+]], x16 + + ret void +} + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} diff --git a/llvm/test/CodeGen/AArch64/ptrauth-tagged-globals-pic.ll b/llvm/test/CodeGen/AArch64/ptrauth-tagged-globals-pic.ll new file mode 100644 index 0000000000000..ee34b439daec7 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/ptrauth-tagged-globals-pic.ll @@ -0,0 +1,117 @@ +; RUN: llc -global-isel=0 -fast-isel=0 -O0 --relocation-model=pic < %s \ +; RUN: -mattr=+pauth -mattr=+fpac | FileCheck %s --check-prefixes=CHECK,DAGISEL,NOTRAP,DAGISEL-NOTRAP +; RUN: llc -global-isel=0 -fast-isel=0 -O0 --relocation-model=pic < %s \ +; RUN: -mattr=+pauth | FileCheck %s --check-prefixes=CHECK,DAGISEL,TRAP,DAGISEL-TRAP + +; RUN: llc -global-isel=0 -fast-isel=1 -O0 --relocation-model=pic < %s \ +; RUN: -mattr=+pauth -mattr=+fpac | FileCheck %s --check-prefixes=CHECK,DAGISEL,NOTRAP,DAGISEL-NOTRAP +; RUN: llc -global-isel=0 -fast-isel=1 -O0 --relocation-model=pic < %s \ +; RUN: -mattr=+pauth | FileCheck %s --check-prefixes=CHECK,DAGISEL,TRAP,DAGISEL-TRAP + +; RUN: llc -global-isel=1 -global-isel-abort=1 -O0 --relocation-model=pic < %s \ +; RUN: -mattr=+pauth -mattr=+fpac | FileCheck %s --check-prefixes=CHECK,GISEL,NOTRAP,GISEL-NOTRAP +; RUN: llc -global-isel=1 -global-isel-abort=1 -O0 --relocation-model=pic < %s \ +; RUN: -mattr=+pauth | FileCheck %s --check-prefixes=CHECK,GISEL,TRAP,GISEL-TRAP + +;; Note: for FastISel, we fall back to SelectionDAG + +target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-unknown-linux-android" + +@global = external global i32 +declare void @func() + +define ptr @global_addr() #0 { +; CHECK-LABEL: global_addr: +; CHECK: adrp x17, :got_auth:global +; CHECK-NEXT: add x17, x17, :got_auth_lo12:global +; NOTRAP-NEXT: ldr x0, [x17] +; NOTRAP-NEXT: autda x0, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_0 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_0: +; TRAP-NEXT: mov x0, x16 +; CHECK-NEXT: ret + + ret ptr @global +} + +define i32 @global_load() #0 { +; CHECK-LABEL: global_load: +; CHECK: adrp x17, :got_auth:global +; CHECK-NEXT: add x17, x17, :got_auth_lo12:global +; NOTRAP-NEXT: ldr x8, [x17] +; NOTRAP-NEXT: autda x8, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_1 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_1: +; TRAP-NEXT: mov x8, x16 +; CHECK-NEXT: ldr w0, [x8] +; CHECK-NEXT: ret + + %load = load i32, ptr @global + ret i32 %load +} + +define void @global_store() #0 { +; CHECK-LABEL: global_store: +; CHECK: adrp x17, :got_auth:global +; CHECK-NEXT: add x17, x17, :got_auth_lo12:global +; GISEL-NOTRAP-NEXT: ldr x8, [x17] +; GISEL-NOTRAP-NEXT: autda x8, x17 +; GISEL-TRAP-NEXT: ldr x16, [x17] +; GISEL-TRAP-NEXT: autda x16, x17 +; DAGISEL-NOTRAP-NEXT: ldr x9, [x17] +; DAGISEL-NOTRAP-NEXT: autda x9, x17 +; DAGISEL-TRAP-NEXT: ldr x16, [x17] +; DAGISEL-TRAP-NEXT: autda x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpacd x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_2 +; TRAP-NEXT: brk #0xc472 +; TRAP-NEXT: .Lauth_success_2: +; GISEL-TRAP-NEXT: mov x8, x16 +; DAGISEL-TRAP-NEXT: mov x9, x16 +; GISEL-NEXT: str wzr, [x8] +; DAGISEL-NEXT: mov w8, wzr +; DAGISEL-NEXT: str w8, [x9] +; CHECK-NEXT: ret + store i32 0, ptr @global + ret void +} + +define ptr @func_addr() #0 { +; CHECK-LABEL: func_addr: +; CHECK: adrp x17, :got_auth:func +; CHECK-NEXT: add x17, x17, :got_auth_lo12:func +; NOTRAP-NEXT: ldr x0, [x17] +; NOTRAP-NEXT: autia x0, x17 +; TRAP-NEXT: ldr x16, [x17] +; TRAP-NEXT: autia x16, x17 +; TRAP-NEXT: mov x17, x16 +; TRAP-NEXT: xpaci x17 +; TRAP-NEXT: cmp x16, x17 +; TRAP-NEXT: b.eq .Lauth_success_3 +; TRAP-NEXT: brk #0xc470 +; TRAP-NEXT: .Lauth_success_3: +; TRAP-NEXT: mov x0, x16 +; CHECK-NEXT: ret + + ret ptr @func +} + +attributes #0 = { "target-features"="+tagged-globals" } + +!llvm.module.flags = !{!0} +!0 = !{i32 8, !"ptrauth-elf-got", i32 1} diff --git a/llvm/test/MC/AArch64/adrp-auth-relocation.s b/llvm/test/MC/AArch64/adrp-auth-relocation.s new file mode 100644 index 0000000000000..57021c71632ff --- /dev/null +++ b/llvm/test/MC/AArch64/adrp-auth-relocation.s @@ -0,0 +1,12 @@ +// RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj -o - %s | llvm-readobj -r - | FileCheck %s +// RUN: not llvm-mc -triple=aarch64-linux-gnu_ilp32 -filetype=obj \ +// RUN: -o /dev/null %s 2>&1 | FileCheck -check-prefix=CHECK-ILP32 %s + +.text +adrp x0, :got_auth:sym + +.global sym +sym: + +// CHECK: R_AARCH64_AUTH_ADR_GOT_PAGE sym +// CHECK-ILP32: error: ILP32 ADRP AUTH relocation not supported (LP64 eqv: AUTH_ADR_GOT_PAGE) diff --git a/llvm/test/MC/AArch64/arm64-elf-relocs.s b/llvm/test/MC/AArch64/arm64-elf-relocs.s index 8813c4bd7d1aa..f679bb4c82827 100644 --- a/llvm/test/MC/AArch64/arm64-elf-relocs.s +++ b/llvm/test/MC/AArch64/arm64-elf-relocs.s @@ -81,13 +81,17 @@ // CHECK: adrp x15, :got:sym // CHECK-OBJ-LP64: 58 R_AARCH64_ADR_GOT_PAGE sym + adrp x15, :got_auth:sym +// CHECK: adrp x15, :got_auth:sym +// CHECK-OBJ-LP64: 5c R_AARCH64_AUTH_ADR_GOT_PAGE sym + adrp x29, :gottprel:sym // CHECK: adrp x29, :gottprel:sym -// CHECK-OBJ-LP64: 5c R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 sym +// CHECK-OBJ-LP64: 60 R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 sym adrp x2, :tlsdesc:sym // CHECK: adrp x2, :tlsdesc:sym -// CHECK-OBJ-LP64: 60 R_AARCH64_TLSDESC_ADR_PAGE21 sym +// CHECK-OBJ-LP64: 64 R_AARCH64_TLSDESC_ADR_PAGE21 sym // LLVM is not competent enough to do this relocation because the // page boundary could occur anywhere after linking. A relocation @@ -96,7 +100,7 @@ .global trickQuestion trickQuestion: // CHECK: adrp x3, trickQuestion -// CHECK-OBJ-LP64: 64 R_AARCH64_ADR_PREL_PG_HI21 trickQuestion +// CHECK-OBJ-LP64: 68 R_AARCH64_ADR_PREL_PG_HI21 trickQuestion ldrb w2, [x3, :lo12:sym] ldrsb w5, [x7, #:lo12:sym] @@ -245,6 +249,16 @@ trickQuestion: // CHECK-OBJ-LP64: R_AARCH64_LD64_GOT_LO12_NC sym // CHECK-OBJ-LP64: R_AARCH64_LD64_GOT_LO12_NC sym+0x7 + ldr x24, [x23, #:got_auth_lo12:sym] + ldr d22, [x21, :got_auth_lo12:sym] + ldr x24, [x23, :got_auth_lo12:sym+7] +// CHECK: ldr x24, [x23, :got_auth_lo12:sym] +// CHECK: ldr d22, [x21, :got_auth_lo12:sym] +// CHECK: ldr x24, [x23, :got_auth_lo12:sym+7] +// CHECK-OBJ-LP64: R_AARCH64_AUTH_LD64_GOT_LO12_NC sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_LD64_GOT_LO12_NC sym +// CHECK-OBJ-LP64: R_AARCH64_AUTH_LD64_GOT_LO12_NC sym+0x7 + ldr x24, [x23, #:gotpage_lo15:sym] ldr d22, [x21, :gotpage_lo15:sym] ldr d22, [x23, :gotpage_lo15:sym+7] diff --git a/llvm/test/MC/AArch64/ilp32-diagnostics.s b/llvm/test/MC/AArch64/ilp32-diagnostics.s index 8a3bc1398e042..5d9c6e5626b2b 100644 --- a/llvm/test/MC/AArch64/ilp32-diagnostics.s +++ b/llvm/test/MC/AArch64/ilp32-diagnostics.s @@ -69,6 +69,12 @@ ldr x10, [x0, #:gottprel_lo12:var] ldr x24, [x23, #:got_lo12:sym] // ERROR: [[#@LINE-1]]:1: error: ILP32 64-bit load/store relocation not supported (LP64 eqv: LD64_GOT_LO12_NC) +ldr x24, [x23, #:got_auth_lo12:sym] +// ERROR: [[#@LINE-1]]:1: error: ILP32 64-bit load/store relocation not supported (LP64 eqv: AUTH_GOT_LO12_NC) + +add x24, x23, #:got_auth_lo12:sym +// ERROR: [[#@LINE-1]]:1: error: ILP32 ADD AUTH relocation not supported (LP64 eqv: AUTH_GOT_ADD_LO12_NC) + ldr x24, [x23, :gottprel_lo12:sym] // ERROR: [[#@LINE-1]]:1: error: ILP32 64-bit load/store relocation not supported (LP64 eqv: TLSIE_LD64_GOTTPREL_LO12_NC)