12f09f445SMaksim Panchenko //===- bolt/Target/AArch64/AArch64MCPlusBuilder.cpp -----------------------===// 2a34c753fSRafael Auler // 3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information. 5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a34c753fSRafael Auler // 7a34c753fSRafael Auler //===----------------------------------------------------------------------===// 8a34c753fSRafael Auler // 92f09f445SMaksim Panchenko // This file provides AArch64-specific MCPlus builder. 10a34c753fSRafael Auler // 11a34c753fSRafael Auler //===----------------------------------------------------------------------===// 12a34c753fSRafael Auler 13a34c753fSRafael Auler #include "MCTargetDesc/AArch64AddressingModes.h" 1462020a3aSzhoujiapeng #include "MCTargetDesc/AArch64FixupKinds.h" 15a34c753fSRafael Auler #include "MCTargetDesc/AArch64MCExpr.h" 16a34c753fSRafael Auler #include "MCTargetDesc/AArch64MCTargetDesc.h" 17a34c753fSRafael Auler #include "Utils/AArch64BaseInfo.h" 18be89e794SMaksim Panchenko #include "bolt/Core/BinaryBasicBlock.h" 19be89e794SMaksim Panchenko #include "bolt/Core/BinaryFunction.h" 20a34c753fSRafael Auler #include "bolt/Core/MCPlusBuilder.h" 21a34c753fSRafael Auler #include "llvm/BinaryFormat/ELF.h" 226e4c2305SElvina Yakubova #include "llvm/MC/MCContext.h" 2362020a3aSzhoujiapeng #include "llvm/MC/MCFixupKindInfo.h" 246e4c2305SElvina Yakubova #include "llvm/MC/MCInstBuilder.h" 25a34c753fSRafael Auler #include "llvm/MC/MCInstrInfo.h" 26a34c753fSRafael Auler #include "llvm/MC/MCRegisterInfo.h" 27be89e794SMaksim Panchenko #include "llvm/Support/DataExtractor.h" 28a34c753fSRafael Auler #include "llvm/Support/Debug.h" 29a34c753fSRafael Auler #include "llvm/Support/ErrorHandling.h" 30a34c753fSRafael Auler 31bc9032c7SMaksim Panchenko #define DEBUG_TYPE "mcplus" 32a34c753fSRafael Auler 33a34c753fSRafael Auler using namespace llvm; 34a34c753fSRafael Auler using namespace bolt; 35a34c753fSRafael Auler 36a34c753fSRafael Auler namespace { 37a34c753fSRafael Auler 386e4c2305SElvina Yakubova static void getSystemFlag(MCInst &Inst, MCPhysReg RegName) { 396e4c2305SElvina Yakubova Inst.setOpcode(AArch64::MRS); 406e4c2305SElvina Yakubova Inst.clear(); 416e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(RegName)); 426e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(AArch64SysReg::NZCV)); 436e4c2305SElvina Yakubova } 446e4c2305SElvina Yakubova 456e4c2305SElvina Yakubova static void setSystemFlag(MCInst &Inst, MCPhysReg RegName) { 466e4c2305SElvina Yakubova Inst.setOpcode(AArch64::MSR); 476e4c2305SElvina Yakubova Inst.clear(); 486e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(AArch64SysReg::NZCV)); 496e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(RegName)); 506e4c2305SElvina Yakubova } 516e4c2305SElvina Yakubova 526e4c2305SElvina Yakubova static void createPushRegisters(MCInst &Inst, MCPhysReg Reg1, MCPhysReg Reg2) { 536e4c2305SElvina Yakubova Inst.clear(); 546e4c2305SElvina Yakubova unsigned NewOpcode = AArch64::STPXpre; 556e4c2305SElvina Yakubova Inst.setOpcode(NewOpcode); 566e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 576e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(Reg1)); 586e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(Reg2)); 596e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 606e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(-2)); 616e4c2305SElvina Yakubova } 626e4c2305SElvina Yakubova 636e4c2305SElvina Yakubova static void createPopRegisters(MCInst &Inst, MCPhysReg Reg1, MCPhysReg Reg2) { 646e4c2305SElvina Yakubova Inst.clear(); 656e4c2305SElvina Yakubova unsigned NewOpcode = AArch64::LDPXpost; 666e4c2305SElvina Yakubova Inst.setOpcode(NewOpcode); 676e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 686e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(Reg1)); 696e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(Reg2)); 706e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 716e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(2)); 726e4c2305SElvina Yakubova } 736e4c2305SElvina Yakubova 746e4c2305SElvina Yakubova static void loadReg(MCInst &Inst, MCPhysReg To, MCPhysReg From) { 756e4c2305SElvina Yakubova Inst.setOpcode(AArch64::LDRXui); 766e4c2305SElvina Yakubova Inst.clear(); 776e4c2305SElvina Yakubova if (From == AArch64::SP) { 786e4c2305SElvina Yakubova Inst.setOpcode(AArch64::LDRXpost); 796e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(From)); 806e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(To)); 816e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(From)); 826e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(16)); 836e4c2305SElvina Yakubova } else { 846e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(To)); 856e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(From)); 866e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(0)); 876e4c2305SElvina Yakubova } 886e4c2305SElvina Yakubova } 896e4c2305SElvina Yakubova 906e4c2305SElvina Yakubova static void storeReg(MCInst &Inst, MCPhysReg From, MCPhysReg To) { 916e4c2305SElvina Yakubova Inst.setOpcode(AArch64::STRXui); 926e4c2305SElvina Yakubova Inst.clear(); 936e4c2305SElvina Yakubova if (To == AArch64::SP) { 946e4c2305SElvina Yakubova Inst.setOpcode(AArch64::STRXpre); 956e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(To)); 966e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(From)); 976e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(To)); 986e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(-16)); 996e4c2305SElvina Yakubova } else { 1006e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(From)); 1016e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(To)); 1026e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(0)); 1036e4c2305SElvina Yakubova } 1046e4c2305SElvina Yakubova } 1056e4c2305SElvina Yakubova 1066e4c2305SElvina Yakubova static void atomicAdd(MCInst &Inst, MCPhysReg RegTo, MCPhysReg RegCnt) { 1076e4c2305SElvina Yakubova // NOTE: Supports only ARM with LSE extension 1086e4c2305SElvina Yakubova Inst.setOpcode(AArch64::LDADDX); 1096e4c2305SElvina Yakubova Inst.clear(); 1106e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::XZR)); 1116e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(RegCnt)); 1126e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(RegTo)); 1136e4c2305SElvina Yakubova } 1146e4c2305SElvina Yakubova 1156e4c2305SElvina Yakubova static void createMovz(MCInst &Inst, MCPhysReg Reg, uint64_t Imm) { 1166e4c2305SElvina Yakubova assert(Imm <= UINT16_MAX && "Invalid Imm size"); 1176e4c2305SElvina Yakubova Inst.clear(); 1186e4c2305SElvina Yakubova Inst.setOpcode(AArch64::MOVZXi); 1196e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(Reg)); 1206e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(Imm & 0xFFFF)); 1216e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(0)); 1226e4c2305SElvina Yakubova } 1236e4c2305SElvina Yakubova 1246e4c2305SElvina Yakubova static InstructionListType createIncMemory(MCPhysReg RegTo, MCPhysReg RegTmp) { 1256e4c2305SElvina Yakubova InstructionListType Insts; 1266e4c2305SElvina Yakubova Insts.emplace_back(); 1276e4c2305SElvina Yakubova createMovz(Insts.back(), RegTmp, 1); 1286e4c2305SElvina Yakubova Insts.emplace_back(); 1296e4c2305SElvina Yakubova atomicAdd(Insts.back(), RegTo, RegTmp); 1306e4c2305SElvina Yakubova return Insts; 1316e4c2305SElvina Yakubova } 132a34c753fSRafael Auler class AArch64MCPlusBuilder : public MCPlusBuilder { 133a34c753fSRafael Auler public: 1348fb83bf5SJob Noorman using MCPlusBuilder::MCPlusBuilder; 135a34c753fSRafael Auler 136ee428225SNicholas MCPhysReg getStackPointer() const override { return AArch64::SP; } 137ad599c25SAlexey Moksyakov MCPhysReg getFramePointer() const override { return AArch64::FP; } 138ee428225SNicholas 139ad599c25SAlexey Moksyakov bool isPush(const MCInst &Inst) const override { 140ad599c25SAlexey Moksyakov return isStoreToStack(Inst); 141ad599c25SAlexey Moksyakov }; 142ee428225SNicholas 143ad599c25SAlexey Moksyakov bool isPop(const MCInst &Inst) const override { 144ad599c25SAlexey Moksyakov return isLoadFromStack(Inst); 145ad599c25SAlexey Moksyakov }; 146ee428225SNicholas 147ee428225SNicholas void createCall(MCInst &Inst, const MCSymbol *Target, 148ee428225SNicholas MCContext *Ctx) override { 149ee428225SNicholas createDirectCall(Inst, Target, Ctx, false); 150ee428225SNicholas } 151ee428225SNicholas 152ee428225SNicholas bool convertTailCallToCall(MCInst &Inst) override { 153ee428225SNicholas int NewOpcode; 154ee428225SNicholas switch (Inst.getOpcode()) { 155ee428225SNicholas default: 156ee428225SNicholas return false; 157ee428225SNicholas case AArch64::B: 158ee428225SNicholas NewOpcode = AArch64::BL; 159ee428225SNicholas break; 160ee428225SNicholas case AArch64::BR: 161ee428225SNicholas NewOpcode = AArch64::BLR; 162ee428225SNicholas break; 163ee428225SNicholas } 164ee428225SNicholas 165ee428225SNicholas Inst.setOpcode(NewOpcode); 166ee428225SNicholas removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall); 167ee428225SNicholas clearOffset(Inst); 168ee428225SNicholas return true; 169ee428225SNicholas } 170ee428225SNicholas 171a34c753fSRafael Auler bool equals(const MCTargetExpr &A, const MCTargetExpr &B, 172a34c753fSRafael Auler CompFuncTy Comp) const override { 173a34c753fSRafael Auler const auto &AArch64ExprA = cast<AArch64MCExpr>(A); 174a34c753fSRafael Auler const auto &AArch64ExprB = cast<AArch64MCExpr>(B); 175a34c753fSRafael Auler if (AArch64ExprA.getKind() != AArch64ExprB.getKind()) 176a34c753fSRafael Auler return false; 177a34c753fSRafael Auler 178a34c753fSRafael Auler return MCPlusBuilder::equals(*AArch64ExprA.getSubExpr(), 179a34c753fSRafael Auler *AArch64ExprB.getSubExpr(), Comp); 180a34c753fSRafael Auler } 181a34c753fSRafael Auler 182dc1cf838SAmir Ayupov bool shortenInstruction(MCInst &, const MCSubtargetInfo &) const override { 183dc1cf838SAmir Ayupov return false; 184dc1cf838SAmir Ayupov } 185a34c753fSRafael Auler 186a34c753fSRafael Auler bool isADRP(const MCInst &Inst) const override { 187a34c753fSRafael Auler return Inst.getOpcode() == AArch64::ADRP; 188a34c753fSRafael Auler } 189a34c753fSRafael Auler 190a34c753fSRafael Auler bool isADR(const MCInst &Inst) const override { 191a34c753fSRafael Auler return Inst.getOpcode() == AArch64::ADR; 192a34c753fSRafael Auler } 193a34c753fSRafael Auler 19417ed8f29SVladislav Khmelevsky bool isAddXri(const MCInst &Inst) const { 19517ed8f29SVladislav Khmelevsky return Inst.getOpcode() == AArch64::ADDXri; 19617ed8f29SVladislav Khmelevsky } 19717ed8f29SVladislav Khmelevsky 198a34c753fSRafael Auler void getADRReg(const MCInst &Inst, MCPhysReg &RegName) const override { 199a34c753fSRafael Auler assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction"); 200a34c753fSRafael Auler assert(MCPlus::getNumPrimeOperands(Inst) != 0 && 201a34c753fSRafael Auler "No operands for ADR instruction"); 202a34c753fSRafael Auler assert(Inst.getOperand(0).isReg() && 203a34c753fSRafael Auler "Unexpected operand in ADR instruction"); 204a34c753fSRafael Auler RegName = Inst.getOperand(0).getReg(); 205a34c753fSRafael Auler } 206a34c753fSRafael Auler 207a34c753fSRafael Auler bool isTB(const MCInst &Inst) const { 208a34c753fSRafael Auler return (Inst.getOpcode() == AArch64::TBNZW || 209a34c753fSRafael Auler Inst.getOpcode() == AArch64::TBNZX || 210a34c753fSRafael Auler Inst.getOpcode() == AArch64::TBZW || 211a34c753fSRafael Auler Inst.getOpcode() == AArch64::TBZX); 212a34c753fSRafael Auler } 213a34c753fSRafael Auler 214a34c753fSRafael Auler bool isCB(const MCInst &Inst) const { 215a34c753fSRafael Auler return (Inst.getOpcode() == AArch64::CBNZW || 216a34c753fSRafael Auler Inst.getOpcode() == AArch64::CBNZX || 217a34c753fSRafael Auler Inst.getOpcode() == AArch64::CBZW || 218a34c753fSRafael Auler Inst.getOpcode() == AArch64::CBZX); 219a34c753fSRafael Auler } 220a34c753fSRafael Auler 221a34c753fSRafael Auler bool isMOVW(const MCInst &Inst) const { 222a34c753fSRafael Auler return (Inst.getOpcode() == AArch64::MOVKWi || 223a34c753fSRafael Auler Inst.getOpcode() == AArch64::MOVKXi || 224a34c753fSRafael Auler Inst.getOpcode() == AArch64::MOVNWi || 225a34c753fSRafael Auler Inst.getOpcode() == AArch64::MOVNXi || 226a34c753fSRafael Auler Inst.getOpcode() == AArch64::MOVZXi || 227a34c753fSRafael Auler Inst.getOpcode() == AArch64::MOVZWi); 228a34c753fSRafael Auler } 229a34c753fSRafael Auler 230a34c753fSRafael Auler bool isADD(const MCInst &Inst) const { 231a34c753fSRafael Auler return (Inst.getOpcode() == AArch64::ADDSWri || 232a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSWrr || 233a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSWrs || 234a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSWrx || 235a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSXri || 236a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSXrr || 237a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSXrs || 238a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSXrx || 239a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDSXrx64 || 240a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDWri || 241a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDWrr || 242a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDWrs || 243a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDWrx || 244a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDXri || 245a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDXrr || 246a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDXrs || 247a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDXrx || 248a34c753fSRafael Auler Inst.getOpcode() == AArch64::ADDXrx64); 249a34c753fSRafael Auler } 250a34c753fSRafael Auler 251a34c753fSRafael Auler bool isLDRB(const MCInst &Inst) const { 252ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 253ad599c25SAlexey Moksyakov switch (opcode) { 254ad599c25SAlexey Moksyakov case AArch64::LDRBpost: 255ad599c25SAlexey Moksyakov case AArch64::LDRBBpost: 256ad599c25SAlexey Moksyakov case AArch64::LDRBBpre: 257ad599c25SAlexey Moksyakov case AArch64::LDRBBroW: 258ad599c25SAlexey Moksyakov case AArch64::LDRBroW: 259ad599c25SAlexey Moksyakov case AArch64::LDRBroX: 260ad599c25SAlexey Moksyakov case AArch64::LDRBBroX: 261ad599c25SAlexey Moksyakov case AArch64::LDRBBui: 262ad599c25SAlexey Moksyakov case AArch64::LDRBui: 263ad599c25SAlexey Moksyakov case AArch64::LDRBpre: 264ad599c25SAlexey Moksyakov case AArch64::LDRSBWpost: 265ad599c25SAlexey Moksyakov case AArch64::LDRSBWpre: 266ad599c25SAlexey Moksyakov case AArch64::LDRSBWroW: 267ad599c25SAlexey Moksyakov case AArch64::LDRSBWroX: 268ad599c25SAlexey Moksyakov case AArch64::LDRSBWui: 269ad599c25SAlexey Moksyakov case AArch64::LDRSBXpost: 270ad599c25SAlexey Moksyakov case AArch64::LDRSBXpre: 271ad599c25SAlexey Moksyakov case AArch64::LDRSBXroW: 272ad599c25SAlexey Moksyakov case AArch64::LDRSBXroX: 273ad599c25SAlexey Moksyakov case AArch64::LDRSBXui: 274ad599c25SAlexey Moksyakov case AArch64::LDURBi: 275ad599c25SAlexey Moksyakov case AArch64::LDURBBi: 276ad599c25SAlexey Moksyakov case AArch64::LDURSBWi: 277ad599c25SAlexey Moksyakov case AArch64::LDURSBXi: 278ad599c25SAlexey Moksyakov case AArch64::LDTRBi: 279ad599c25SAlexey Moksyakov case AArch64::LDTRSBWi: 280ad599c25SAlexey Moksyakov case AArch64::LDTRSBXi: 281ad599c25SAlexey Moksyakov return true; 282ad599c25SAlexey Moksyakov default: 283ad599c25SAlexey Moksyakov break; 284ad599c25SAlexey Moksyakov } 285ad599c25SAlexey Moksyakov 286ad599c25SAlexey Moksyakov return false; 287a34c753fSRafael Auler } 288a34c753fSRafael Auler 289a34c753fSRafael Auler bool isLDRH(const MCInst &Inst) const { 290ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 291ad599c25SAlexey Moksyakov switch (opcode) { 292ad599c25SAlexey Moksyakov case AArch64::LDRHpost: 293ad599c25SAlexey Moksyakov case AArch64::LDRHHpost: 294ad599c25SAlexey Moksyakov case AArch64::LDRHHpre: 295ad599c25SAlexey Moksyakov case AArch64::LDRHroW: 296ad599c25SAlexey Moksyakov case AArch64::LDRHHroW: 297ad599c25SAlexey Moksyakov case AArch64::LDRHroX: 298ad599c25SAlexey Moksyakov case AArch64::LDRHHroX: 299ad599c25SAlexey Moksyakov case AArch64::LDRHHui: 300ad599c25SAlexey Moksyakov case AArch64::LDRHui: 301ad599c25SAlexey Moksyakov case AArch64::LDRHpre: 302ad599c25SAlexey Moksyakov case AArch64::LDRSHWpost: 303ad599c25SAlexey Moksyakov case AArch64::LDRSHWpre: 304ad599c25SAlexey Moksyakov case AArch64::LDRSHWroW: 305ad599c25SAlexey Moksyakov case AArch64::LDRSHWroX: 306ad599c25SAlexey Moksyakov case AArch64::LDRSHWui: 307ad599c25SAlexey Moksyakov case AArch64::LDRSHXpost: 308ad599c25SAlexey Moksyakov case AArch64::LDRSHXpre: 309ad599c25SAlexey Moksyakov case AArch64::LDRSHXroW: 310ad599c25SAlexey Moksyakov case AArch64::LDRSHXroX: 311ad599c25SAlexey Moksyakov case AArch64::LDRSHXui: 312ad599c25SAlexey Moksyakov case AArch64::LDURHi: 313ad599c25SAlexey Moksyakov case AArch64::LDURHHi: 314ad599c25SAlexey Moksyakov case AArch64::LDURSHWi: 315ad599c25SAlexey Moksyakov case AArch64::LDURSHXi: 316ad599c25SAlexey Moksyakov case AArch64::LDTRHi: 317ad599c25SAlexey Moksyakov case AArch64::LDTRSHWi: 318ad599c25SAlexey Moksyakov case AArch64::LDTRSHXi: 319ad599c25SAlexey Moksyakov return true; 320ad599c25SAlexey Moksyakov default: 321ad599c25SAlexey Moksyakov break; 322ad599c25SAlexey Moksyakov } 323ad599c25SAlexey Moksyakov 324ad599c25SAlexey Moksyakov return false; 325a34c753fSRafael Auler } 326a34c753fSRafael Auler 327a34c753fSRafael Auler bool isLDRW(const MCInst &Inst) const { 328ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 329ad599c25SAlexey Moksyakov switch (opcode) { 330ad599c25SAlexey Moksyakov case AArch64::LDRWpost: 331ad599c25SAlexey Moksyakov case AArch64::LDRWpre: 332ad599c25SAlexey Moksyakov case AArch64::LDRWroW: 333ad599c25SAlexey Moksyakov case AArch64::LDRWroX: 334ad599c25SAlexey Moksyakov case AArch64::LDRWui: 335ad599c25SAlexey Moksyakov case AArch64::LDRWl: 336ad599c25SAlexey Moksyakov case AArch64::LDRSWl: 337ad599c25SAlexey Moksyakov case AArch64::LDURWi: 338ad599c25SAlexey Moksyakov case AArch64::LDRSWpost: 339ad599c25SAlexey Moksyakov case AArch64::LDRSWpre: 340ad599c25SAlexey Moksyakov case AArch64::LDRSWroW: 341ad599c25SAlexey Moksyakov case AArch64::LDRSWroX: 342ad599c25SAlexey Moksyakov case AArch64::LDRSWui: 343ad599c25SAlexey Moksyakov case AArch64::LDURSWi: 344ad599c25SAlexey Moksyakov case AArch64::LDTRWi: 345ad599c25SAlexey Moksyakov case AArch64::LDTRSWi: 346ad599c25SAlexey Moksyakov case AArch64::LDPWi: 347ad599c25SAlexey Moksyakov case AArch64::LDPWpost: 348ad599c25SAlexey Moksyakov case AArch64::LDPWpre: 349ad599c25SAlexey Moksyakov case AArch64::LDPSWi: 350ad599c25SAlexey Moksyakov case AArch64::LDPSWpost: 351ad599c25SAlexey Moksyakov case AArch64::LDPSWpre: 352ad599c25SAlexey Moksyakov case AArch64::LDNPWi: 353ad599c25SAlexey Moksyakov return true; 354ad599c25SAlexey Moksyakov default: 355ad599c25SAlexey Moksyakov break; 356ad599c25SAlexey Moksyakov } 357ad599c25SAlexey Moksyakov 358ad599c25SAlexey Moksyakov return false; 359a34c753fSRafael Auler } 360a34c753fSRafael Auler 361a34c753fSRafael Auler bool isLDRX(const MCInst &Inst) const { 362ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 363ad599c25SAlexey Moksyakov switch (opcode) { 364ad599c25SAlexey Moksyakov case AArch64::LDRXpost: 365ad599c25SAlexey Moksyakov case AArch64::LDRXpre: 366ad599c25SAlexey Moksyakov case AArch64::LDRXroW: 367ad599c25SAlexey Moksyakov case AArch64::LDRXroX: 368ad599c25SAlexey Moksyakov case AArch64::LDRXui: 369ad599c25SAlexey Moksyakov case AArch64::LDRXl: 370ad599c25SAlexey Moksyakov case AArch64::LDURXi: 371ad599c25SAlexey Moksyakov case AArch64::LDTRXi: 372ad599c25SAlexey Moksyakov case AArch64::LDNPXi: 373ad599c25SAlexey Moksyakov case AArch64::LDPXi: 374ad599c25SAlexey Moksyakov case AArch64::LDPXpost: 375ad599c25SAlexey Moksyakov case AArch64::LDPXpre: 376ad599c25SAlexey Moksyakov return true; 377ad599c25SAlexey Moksyakov default: 378ad599c25SAlexey Moksyakov break; 379ad599c25SAlexey Moksyakov } 380ad599c25SAlexey Moksyakov 381ad599c25SAlexey Moksyakov return false; 382ad599c25SAlexey Moksyakov } 383ad599c25SAlexey Moksyakov 384ad599c25SAlexey Moksyakov bool isLDRS(const MCInst &Inst) const { 385ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 386ad599c25SAlexey Moksyakov switch (opcode) { 387ad599c25SAlexey Moksyakov case AArch64::LDRSl: 388ad599c25SAlexey Moksyakov case AArch64::LDRSui: 389ad599c25SAlexey Moksyakov case AArch64::LDRSroW: 390ad599c25SAlexey Moksyakov case AArch64::LDRSroX: 391ad599c25SAlexey Moksyakov case AArch64::LDURSi: 392ad599c25SAlexey Moksyakov case AArch64::LDPSi: 393ad599c25SAlexey Moksyakov case AArch64::LDNPSi: 394ad599c25SAlexey Moksyakov case AArch64::LDRSpre: 395ad599c25SAlexey Moksyakov case AArch64::LDRSpost: 396ad599c25SAlexey Moksyakov case AArch64::LDPSpost: 397ad599c25SAlexey Moksyakov case AArch64::LDPSpre: 398ad599c25SAlexey Moksyakov return true; 399ad599c25SAlexey Moksyakov default: 400ad599c25SAlexey Moksyakov break; 401ad599c25SAlexey Moksyakov } 402ad599c25SAlexey Moksyakov 403ad599c25SAlexey Moksyakov return false; 404ad599c25SAlexey Moksyakov } 405ad599c25SAlexey Moksyakov 406ad599c25SAlexey Moksyakov bool isLDRD(const MCInst &Inst) const { 407ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 408ad599c25SAlexey Moksyakov switch (opcode) { 409ad599c25SAlexey Moksyakov case AArch64::LDRDl: 410ad599c25SAlexey Moksyakov case AArch64::LDRDui: 411ad599c25SAlexey Moksyakov case AArch64::LDRDpre: 412ad599c25SAlexey Moksyakov case AArch64::LDRDpost: 413ad599c25SAlexey Moksyakov case AArch64::LDRDroW: 414ad599c25SAlexey Moksyakov case AArch64::LDRDroX: 415ad599c25SAlexey Moksyakov case AArch64::LDURDi: 416ad599c25SAlexey Moksyakov case AArch64::LDPDi: 417ad599c25SAlexey Moksyakov case AArch64::LDNPDi: 418ad599c25SAlexey Moksyakov case AArch64::LDPDpost: 419ad599c25SAlexey Moksyakov case AArch64::LDPDpre: 420ad599c25SAlexey Moksyakov return true; 421ad599c25SAlexey Moksyakov default: 422ad599c25SAlexey Moksyakov break; 423ad599c25SAlexey Moksyakov } 424ad599c25SAlexey Moksyakov 425ad599c25SAlexey Moksyakov return false; 426ad599c25SAlexey Moksyakov } 427ad599c25SAlexey Moksyakov 428ad599c25SAlexey Moksyakov bool isLDRQ(const MCInst &Inst) const { 429ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 430ad599c25SAlexey Moksyakov switch (opcode) { 431ad599c25SAlexey Moksyakov case AArch64::LDRQui: 432ad599c25SAlexey Moksyakov case AArch64::LDRQl: 433ad599c25SAlexey Moksyakov case AArch64::LDRQpre: 434ad599c25SAlexey Moksyakov case AArch64::LDRQpost: 435ad599c25SAlexey Moksyakov case AArch64::LDRQroW: 436ad599c25SAlexey Moksyakov case AArch64::LDRQroX: 437ad599c25SAlexey Moksyakov case AArch64::LDURQi: 438ad599c25SAlexey Moksyakov case AArch64::LDPQi: 439ad599c25SAlexey Moksyakov case AArch64::LDNPQi: 440ad599c25SAlexey Moksyakov case AArch64::LDPQpost: 441ad599c25SAlexey Moksyakov case AArch64::LDPQpre: 442ad599c25SAlexey Moksyakov return true; 443ad599c25SAlexey Moksyakov default: 444ad599c25SAlexey Moksyakov break; 445ad599c25SAlexey Moksyakov } 446ad599c25SAlexey Moksyakov 447ad599c25SAlexey Moksyakov return false; 448a34c753fSRafael Auler } 449a34c753fSRafael Auler 450eafe4ee2SJob Noorman bool mayLoad(const MCInst &Inst) const override { 451ad599c25SAlexey Moksyakov return isLDRB(Inst) || isLDRH(Inst) || isLDRW(Inst) || isLDRX(Inst) || 452ad599c25SAlexey Moksyakov isLDRQ(Inst) || isLDRD(Inst) || isLDRS(Inst); 453a34c753fSRafael Auler } 454a34c753fSRafael Auler 455b98e6a5cSElvina Yakubova bool isAArch64ExclusiveLoad(const MCInst &Inst) const override { 456846eb767SVladislav Khmelevsky return (Inst.getOpcode() == AArch64::LDXPX || 457846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDXPW || 458846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDXRX || 459846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDXRW || 460846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDXRH || 461846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDXRB || 462846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDAXPX || 463846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDAXPW || 464846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDAXRX || 465846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDAXRW || 466846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::LDAXRH || 467b98e6a5cSElvina Yakubova Inst.getOpcode() == AArch64::LDAXRB); 468b98e6a5cSElvina Yakubova } 469b98e6a5cSElvina Yakubova 470b98e6a5cSElvina Yakubova bool isAArch64ExclusiveStore(const MCInst &Inst) const override { 471b98e6a5cSElvina Yakubova return (Inst.getOpcode() == AArch64::STXPX || 472b98e6a5cSElvina Yakubova Inst.getOpcode() == AArch64::STXPW || 473b98e6a5cSElvina Yakubova Inst.getOpcode() == AArch64::STXRX || 474b98e6a5cSElvina Yakubova Inst.getOpcode() == AArch64::STXRW || 475b98e6a5cSElvina Yakubova Inst.getOpcode() == AArch64::STXRH || 476b98e6a5cSElvina Yakubova Inst.getOpcode() == AArch64::STXRB || 477846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::STLXPX || 478846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::STLXPW || 479846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::STLXRX || 480846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::STLXRW || 481846eb767SVladislav Khmelevsky Inst.getOpcode() == AArch64::STLXRH || 482b98e6a5cSElvina Yakubova Inst.getOpcode() == AArch64::STLXRB); 483b98e6a5cSElvina Yakubova } 484b98e6a5cSElvina Yakubova 485b98e6a5cSElvina Yakubova bool isAArch64ExclusiveClear(const MCInst &Inst) const override { 486b98e6a5cSElvina Yakubova return (Inst.getOpcode() == AArch64::CLREX); 487846eb767SVladislav Khmelevsky } 488846eb767SVladislav Khmelevsky 489a34c753fSRafael Auler bool isLoadFromStack(const MCInst &Inst) const { 490eafe4ee2SJob Noorman if (!mayLoad(Inst)) 491a34c753fSRafael Auler return false; 492b6f07d3aSAmir Ayupov for (const MCOperand &Operand : useOperands(Inst)) { 493a34c753fSRafael Auler if (!Operand.isReg()) 494a34c753fSRafael Auler continue; 495a34c753fSRafael Auler unsigned Reg = Operand.getReg(); 496ad599c25SAlexey Moksyakov if (Reg == AArch64::SP || Reg == AArch64::WSP) 497a34c753fSRafael Auler return true; 498a34c753fSRafael Auler } 499a34c753fSRafael Auler return false; 500a34c753fSRafael Auler } 501a34c753fSRafael Auler 502a34c753fSRafael Auler bool isRegToRegMove(const MCInst &Inst, MCPhysReg &From, 503a34c753fSRafael Auler MCPhysReg &To) const override { 504f20af737Seleviant if (Inst.getOpcode() == AArch64::FMOVDXr) { 505f20af737Seleviant From = Inst.getOperand(1).getReg(); 506f20af737Seleviant To = Inst.getOperand(0).getReg(); 507f20af737Seleviant return true; 508f20af737Seleviant } 509f20af737Seleviant 510a34c753fSRafael Auler if (Inst.getOpcode() != AArch64::ORRXrs) 511a34c753fSRafael Auler return false; 512a34c753fSRafael Auler if (Inst.getOperand(1).getReg() != AArch64::XZR) 513a34c753fSRafael Auler return false; 514a34c753fSRafael Auler if (Inst.getOperand(3).getImm() != 0) 515a34c753fSRafael Auler return false; 516a34c753fSRafael Auler From = Inst.getOperand(2).getReg(); 517a34c753fSRafael Auler To = Inst.getOperand(0).getReg(); 518a34c753fSRafael Auler return true; 519a34c753fSRafael Auler } 520a34c753fSRafael Auler 521a34c753fSRafael Auler bool isIndirectCall(const MCInst &Inst) const override { 522a34c753fSRafael Auler return Inst.getOpcode() == AArch64::BLR; 523a34c753fSRafael Auler } 524a34c753fSRafael Auler 5256e4c2305SElvina Yakubova MCPhysReg getSpRegister(int Size) const { 5266e4c2305SElvina Yakubova switch (Size) { 5276e4c2305SElvina Yakubova case 4: 5286e4c2305SElvina Yakubova return AArch64::WSP; 5296e4c2305SElvina Yakubova case 8: 5306e4c2305SElvina Yakubova return AArch64::SP; 5316e4c2305SElvina Yakubova default: 5326e4c2305SElvina Yakubova llvm_unreachable("Unexpected size"); 5336e4c2305SElvina Yakubova } 5346e4c2305SElvina Yakubova } 5356e4c2305SElvina Yakubova 5366e4c2305SElvina Yakubova MCPhysReg getIntArgRegister(unsigned ArgNo) const override { 5376e4c2305SElvina Yakubova switch (ArgNo) { 5386e4c2305SElvina Yakubova case 0: 5396e4c2305SElvina Yakubova return AArch64::X0; 5406e4c2305SElvina Yakubova case 1: 5416e4c2305SElvina Yakubova return AArch64::X1; 5426e4c2305SElvina Yakubova case 2: 5436e4c2305SElvina Yakubova return AArch64::X2; 5446e4c2305SElvina Yakubova case 3: 5456e4c2305SElvina Yakubova return AArch64::X3; 5466e4c2305SElvina Yakubova case 4: 5476e4c2305SElvina Yakubova return AArch64::X4; 5486e4c2305SElvina Yakubova case 5: 5496e4c2305SElvina Yakubova return AArch64::X5; 5506e4c2305SElvina Yakubova case 6: 5516e4c2305SElvina Yakubova return AArch64::X6; 5526e4c2305SElvina Yakubova case 7: 5536e4c2305SElvina Yakubova return AArch64::X7; 5546e4c2305SElvina Yakubova default: 5556e4c2305SElvina Yakubova return getNoRegister(); 5566e4c2305SElvina Yakubova } 5576e4c2305SElvina Yakubova } 5586e4c2305SElvina Yakubova 559a34c753fSRafael Auler bool hasPCRelOperand(const MCInst &Inst) const override { 560a34c753fSRafael Auler // ADRP is blacklisted and is an exception. Even though it has a 561a34c753fSRafael Auler // PC-relative operand, this operand is not a complete symbol reference 562a34c753fSRafael Auler // and BOLT shouldn't try to process it in isolation. 563a34c753fSRafael Auler if (isADRP(Inst)) 564a34c753fSRafael Auler return false; 565a34c753fSRafael Auler 566a34c753fSRafael Auler if (isADR(Inst)) 567a34c753fSRafael Auler return true; 568a34c753fSRafael Auler 569a34c753fSRafael Auler // Look for literal addressing mode (see C1-143 ARM DDI 0487B.a) 570a34c753fSRafael Auler const MCInstrDesc &MCII = Info->get(Inst.getOpcode()); 57189ceb779SAmir Ayupov for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) 572fbb00337SJay Foad if (MCII.operands()[I].OperandType == MCOI::OPERAND_PCREL) 573a34c753fSRafael Auler return true; 57489ceb779SAmir Ayupov 575a34c753fSRafael Auler return false; 576a34c753fSRafael Auler } 577a34c753fSRafael Auler 578a34c753fSRafael Auler bool evaluateADR(const MCInst &Inst, int64_t &Imm, 579a34c753fSRafael Auler const MCExpr **DispExpr) const { 580a34c753fSRafael Auler assert((isADR(Inst) || isADRP(Inst)) && "Not an ADR instruction"); 581a34c753fSRafael Auler 582a34c753fSRafael Auler const MCOperand &Label = Inst.getOperand(1); 583a34c753fSRafael Auler if (!Label.isImm()) { 584a34c753fSRafael Auler assert(Label.isExpr() && "Unexpected ADR operand"); 585a34c753fSRafael Auler assert(DispExpr && "DispExpr must be set"); 586a34c753fSRafael Auler *DispExpr = Label.getExpr(); 587a34c753fSRafael Auler return false; 588a34c753fSRafael Auler } 589a34c753fSRafael Auler 590a34c753fSRafael Auler if (Inst.getOpcode() == AArch64::ADR) { 591a34c753fSRafael Auler Imm = Label.getImm(); 592a34c753fSRafael Auler return true; 593a34c753fSRafael Auler } 594a34c753fSRafael Auler Imm = Label.getImm() << 12; 595a34c753fSRafael Auler return true; 596a34c753fSRafael Auler } 597a34c753fSRafael Auler 59840c2e0faSMaksim Panchenko bool evaluateAArch64MemoryOperand(const MCInst &Inst, int64_t &DispImm, 59940c2e0faSMaksim Panchenko const MCExpr **DispExpr = nullptr) const { 600a34c753fSRafael Auler if (isADR(Inst) || isADRP(Inst)) 601a34c753fSRafael Auler return evaluateADR(Inst, DispImm, DispExpr); 602a34c753fSRafael Auler 603a34c753fSRafael Auler // Literal addressing mode 604a34c753fSRafael Auler const MCInstrDesc &MCII = Info->get(Inst.getOpcode()); 605a34c753fSRafael Auler for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) { 606fbb00337SJay Foad if (MCII.operands()[I].OperandType != MCOI::OPERAND_PCREL) 607a34c753fSRafael Auler continue; 608a34c753fSRafael Auler 609a34c753fSRafael Auler if (!Inst.getOperand(I).isImm()) { 610a34c753fSRafael Auler assert(Inst.getOperand(I).isExpr() && "Unexpected PCREL operand"); 611a34c753fSRafael Auler assert(DispExpr && "DispExpr must be set"); 612a34c753fSRafael Auler *DispExpr = Inst.getOperand(I).getExpr(); 613a34c753fSRafael Auler return true; 614a34c753fSRafael Auler } 615a34c753fSRafael Auler 616df3f1e2fSJob Noorman DispImm = Inst.getOperand(I).getImm() * 4; 617a34c753fSRafael Auler return true; 618a34c753fSRafael Auler } 619a34c753fSRafael Auler return false; 620a34c753fSRafael Auler } 621a34c753fSRafael Auler 622a34c753fSRafael Auler bool evaluateMemOperandTarget(const MCInst &Inst, uint64_t &Target, 623a34c753fSRafael Auler uint64_t Address, 624a34c753fSRafael Auler uint64_t Size) const override { 625a34c753fSRafael Auler int64_t DispValue; 626a34c753fSRafael Auler const MCExpr *DispExpr = nullptr; 627a34c753fSRafael Auler if (!evaluateAArch64MemoryOperand(Inst, DispValue, &DispExpr)) 628a34c753fSRafael Auler return false; 629a34c753fSRafael Auler 630a34c753fSRafael Auler // Make sure it's a well-formed addressing we can statically evaluate. 631a34c753fSRafael Auler if (DispExpr) 632a34c753fSRafael Auler return false; 633a34c753fSRafael Auler 634a34c753fSRafael Auler Target = DispValue; 635a34c753fSRafael Auler if (Inst.getOpcode() == AArch64::ADRP) 636a34c753fSRafael Auler Target += Address & ~0xFFFULL; 637a34c753fSRafael Auler else 638a34c753fSRafael Auler Target += Address; 639a34c753fSRafael Auler return true; 640a34c753fSRafael Auler } 641a34c753fSRafael Auler 6428d1fc45dSRafael Auler MCInst::iterator getMemOperandDisp(MCInst &Inst) const override { 643a34c753fSRafael Auler MCInst::iterator OI = Inst.begin(); 644a34c753fSRafael Auler if (isADR(Inst) || isADRP(Inst)) { 645a34c753fSRafael Auler assert(MCPlus::getNumPrimeOperands(Inst) >= 2 && 646a34c753fSRafael Auler "Unexpected number of operands"); 6478d1fc45dSRafael Auler return ++OI; 6488d1fc45dSRafael Auler } 649a34c753fSRafael Auler const MCInstrDesc &MCII = Info->get(Inst.getOpcode()); 650a34c753fSRafael Auler for (unsigned I = 0, E = MCII.getNumOperands(); I != E; ++I) { 651fbb00337SJay Foad if (MCII.operands()[I].OperandType == MCOI::OPERAND_PCREL) 652a34c753fSRafael Auler break; 653a34c753fSRafael Auler ++OI; 654a34c753fSRafael Auler } 655a34c753fSRafael Auler assert(OI != Inst.end() && "Literal operand not found"); 6568d1fc45dSRafael Auler return OI; 657a34c753fSRafael Auler } 6588d1fc45dSRafael Auler 6598d1fc45dSRafael Auler bool replaceMemOperandDisp(MCInst &Inst, MCOperand Operand) const override { 6608d1fc45dSRafael Auler MCInst::iterator OI = getMemOperandDisp(Inst); 661a34c753fSRafael Auler *OI = Operand; 662a34c753fSRafael Auler return true; 663a34c753fSRafael Auler } 664a34c753fSRafael Auler 6652d902d0fSKepontry void getCalleeSavedRegs(BitVector &Regs) const override { 6662d902d0fSKepontry Regs |= getAliases(AArch64::X18); 6672d902d0fSKepontry Regs |= getAliases(AArch64::X19); 6682d902d0fSKepontry Regs |= getAliases(AArch64::X20); 6692d902d0fSKepontry Regs |= getAliases(AArch64::X21); 6702d902d0fSKepontry Regs |= getAliases(AArch64::X22); 6712d902d0fSKepontry Regs |= getAliases(AArch64::X23); 6722d902d0fSKepontry Regs |= getAliases(AArch64::X24); 6732d902d0fSKepontry Regs |= getAliases(AArch64::X25); 6742d902d0fSKepontry Regs |= getAliases(AArch64::X26); 6752d902d0fSKepontry Regs |= getAliases(AArch64::X27); 6762d902d0fSKepontry Regs |= getAliases(AArch64::X28); 6772d902d0fSKepontry Regs |= getAliases(AArch64::LR); 6782d902d0fSKepontry Regs |= getAliases(AArch64::FP); 6792d902d0fSKepontry } 6802d902d0fSKepontry 681a34c753fSRafael Auler const MCExpr *getTargetExprFor(MCInst &Inst, const MCExpr *Expr, 682a34c753fSRafael Auler MCContext &Ctx, 683a34c753fSRafael Auler uint64_t RelType) const override { 684a34c753fSRafael Auler 685a34c753fSRafael Auler if (isADR(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_LO21 || 686a34c753fSRafael Auler RelType == ELF::R_AARCH64_TLSDESC_ADR_PREL21) { 687a34c753fSRafael Auler return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS, Ctx); 688a34c753fSRafael Auler } else if (isADRP(Inst) || RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21 || 689a34c753fSRafael Auler RelType == ELF::R_AARCH64_ADR_PREL_PG_HI21_NC || 690a34c753fSRafael Auler RelType == ELF::R_AARCH64_TLSDESC_ADR_PAGE21 || 691a34c753fSRafael Auler RelType == ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21 || 692a34c753fSRafael Auler RelType == ELF::R_AARCH64_ADR_GOT_PAGE) { 693a34c753fSRafael Auler // Never emit a GOT reloc, we handled this in 694a34c753fSRafael Auler // RewriteInstance::readRelocations(). 695a34c753fSRafael Auler return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_PAGE, Ctx); 696a34c753fSRafael Auler } else { 697a34c753fSRafael Auler switch (RelType) { 698a34c753fSRafael Auler case ELF::R_AARCH64_ADD_ABS_LO12_NC: 699a34c753fSRafael Auler case ELF::R_AARCH64_LD64_GOT_LO12_NC: 700a34c753fSRafael Auler case ELF::R_AARCH64_LDST8_ABS_LO12_NC: 701a34c753fSRafael Auler case ELF::R_AARCH64_LDST16_ABS_LO12_NC: 702a34c753fSRafael Auler case ELF::R_AARCH64_LDST32_ABS_LO12_NC: 703a34c753fSRafael Auler case ELF::R_AARCH64_LDST64_ABS_LO12_NC: 704a34c753fSRafael Auler case ELF::R_AARCH64_LDST128_ABS_LO12_NC: 705a34c753fSRafael Auler case ELF::R_AARCH64_TLSDESC_ADD_LO12: 706a34c753fSRafael Auler case ELF::R_AARCH64_TLSDESC_LD64_LO12: 707a34c753fSRafael Auler case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: 708a34c753fSRafael Auler case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: 709a34c753fSRafael Auler return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_LO12, Ctx); 710a34c753fSRafael Auler case ELF::R_AARCH64_MOVW_UABS_G3: 711a34c753fSRafael Auler return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G3, Ctx); 712a34c753fSRafael Auler case ELF::R_AARCH64_MOVW_UABS_G2: 713a34c753fSRafael Auler case ELF::R_AARCH64_MOVW_UABS_G2_NC: 714a34c753fSRafael Auler return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G2_NC, Ctx); 715a34c753fSRafael Auler case ELF::R_AARCH64_MOVW_UABS_G1: 716a34c753fSRafael Auler case ELF::R_AARCH64_MOVW_UABS_G1_NC: 717a34c753fSRafael Auler return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G1_NC, Ctx); 718a34c753fSRafael Auler case ELF::R_AARCH64_MOVW_UABS_G0: 719a34c753fSRafael Auler case ELF::R_AARCH64_MOVW_UABS_G0_NC: 720a34c753fSRafael Auler return AArch64MCExpr::create(Expr, AArch64MCExpr::VK_ABS_G0_NC, Ctx); 721a34c753fSRafael Auler default: 722a34c753fSRafael Auler break; 723a34c753fSRafael Auler } 724a34c753fSRafael Auler } 725a34c753fSRafael Auler return Expr; 726a34c753fSRafael Auler } 727a34c753fSRafael Auler 728a34c753fSRafael Auler bool getSymbolRefOperandNum(const MCInst &Inst, unsigned &OpNum) const { 729a34c753fSRafael Auler if (OpNum >= MCPlus::getNumPrimeOperands(Inst)) 730a34c753fSRafael Auler return false; 731a34c753fSRafael Auler 732a34c753fSRafael Auler // Auto-select correct operand number 733a34c753fSRafael Auler if (OpNum == 0) { 73417ed8f29SVladislav Khmelevsky if (isConditionalBranch(Inst) || isADR(Inst) || isADRP(Inst) || 73517ed8f29SVladislav Khmelevsky isMOVW(Inst)) 736a34c753fSRafael Auler OpNum = 1; 73717ed8f29SVladislav Khmelevsky if (isTB(Inst) || isAddXri(Inst)) 738a34c753fSRafael Auler OpNum = 2; 739a34c753fSRafael Auler } 740a34c753fSRafael Auler 741a34c753fSRafael Auler return true; 742a34c753fSRafael Auler } 743a34c753fSRafael Auler 744a34c753fSRafael Auler const MCSymbol *getTargetSymbol(const MCExpr *Expr) const override { 745a34c753fSRafael Auler auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr); 746a34c753fSRafael Auler if (AArchExpr && AArchExpr->getSubExpr()) 747a34c753fSRafael Auler return getTargetSymbol(AArchExpr->getSubExpr()); 748a34c753fSRafael Auler 749a34c753fSRafael Auler auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr); 750a34c753fSRafael Auler if (BinExpr) 751a34c753fSRafael Auler return getTargetSymbol(BinExpr->getLHS()); 752a34c753fSRafael Auler 753a34c753fSRafael Auler auto *SymExpr = dyn_cast<MCSymbolRefExpr>(Expr); 754a34c753fSRafael Auler if (SymExpr && SymExpr->getKind() == MCSymbolRefExpr::VK_None) 755a34c753fSRafael Auler return &SymExpr->getSymbol(); 756a34c753fSRafael Auler 757a34c753fSRafael Auler return nullptr; 758a34c753fSRafael Auler } 759a34c753fSRafael Auler 760a34c753fSRafael Auler const MCSymbol *getTargetSymbol(const MCInst &Inst, 761a34c753fSRafael Auler unsigned OpNum = 0) const override { 762a34c753fSRafael Auler if (!getSymbolRefOperandNum(Inst, OpNum)) 763a34c753fSRafael Auler return nullptr; 764a34c753fSRafael Auler 765a34c753fSRafael Auler const MCOperand &Op = Inst.getOperand(OpNum); 766a34c753fSRafael Auler if (!Op.isExpr()) 767a34c753fSRafael Auler return nullptr; 768a34c753fSRafael Auler 769a34c753fSRafael Auler return getTargetSymbol(Op.getExpr()); 770a34c753fSRafael Auler } 771a34c753fSRafael Auler 772a34c753fSRafael Auler int64_t getTargetAddend(const MCExpr *Expr) const override { 773a34c753fSRafael Auler auto *AArchExpr = dyn_cast<AArch64MCExpr>(Expr); 774a34c753fSRafael Auler if (AArchExpr && AArchExpr->getSubExpr()) 775a34c753fSRafael Auler return getTargetAddend(AArchExpr->getSubExpr()); 776a34c753fSRafael Auler 777a34c753fSRafael Auler auto *BinExpr = dyn_cast<MCBinaryExpr>(Expr); 778a34c753fSRafael Auler if (BinExpr && BinExpr->getOpcode() == MCBinaryExpr::Add) 779a34c753fSRafael Auler return getTargetAddend(BinExpr->getRHS()); 780a34c753fSRafael Auler 781a34c753fSRafael Auler auto *ConstExpr = dyn_cast<MCConstantExpr>(Expr); 782a34c753fSRafael Auler if (ConstExpr) 783a34c753fSRafael Auler return ConstExpr->getValue(); 784a34c753fSRafael Auler 785a34c753fSRafael Auler return 0; 786a34c753fSRafael Auler } 787a34c753fSRafael Auler 788a34c753fSRafael Auler int64_t getTargetAddend(const MCInst &Inst, 789a34c753fSRafael Auler unsigned OpNum = 0) const override { 790a34c753fSRafael Auler if (!getSymbolRefOperandNum(Inst, OpNum)) 791a34c753fSRafael Auler return 0; 792a34c753fSRafael Auler 793a34c753fSRafael Auler const MCOperand &Op = Inst.getOperand(OpNum); 794a34c753fSRafael Auler if (!Op.isExpr()) 795a34c753fSRafael Auler return 0; 796a34c753fSRafael Auler 797a34c753fSRafael Auler return getTargetAddend(Op.getExpr()); 798a34c753fSRafael Auler } 799a34c753fSRafael Auler 8003fefb3c5SNathan Sidwell void replaceBranchTarget(MCInst &Inst, const MCSymbol *TBB, 801a34c753fSRafael Auler MCContext *Ctx) const override { 802a34c753fSRafael Auler assert((isCall(Inst) || isBranch(Inst)) && !isIndirectBranch(Inst) && 803a34c753fSRafael Auler "Invalid instruction"); 804a34c753fSRafael Auler assert(MCPlus::getNumPrimeOperands(Inst) >= 1 && 805a34c753fSRafael Auler "Invalid number of operands"); 806a34c753fSRafael Auler MCInst::iterator OI = Inst.begin(); 807a34c753fSRafael Auler 808a34c753fSRafael Auler if (isConditionalBranch(Inst)) { 809a34c753fSRafael Auler assert(MCPlus::getNumPrimeOperands(Inst) >= 2 && 810a34c753fSRafael Auler "Invalid number of operands"); 811a34c753fSRafael Auler ++OI; 812a34c753fSRafael Auler } 813a34c753fSRafael Auler 814a34c753fSRafael Auler if (isTB(Inst)) { 815a34c753fSRafael Auler assert(MCPlus::getNumPrimeOperands(Inst) >= 3 && 816a34c753fSRafael Auler "Invalid number of operands"); 817a34c753fSRafael Auler OI = Inst.begin() + 2; 818a34c753fSRafael Auler } 819a34c753fSRafael Auler 820a34c753fSRafael Auler *OI = MCOperand::createExpr( 821a34c753fSRafael Auler MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx)); 822a34c753fSRafael Auler } 823a34c753fSRafael Auler 824a34c753fSRafael Auler /// Matches indirect branch patterns in AArch64 related to a jump table (JT), 825a34c753fSRafael Auler /// helping us to build the complete CFG. A typical indirect branch to 826a34c753fSRafael Auler /// a jump table entry in AArch64 looks like the following: 827a34c753fSRafael Auler /// 828a34c753fSRafael Auler /// adrp x1, #-7585792 # Get JT Page location 829a34c753fSRafael Auler /// add x1, x1, #692 # Complement with JT Page offset 830a34c753fSRafael Auler /// ldrh w0, [x1, w0, uxtw #1] # Loads JT entry 831a34c753fSRafael Auler /// adr x1, #12 # Get PC + 12 (end of this BB) used next 832a34c753fSRafael Auler /// add x0, x1, w0, sxth #2 # Finish building branch target 833a34c753fSRafael Auler /// # (entries in JT are relative to the end 834a34c753fSRafael Auler /// # of this BB) 835a34c753fSRafael Auler /// br x0 # Indirect jump instruction 836a34c753fSRafael Auler /// 837*1b4bd4e1SMaksim Panchenko /// Return true on successful jump table instruction sequence match, false 838*1b4bd4e1SMaksim Panchenko /// otherwise. 839a34c753fSRafael Auler bool analyzeIndirectBranchFragment( 840a34c753fSRafael Auler const MCInst &Inst, 841a34c753fSRafael Auler DenseMap<const MCInst *, SmallVector<MCInst *, 4>> &UDChain, 842a34c753fSRafael Auler const MCExpr *&JumpTable, int64_t &Offset, int64_t &ScaleValue, 843a34c753fSRafael Auler MCInst *&PCRelBase) const { 844a34c753fSRafael Auler // Expect AArch64 BR 845a34c753fSRafael Auler assert(Inst.getOpcode() == AArch64::BR && "Unexpected opcode"); 846a34c753fSRafael Auler 847*1b4bd4e1SMaksim Panchenko JumpTable = nullptr; 848*1b4bd4e1SMaksim Panchenko 849a34c753fSRafael Auler // Match the indirect branch pattern for aarch64 850a34c753fSRafael Auler SmallVector<MCInst *, 4> &UsesRoot = UDChain[&Inst]; 85189ceb779SAmir Ayupov if (UsesRoot.size() == 0 || UsesRoot[0] == nullptr) 852a34c753fSRafael Auler return false; 85389ceb779SAmir Ayupov 854a34c753fSRafael Auler const MCInst *DefAdd = UsesRoot[0]; 855a34c753fSRafael Auler 856a34c753fSRafael Auler // Now we match an ADD 857a34c753fSRafael Auler if (!isADD(*DefAdd)) { 858a34c753fSRafael Auler // If the address is not broken up in two parts, this is not branching 859a34c753fSRafael Auler // according to a jump table entry. Fail. 860a34c753fSRafael Auler return false; 861a34c753fSRafael Auler } 862a34c753fSRafael Auler if (DefAdd->getOpcode() == AArch64::ADDXri) { 863a34c753fSRafael Auler // This can happen when there is no offset, but a direct jump that was 864a34c753fSRafael Auler // transformed into an indirect one (indirect tail call) : 865a34c753fSRafael Auler // ADRP x2, Perl_re_compiler 866a34c753fSRafael Auler // ADD x2, x2, :lo12:Perl_re_compiler 867a34c753fSRafael Auler // BR x2 868a34c753fSRafael Auler return false; 869a34c753fSRafael Auler } 870a34c753fSRafael Auler if (DefAdd->getOpcode() == AArch64::ADDXrs) { 871a34c753fSRafael Auler // Covers the less common pattern where JT entries are relative to 872a34c753fSRafael Auler // the JT itself (like x86). Seems less efficient since we can't 873a34c753fSRafael Auler // assume the JT is aligned at 4B boundary and thus drop 2 bits from 874a34c753fSRafael Auler // JT values. 875a34c753fSRafael Auler // cde264: 876a34c753fSRafael Auler // adrp x12, #21544960 ; 216a000 877a34c753fSRafael Auler // add x12, x12, #1696 ; 216a6a0 (JT object in .rodata) 878a34c753fSRafael Auler // ldrsw x8, [x12, x8, lsl #2] --> loads e.g. 0xfeb73bd8 879a34c753fSRafael Auler // * add x8, x8, x12 --> = cde278, next block 880a34c753fSRafael Auler // br x8 881a34c753fSRafael Auler // cde278: 882a34c753fSRafael Auler // 883a34c753fSRafael Auler // Parsed as ADDXrs reg:x8 reg:x8 reg:x12 imm:0 884a34c753fSRafael Auler return false; 885a34c753fSRafael Auler } 886*1b4bd4e1SMaksim Panchenko if (DefAdd->getOpcode() != AArch64::ADDXrx) 887*1b4bd4e1SMaksim Panchenko return false; 888a34c753fSRafael Auler 889a34c753fSRafael Auler // Validate ADD operands 890a34c753fSRafael Auler int64_t OperandExtension = DefAdd->getOperand(3).getImm(); 891a34c753fSRafael Auler unsigned ShiftVal = AArch64_AM::getArithShiftValue(OperandExtension); 892a34c753fSRafael Auler AArch64_AM::ShiftExtendType ExtendType = 893a34c753fSRafael Auler AArch64_AM::getArithExtendType(OperandExtension); 894e2cee2c1SÁdám Kallai if (ShiftVal != 2) { 895e2cee2c1SÁdám Kallai // TODO: Handle the patten where ShiftVal != 2. 896e2cee2c1SÁdám Kallai // The following code sequence below has no shift amount, 897e2cee2c1SÁdám Kallai // the range could be 0 to 4. 898e2cee2c1SÁdám Kallai // The pattern comes from libc, it occurs when the binary is static. 899e2cee2c1SÁdám Kallai // adr x6, 0x219fb0 <sigall_set+0x88> 900e2cee2c1SÁdám Kallai // add x6, x6, x14, lsl #2 901e2cee2c1SÁdám Kallai // ldr w7, [x6] 902e2cee2c1SÁdám Kallai // add x6, x6, w7, sxtw => no shift amount 903e2cee2c1SÁdám Kallai // br x6 904*1b4bd4e1SMaksim Panchenko LLVM_DEBUG(dbgs() << "BOLT-DEBUG: " 905*1b4bd4e1SMaksim Panchenko "failed to match indirect branch: ShiftVAL != 2\n"); 906e2cee2c1SÁdám Kallai return false; 907e2cee2c1SÁdám Kallai } 90889ceb779SAmir Ayupov 90989ceb779SAmir Ayupov if (ExtendType == AArch64_AM::SXTB) 910a34c753fSRafael Auler ScaleValue = 1LL; 91189ceb779SAmir Ayupov else if (ExtendType == AArch64_AM::SXTH) 912a34c753fSRafael Auler ScaleValue = 2LL; 91389ceb779SAmir Ayupov else if (ExtendType == AArch64_AM::SXTW) 914a34c753fSRafael Auler ScaleValue = 4LL; 91589ceb779SAmir Ayupov else 916*1b4bd4e1SMaksim Panchenko return false; 917a34c753fSRafael Auler 918a34c753fSRafael Auler // Match an ADR to load base address to be used when addressing JT targets 919a34c753fSRafael Auler SmallVector<MCInst *, 4> &UsesAdd = UDChain[DefAdd]; 920a34c753fSRafael Auler if (UsesAdd.size() <= 1 || UsesAdd[1] == nullptr || UsesAdd[2] == nullptr) { 921a34c753fSRafael Auler // This happens when we don't have enough context about this jump table 922a34c753fSRafael Auler // because the jumping code sequence was split in multiple basic blocks. 923a34c753fSRafael Auler // This was observed in the wild in HHVM code (dispatchImpl). 924a34c753fSRafael Auler return false; 925a34c753fSRafael Auler } 926a34c753fSRafael Auler MCInst *DefBaseAddr = UsesAdd[1]; 927*1b4bd4e1SMaksim Panchenko if (DefBaseAddr->getOpcode() != AArch64::ADR) 928*1b4bd4e1SMaksim Panchenko return false; 929a34c753fSRafael Auler 930a34c753fSRafael Auler PCRelBase = DefBaseAddr; 931a34c753fSRafael Auler // Match LOAD to load the jump table (relative) target 932a34c753fSRafael Auler const MCInst *DefLoad = UsesAdd[2]; 933*1b4bd4e1SMaksim Panchenko if (!mayLoad(*DefLoad) || (ScaleValue == 1LL && !isLDRB(*DefLoad)) || 934*1b4bd4e1SMaksim Panchenko (ScaleValue == 2LL && !isLDRH(*DefLoad))) 935*1b4bd4e1SMaksim Panchenko return false; 936a34c753fSRafael Auler 937a34c753fSRafael Auler // Match ADD that calculates the JumpTable Base Address (not the offset) 938a34c753fSRafael Auler SmallVector<MCInst *, 4> &UsesLoad = UDChain[DefLoad]; 939a34c753fSRafael Auler const MCInst *DefJTBaseAdd = UsesLoad[1]; 940a34c753fSRafael Auler MCPhysReg From, To; 941a34c753fSRafael Auler if (DefJTBaseAdd == nullptr || isLoadFromStack(*DefJTBaseAdd) || 942a34c753fSRafael Auler isRegToRegMove(*DefJTBaseAdd, From, To)) { 943a34c753fSRafael Auler // Sometimes base address may have been defined in another basic block 944a34c753fSRafael Auler // (hoisted). Return with no jump table info. 945a34c753fSRafael Auler return true; 946a34c753fSRafael Auler } 947a34c753fSRafael Auler 948e2cee2c1SÁdám Kallai if (DefJTBaseAdd->getOpcode() == AArch64::ADR) { 949e2cee2c1SÁdám Kallai // TODO: Handle the pattern where there is no adrp/add pair. 950e2cee2c1SÁdám Kallai // It also occurs when the binary is static. 951e2cee2c1SÁdám Kallai // adr x13, 0x215a18 <_nl_value_type_LC_COLLATE+0x50> 952e2cee2c1SÁdám Kallai // ldrh w13, [x13, w12, uxtw #1] 953e2cee2c1SÁdám Kallai // adr x12, 0x247b30 <__gettextparse+0x5b0> 954e2cee2c1SÁdám Kallai // add x13, x12, w13, sxth #2 955e2cee2c1SÁdám Kallai // br x13 956*1b4bd4e1SMaksim Panchenko LLVM_DEBUG(dbgs() << "BOLT-DEBUG: failed to match indirect branch: " 957*1b4bd4e1SMaksim Panchenko "nop/adr instead of adrp/add\n"); 958e2cee2c1SÁdám Kallai return false; 959e2cee2c1SÁdám Kallai } 960e2cee2c1SÁdám Kallai 961*1b4bd4e1SMaksim Panchenko if (DefJTBaseAdd->getOpcode() != AArch64::ADDXri) { 962*1b4bd4e1SMaksim Panchenko LLVM_DEBUG(dbgs() << "BOLT-DEBUG: failed to match jump table base " 963*1b4bd4e1SMaksim Panchenko "address pattern! (1)\n"); 964*1b4bd4e1SMaksim Panchenko return false; 965*1b4bd4e1SMaksim Panchenko } 966a34c753fSRafael Auler 967a34c753fSRafael Auler if (DefJTBaseAdd->getOperand(2).isImm()) 968a34c753fSRafael Auler Offset = DefJTBaseAdd->getOperand(2).getImm(); 969a34c753fSRafael Auler SmallVector<MCInst *, 4> &UsesJTBaseAdd = UDChain[DefJTBaseAdd]; 970a34c753fSRafael Auler const MCInst *DefJTBasePage = UsesJTBaseAdd[1]; 971a34c753fSRafael Auler if (DefJTBasePage == nullptr || isLoadFromStack(*DefJTBasePage)) { 972a34c753fSRafael Auler return true; 973a34c753fSRafael Auler } 974*1b4bd4e1SMaksim Panchenko if (DefJTBasePage->getOpcode() != AArch64::ADRP) 975*1b4bd4e1SMaksim Panchenko return false; 976*1b4bd4e1SMaksim Panchenko 977a34c753fSRafael Auler if (DefJTBasePage->getOperand(1).isExpr()) 978a34c753fSRafael Auler JumpTable = DefJTBasePage->getOperand(1).getExpr(); 979a34c753fSRafael Auler return true; 980a34c753fSRafael Auler } 981a34c753fSRafael Auler 982a34c753fSRafael Auler DenseMap<const MCInst *, SmallVector<MCInst *, 4>> 98340c2e0faSMaksim Panchenko computeLocalUDChain(const MCInst *CurInstr, InstructionIterator Begin, 984a34c753fSRafael Auler InstructionIterator End) const { 985a34c753fSRafael Auler DenseMap<int, MCInst *> RegAliasTable; 986a34c753fSRafael Auler DenseMap<const MCInst *, SmallVector<MCInst *, 4>> Uses; 987a34c753fSRafael Auler 988a34c753fSRafael Auler auto addInstrOperands = [&](const MCInst &Instr) { 989a34c753fSRafael Auler // Update Uses table 9908cb7a873SAmir Ayupov for (const MCOperand &Operand : MCPlus::primeOperands(Instr)) { 9918cb7a873SAmir Ayupov if (!Operand.isReg()) 992a34c753fSRafael Auler continue; 9938cb7a873SAmir Ayupov unsigned Reg = Operand.getReg(); 994a34c753fSRafael Auler MCInst *AliasInst = RegAliasTable[Reg]; 995a34c753fSRafael Auler Uses[&Instr].push_back(AliasInst); 996a34c753fSRafael Auler LLVM_DEBUG({ 997a34c753fSRafael Auler dbgs() << "Adding reg operand " << Reg << " refs "; 998a34c753fSRafael Auler if (AliasInst != nullptr) 999a34c753fSRafael Auler AliasInst->dump(); 1000a34c753fSRafael Auler else 1001a34c753fSRafael Auler dbgs() << "\n"; 1002a34c753fSRafael Auler }); 1003a34c753fSRafael Auler } 1004a34c753fSRafael Auler }; 1005a34c753fSRafael Auler 1006a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "computeLocalUDChain\n"); 1007a34c753fSRafael Auler bool TerminatorSeen = false; 1008a34c753fSRafael Auler for (auto II = Begin; II != End; ++II) { 1009a34c753fSRafael Auler MCInst &Instr = *II; 1010a34c753fSRafael Auler // Ignore nops and CFIs 1011a34c753fSRafael Auler if (isPseudo(Instr) || isNoop(Instr)) 1012a34c753fSRafael Auler continue; 1013a34c753fSRafael Auler if (TerminatorSeen) { 1014a34c753fSRafael Auler RegAliasTable.clear(); 1015a34c753fSRafael Auler Uses.clear(); 1016a34c753fSRafael Auler } 1017a34c753fSRafael Auler 1018a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Now updating for:\n "); 1019a34c753fSRafael Auler LLVM_DEBUG(Instr.dump()); 1020a34c753fSRafael Auler addInstrOperands(Instr); 1021a34c753fSRafael Auler 1022a34c753fSRafael Auler BitVector Regs = BitVector(RegInfo->getNumRegs(), false); 1023a34c753fSRafael Auler getWrittenRegs(Instr, Regs); 1024a34c753fSRafael Auler 1025a34c753fSRafael Auler // Update register definitions after this point 1026d63c5a38SAmir Ayupov for (int Idx : Regs.set_bits()) { 1027a34c753fSRafael Auler RegAliasTable[Idx] = &Instr; 1028a34c753fSRafael Auler LLVM_DEBUG(dbgs() << "Setting reg " << Idx 1029a34c753fSRafael Auler << " def to current instr.\n"); 1030a34c753fSRafael Auler } 1031a34c753fSRafael Auler 1032a34c753fSRafael Auler TerminatorSeen = isTerminator(Instr); 1033a34c753fSRafael Auler } 1034a34c753fSRafael Auler 1035a34c753fSRafael Auler // Process the last instruction, which is not currently added into the 1036a34c753fSRafael Auler // instruction stream 103789ceb779SAmir Ayupov if (CurInstr) 1038a34c753fSRafael Auler addInstrOperands(*CurInstr); 103989ceb779SAmir Ayupov 1040a34c753fSRafael Auler return Uses; 1041a34c753fSRafael Auler } 1042a34c753fSRafael Auler 10433023b15fSAmir Ayupov IndirectBranchType 10443023b15fSAmir Ayupov analyzeIndirectBranch(MCInst &Instruction, InstructionIterator Begin, 10453023b15fSAmir Ayupov InstructionIterator End, const unsigned PtrSize, 10463023b15fSAmir Ayupov MCInst *&MemLocInstrOut, unsigned &BaseRegNumOut, 10478aab58baSMaksim Panchenko unsigned &IndexRegNumOut, int64_t &DispValueOut, 10483023b15fSAmir Ayupov const MCExpr *&DispExprOut, MCInst *&PCRelBaseOut, 10493023b15fSAmir Ayupov MCInst *&FixedEntryLoadInstr) const override { 1050a34c753fSRafael Auler MemLocInstrOut = nullptr; 1051a34c753fSRafael Auler BaseRegNumOut = AArch64::NoRegister; 1052a34c753fSRafael Auler IndexRegNumOut = AArch64::NoRegister; 1053a34c753fSRafael Auler DispValueOut = 0; 1054a34c753fSRafael Auler DispExprOut = nullptr; 10553023b15fSAmir Ayupov FixedEntryLoadInstr = nullptr; 1056a34c753fSRafael Auler 1057a34c753fSRafael Auler // An instruction referencing memory used by jump instruction (directly or 1058a34c753fSRafael Auler // via register). This location could be an array of function pointers 1059a34c753fSRafael Auler // in case of indirect tail call, or a jump table. 1060a34c753fSRafael Auler MCInst *MemLocInstr = nullptr; 1061a34c753fSRafael Auler 1062a34c753fSRafael Auler // Analyze the memory location. 1063a34c753fSRafael Auler int64_t ScaleValue, DispValue; 1064a34c753fSRafael Auler const MCExpr *DispExpr; 1065a34c753fSRafael Auler 1066a34c753fSRafael Auler DenseMap<const MCInst *, SmallVector<llvm::MCInst *, 4>> UDChain = 1067a34c753fSRafael Auler computeLocalUDChain(&Instruction, Begin, End); 1068a34c753fSRafael Auler MCInst *PCRelBase; 1069a34c753fSRafael Auler if (!analyzeIndirectBranchFragment(Instruction, UDChain, DispExpr, 107089ceb779SAmir Ayupov DispValue, ScaleValue, PCRelBase)) 1071a34c753fSRafael Auler return IndirectBranchType::UNKNOWN; 1072a34c753fSRafael Auler 1073a34c753fSRafael Auler MemLocInstrOut = MemLocInstr; 1074a34c753fSRafael Auler DispValueOut = DispValue; 1075a34c753fSRafael Auler DispExprOut = DispExpr; 1076a34c753fSRafael Auler PCRelBaseOut = PCRelBase; 1077a34c753fSRafael Auler return IndirectBranchType::POSSIBLE_PIC_JUMP_TABLE; 1078a34c753fSRafael Auler } 1079a34c753fSRafael Auler 108000b6efc8SVladislav Khmelevsky /// Matches PLT entry pattern and returns the associated GOT entry address. 108100b6efc8SVladislav Khmelevsky /// Typical PLT entry looks like the following: 108200b6efc8SVladislav Khmelevsky /// 108300b6efc8SVladislav Khmelevsky /// adrp x16, 230000 108400b6efc8SVladislav Khmelevsky /// ldr x17, [x16, #3040] 108500b6efc8SVladislav Khmelevsky /// add x16, x16, #0xbe0 108600b6efc8SVladislav Khmelevsky /// br x17 108700b6efc8SVladislav Khmelevsky /// 1088888742a1SVladislav Khmelevsky /// The other type of trampolines are located in .plt.got, that are used for 1089888742a1SVladislav Khmelevsky /// non-lazy bindings so doesn't use x16 arg to transfer .got entry address: 1090888742a1SVladislav Khmelevsky /// 1091888742a1SVladislav Khmelevsky /// adrp x16, 230000 1092888742a1SVladislav Khmelevsky /// ldr x17, [x16, #3040] 1093888742a1SVladislav Khmelevsky /// br x17 1094888742a1SVladislav Khmelevsky /// nop 1095888742a1SVladislav Khmelevsky /// 109600b6efc8SVladislav Khmelevsky uint64_t analyzePLTEntry(MCInst &Instruction, InstructionIterator Begin, 109700b6efc8SVladislav Khmelevsky InstructionIterator End, 109800b6efc8SVladislav Khmelevsky uint64_t BeginPC) const override { 109900b6efc8SVladislav Khmelevsky // Check branch instruction 110000b6efc8SVladislav Khmelevsky MCInst *Branch = &Instruction; 110100b6efc8SVladislav Khmelevsky assert(Branch->getOpcode() == AArch64::BR && "Unexpected opcode"); 110200b6efc8SVladislav Khmelevsky 110300b6efc8SVladislav Khmelevsky DenseMap<const MCInst *, SmallVector<llvm::MCInst *, 4>> UDChain = 110400b6efc8SVladislav Khmelevsky computeLocalUDChain(Branch, Begin, End); 110500b6efc8SVladislav Khmelevsky 110600b6efc8SVladislav Khmelevsky // Match ldr instruction 110700b6efc8SVladislav Khmelevsky SmallVector<MCInst *, 4> &BranchUses = UDChain[Branch]; 110800b6efc8SVladislav Khmelevsky if (BranchUses.size() < 1 || BranchUses[0] == nullptr) 110900b6efc8SVladislav Khmelevsky return 0; 111000b6efc8SVladislav Khmelevsky 111100b6efc8SVladislav Khmelevsky // Check ldr instruction 111200b6efc8SVladislav Khmelevsky const MCInst *Ldr = BranchUses[0]; 111300b6efc8SVladislav Khmelevsky if (Ldr->getOpcode() != AArch64::LDRXui) 111400b6efc8SVladislav Khmelevsky return 0; 111500b6efc8SVladislav Khmelevsky 111600b6efc8SVladislav Khmelevsky // Get ldr value 111700b6efc8SVladislav Khmelevsky const unsigned ScaleLdr = 8; // LDRX operates on 8 bytes segments 111800b6efc8SVladislav Khmelevsky assert(Ldr->getOperand(2).isImm() && "Unexpected ldr operand"); 111900b6efc8SVladislav Khmelevsky const uint64_t Offset = Ldr->getOperand(2).getImm() * ScaleLdr; 112000b6efc8SVladislav Khmelevsky 112100b6efc8SVladislav Khmelevsky // Match adrp instruction 112200b6efc8SVladislav Khmelevsky SmallVector<MCInst *, 4> &LdrUses = UDChain[Ldr]; 112300b6efc8SVladislav Khmelevsky if (LdrUses.size() < 2 || LdrUses[1] == nullptr) 112400b6efc8SVladislav Khmelevsky return 0; 112500b6efc8SVladislav Khmelevsky 112600b6efc8SVladislav Khmelevsky // Check adrp instruction 112700b6efc8SVladislav Khmelevsky MCInst *Adrp = LdrUses[1]; 112800b6efc8SVladislav Khmelevsky if (Adrp->getOpcode() != AArch64::ADRP) 112900b6efc8SVladislav Khmelevsky return 0; 113000b6efc8SVladislav Khmelevsky 113100b6efc8SVladislav Khmelevsky // Get adrp instruction PC 113200b6efc8SVladislav Khmelevsky const unsigned InstSize = 4; 113300b6efc8SVladislav Khmelevsky uint64_t AdrpPC = BeginPC; 113400b6efc8SVladislav Khmelevsky for (InstructionIterator It = Begin; It != End; ++It) { 113500b6efc8SVladislav Khmelevsky if (&(*It) == Adrp) 113600b6efc8SVladislav Khmelevsky break; 113700b6efc8SVladislav Khmelevsky AdrpPC += InstSize; 113800b6efc8SVladislav Khmelevsky } 113900b6efc8SVladislav Khmelevsky 114000b6efc8SVladislav Khmelevsky // Get adrp value 114100b6efc8SVladislav Khmelevsky uint64_t Base; 114200b6efc8SVladislav Khmelevsky assert(Adrp->getOperand(1).isImm() && "Unexpected adrp operand"); 114300b6efc8SVladislav Khmelevsky bool Ret = evaluateMemOperandTarget(*Adrp, Base, AdrpPC, InstSize); 114400b6efc8SVladislav Khmelevsky assert(Ret && "Failed to evaluate adrp"); 1145139744acSAmir Ayupov (void)Ret; 114600b6efc8SVladislav Khmelevsky 114700b6efc8SVladislav Khmelevsky return Base + Offset; 114800b6efc8SVladislav Khmelevsky } 114900b6efc8SVladislav Khmelevsky 1150a34c753fSRafael Auler unsigned getInvertedBranchOpcode(unsigned Opcode) const { 1151a34c753fSRafael Auler switch (Opcode) { 1152a34c753fSRafael Auler default: 1153a34c753fSRafael Auler llvm_unreachable("Failed to invert branch opcode"); 1154a34c753fSRafael Auler return Opcode; 1155a34c753fSRafael Auler case AArch64::TBZW: return AArch64::TBNZW; 1156a34c753fSRafael Auler case AArch64::TBZX: return AArch64::TBNZX; 1157a34c753fSRafael Auler case AArch64::TBNZW: return AArch64::TBZW; 1158a34c753fSRafael Auler case AArch64::TBNZX: return AArch64::TBZX; 1159a34c753fSRafael Auler case AArch64::CBZW: return AArch64::CBNZW; 1160a34c753fSRafael Auler case AArch64::CBZX: return AArch64::CBNZX; 1161a34c753fSRafael Auler case AArch64::CBNZW: return AArch64::CBZW; 1162a34c753fSRafael Auler case AArch64::CBNZX: return AArch64::CBZX; 1163a34c753fSRafael Auler } 1164a34c753fSRafael Auler } 1165a34c753fSRafael Auler 1166a34c753fSRafael Auler unsigned getCondCode(const MCInst &Inst) const override { 1167a34c753fSRafael Auler // AArch64 does not use conditional codes, so we just return the opcode 1168a34c753fSRafael Auler // of the conditional branch here. 1169a34c753fSRafael Auler return Inst.getOpcode(); 1170a34c753fSRafael Auler } 1171a34c753fSRafael Auler 1172a34c753fSRafael Auler unsigned getCanonicalBranchCondCode(unsigned Opcode) const override { 1173a34c753fSRafael Auler switch (Opcode) { 1174a34c753fSRafael Auler default: 1175a34c753fSRafael Auler return Opcode; 1176a34c753fSRafael Auler case AArch64::TBNZW: return AArch64::TBZW; 1177a34c753fSRafael Auler case AArch64::TBNZX: return AArch64::TBZX; 1178a34c753fSRafael Auler case AArch64::CBNZW: return AArch64::CBZW; 1179a34c753fSRafael Auler case AArch64::CBNZX: return AArch64::CBZX; 1180a34c753fSRafael Auler } 1181a34c753fSRafael Auler } 1182a34c753fSRafael Auler 11833fefb3c5SNathan Sidwell void reverseBranchCondition(MCInst &Inst, const MCSymbol *TBB, 1184a34c753fSRafael Auler MCContext *Ctx) const override { 1185a34c753fSRafael Auler if (isTB(Inst) || isCB(Inst)) { 1186a34c753fSRafael Auler Inst.setOpcode(getInvertedBranchOpcode(Inst.getOpcode())); 1187a34c753fSRafael Auler assert(Inst.getOpcode() != 0 && "Invalid branch instruction"); 1188a34c753fSRafael Auler } else if (Inst.getOpcode() == AArch64::Bcc) { 1189a34c753fSRafael Auler Inst.getOperand(0).setImm(AArch64CC::getInvertedCondCode( 1190a34c753fSRafael Auler static_cast<AArch64CC::CondCode>(Inst.getOperand(0).getImm()))); 1191a34c753fSRafael Auler assert(Inst.getOperand(0).getImm() != AArch64CC::AL && 1192a34c753fSRafael Auler Inst.getOperand(0).getImm() != AArch64CC::NV && 1193a34c753fSRafael Auler "Can't reverse ALWAYS cond code"); 1194a34c753fSRafael Auler } else { 1195a34c753fSRafael Auler LLVM_DEBUG(Inst.dump()); 1196a34c753fSRafael Auler llvm_unreachable("Unrecognized branch instruction"); 1197a34c753fSRafael Auler } 11983fefb3c5SNathan Sidwell replaceBranchTarget(Inst, TBB, Ctx); 1199a34c753fSRafael Auler } 1200a34c753fSRafael Auler 1201a34c753fSRafael Auler int getPCRelEncodingSize(const MCInst &Inst) const override { 1202a34c753fSRafael Auler switch (Inst.getOpcode()) { 1203a34c753fSRafael Auler default: 1204a34c753fSRafael Auler llvm_unreachable("Failed to get pcrel encoding size"); 1205a34c753fSRafael Auler return 0; 1206a34c753fSRafael Auler case AArch64::TBZW: return 16; 1207a34c753fSRafael Auler case AArch64::TBZX: return 16; 1208a34c753fSRafael Auler case AArch64::TBNZW: return 16; 1209a34c753fSRafael Auler case AArch64::TBNZX: return 16; 1210a34c753fSRafael Auler case AArch64::CBZW: return 21; 1211a34c753fSRafael Auler case AArch64::CBZX: return 21; 1212a34c753fSRafael Auler case AArch64::CBNZW: return 21; 1213a34c753fSRafael Auler case AArch64::CBNZX: return 21; 1214a34c753fSRafael Auler case AArch64::B: return 28; 1215a34c753fSRafael Auler case AArch64::BL: return 28; 1216a34c753fSRafael Auler case AArch64::Bcc: return 21; 1217a34c753fSRafael Auler } 1218a34c753fSRafael Auler } 1219a34c753fSRafael Auler 122040c2e0faSMaksim Panchenko int getShortJmpEncodingSize() const override { return 33; } 1221a34c753fSRafael Auler 122240c2e0faSMaksim Panchenko int getUncondBranchEncodingSize() const override { return 28; } 1223a34c753fSRafael Auler 12246e4c2305SElvina Yakubova InstructionListType createCmpJE(MCPhysReg RegNo, int64_t Imm, 12256e4c2305SElvina Yakubova const MCSymbol *Target, 12266e4c2305SElvina Yakubova MCContext *Ctx) const override { 12276e4c2305SElvina Yakubova InstructionListType Code; 12286e4c2305SElvina Yakubova Code.emplace_back(MCInstBuilder(AArch64::SUBSXri) 12296e4c2305SElvina Yakubova .addReg(RegNo) 12306e4c2305SElvina Yakubova .addReg(RegNo) 12316e4c2305SElvina Yakubova .addImm(Imm) 12326e4c2305SElvina Yakubova .addImm(0)); 12336e4c2305SElvina Yakubova Code.emplace_back(MCInstBuilder(AArch64::Bcc) 12346e4c2305SElvina Yakubova .addImm(Imm) 12356e4c2305SElvina Yakubova .addExpr(MCSymbolRefExpr::create( 12366e4c2305SElvina Yakubova Target, MCSymbolRefExpr::VK_None, *Ctx))); 12376e4c2305SElvina Yakubova return Code; 12386e4c2305SElvina Yakubova } 12396e4c2305SElvina Yakubova 1240bba790dbSMaksim Panchenko void createTailCall(MCInst &Inst, const MCSymbol *Target, 1241a34c753fSRafael Auler MCContext *Ctx) override { 12426e4c2305SElvina Yakubova return createDirectCall(Inst, Target, Ctx, /*IsTailCall*/ true); 1243a34c753fSRafael Auler } 1244a34c753fSRafael Auler 124569706eafSMaksim Panchenko void createLongTailCall(InstructionListType &Seq, const MCSymbol *Target, 1246a34c753fSRafael Auler MCContext *Ctx) override { 1247a34c753fSRafael Auler createShortJmp(Seq, Target, Ctx, /*IsTailCall*/ true); 1248a34c753fSRafael Auler } 1249a34c753fSRafael Auler 1250bba790dbSMaksim Panchenko void createTrap(MCInst &Inst) const override { 125119fb5a21SVladislav Khmelevsky Inst.clear(); 125219fb5a21SVladislav Khmelevsky Inst.setOpcode(AArch64::BRK); 125319fb5a21SVladislav Khmelevsky Inst.addOperand(MCOperand::createImm(1)); 125419fb5a21SVladislav Khmelevsky } 125519fb5a21SVladislav Khmelevsky 1256a34c753fSRafael Auler bool convertJmpToTailCall(MCInst &Inst) override { 1257a34c753fSRafael Auler setTailCall(Inst); 1258a34c753fSRafael Auler return true; 1259a34c753fSRafael Auler } 1260a34c753fSRafael Auler 1261a34c753fSRafael Auler bool convertTailCallToJmp(MCInst &Inst) override { 1262a34c753fSRafael Auler removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall); 1263a9cd49d5SAmir Ayupov clearOffset(Inst); 1264a34c753fSRafael Auler if (getConditionalTailCall(Inst)) 1265a34c753fSRafael Auler unsetConditionalTailCall(Inst); 1266a34c753fSRafael Auler return true; 1267a34c753fSRafael Auler } 1268a34c753fSRafael Auler 126934c6c5e7SMaksim Panchenko InstructionListType createIndirectPLTCall(MCInst &&DirectCall, 1270a13bc971SPaschalis Mpeis const MCSymbol *TargetLocation, 1271a13bc971SPaschalis Mpeis MCContext *Ctx) override { 1272a13bc971SPaschalis Mpeis const bool IsTailCall = isTailCall(DirectCall); 1273a13bc971SPaschalis Mpeis assert((DirectCall.getOpcode() == AArch64::BL || 1274a13bc971SPaschalis Mpeis (DirectCall.getOpcode() == AArch64::B && IsTailCall)) && 1275a13bc971SPaschalis Mpeis "64-bit direct (tail) call instruction expected"); 1276a13bc971SPaschalis Mpeis 1277a13bc971SPaschalis Mpeis InstructionListType Code; 1278a13bc971SPaschalis Mpeis // Code sequence for indirect plt call: 1279a13bc971SPaschalis Mpeis // adrp x16 <symbol> 1280a13bc971SPaschalis Mpeis // ldr x17, [x16, #<offset>] 1281a13bc971SPaschalis Mpeis // blr x17 ; or 'br' for tail calls 1282a13bc971SPaschalis Mpeis 1283a13bc971SPaschalis Mpeis MCInst InstAdrp; 1284a13bc971SPaschalis Mpeis InstAdrp.setOpcode(AArch64::ADRP); 1285a13bc971SPaschalis Mpeis InstAdrp.addOperand(MCOperand::createReg(AArch64::X16)); 1286a13bc971SPaschalis Mpeis InstAdrp.addOperand(MCOperand::createImm(0)); 1287a13bc971SPaschalis Mpeis setOperandToSymbolRef(InstAdrp, /* OpNum */ 1, TargetLocation, 1288a13bc971SPaschalis Mpeis /* Addend */ 0, Ctx, ELF::R_AARCH64_ADR_GOT_PAGE); 1289a13bc971SPaschalis Mpeis Code.emplace_back(InstAdrp); 1290a13bc971SPaschalis Mpeis 1291a13bc971SPaschalis Mpeis MCInst InstLoad; 1292a13bc971SPaschalis Mpeis InstLoad.setOpcode(AArch64::LDRXui); 1293a13bc971SPaschalis Mpeis InstLoad.addOperand(MCOperand::createReg(AArch64::X17)); 1294a13bc971SPaschalis Mpeis InstLoad.addOperand(MCOperand::createReg(AArch64::X16)); 1295a13bc971SPaschalis Mpeis InstLoad.addOperand(MCOperand::createImm(0)); 1296a13bc971SPaschalis Mpeis setOperandToSymbolRef(InstLoad, /* OpNum */ 2, TargetLocation, 1297a13bc971SPaschalis Mpeis /* Addend */ 0, Ctx, ELF::R_AARCH64_LD64_GOT_LO12_NC); 1298a13bc971SPaschalis Mpeis Code.emplace_back(InstLoad); 1299a13bc971SPaschalis Mpeis 1300a13bc971SPaschalis Mpeis MCInst InstCall; 1301a13bc971SPaschalis Mpeis InstCall.setOpcode(IsTailCall ? AArch64::BR : AArch64::BLR); 1302a13bc971SPaschalis Mpeis InstCall.addOperand(MCOperand::createReg(AArch64::X17)); 130334c6c5e7SMaksim Panchenko moveAnnotations(std::move(DirectCall), InstCall); 1304a13bc971SPaschalis Mpeis Code.emplace_back(InstCall); 1305a13bc971SPaschalis Mpeis 1306a13bc971SPaschalis Mpeis return Code; 1307a13bc971SPaschalis Mpeis } 1308a13bc971SPaschalis Mpeis 1309a34c753fSRafael Auler bool lowerTailCall(MCInst &Inst) override { 1310a34c753fSRafael Auler removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall); 1311a34c753fSRafael Auler if (getConditionalTailCall(Inst)) 1312a34c753fSRafael Auler unsetConditionalTailCall(Inst); 1313a34c753fSRafael Auler return true; 1314a34c753fSRafael Auler } 1315a34c753fSRafael Auler 1316a34c753fSRafael Auler bool isNoop(const MCInst &Inst) const override { 1317a34c753fSRafael Auler return Inst.getOpcode() == AArch64::HINT && 1318a34c753fSRafael Auler Inst.getOperand(0).getImm() == 0; 1319a34c753fSRafael Auler } 1320a34c753fSRafael Auler 1321bba790dbSMaksim Panchenko void createNoop(MCInst &Inst) const override { 1322a34c753fSRafael Auler Inst.setOpcode(AArch64::HINT); 1323a34c753fSRafael Auler Inst.clear(); 1324a34c753fSRafael Auler Inst.addOperand(MCOperand::createImm(0)); 1325a34c753fSRafael Auler } 1326a34c753fSRafael Auler 1327ad599c25SAlexey Moksyakov bool isStorePair(const MCInst &Inst) const { 1328ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 1329ad599c25SAlexey Moksyakov 1330ad599c25SAlexey Moksyakov auto isStorePairImmOffset = [&]() { 1331ad599c25SAlexey Moksyakov switch (opcode) { 1332ad599c25SAlexey Moksyakov case AArch64::STPWi: 1333ad599c25SAlexey Moksyakov case AArch64::STPXi: 1334ad599c25SAlexey Moksyakov case AArch64::STPSi: 1335ad599c25SAlexey Moksyakov case AArch64::STPDi: 1336ad599c25SAlexey Moksyakov case AArch64::STPQi: 1337ad599c25SAlexey Moksyakov case AArch64::STNPWi: 1338ad599c25SAlexey Moksyakov case AArch64::STNPXi: 1339ad599c25SAlexey Moksyakov case AArch64::STNPSi: 1340ad599c25SAlexey Moksyakov case AArch64::STNPDi: 1341ad599c25SAlexey Moksyakov case AArch64::STNPQi: 1342ad599c25SAlexey Moksyakov return true; 1343ad599c25SAlexey Moksyakov default: 1344ad599c25SAlexey Moksyakov break; 1345ad599c25SAlexey Moksyakov } 1346ad599c25SAlexey Moksyakov 1347ad599c25SAlexey Moksyakov return false; 1348ad599c25SAlexey Moksyakov }; 1349ad599c25SAlexey Moksyakov 1350ad599c25SAlexey Moksyakov auto isStorePairPostIndex = [&]() { 1351ad599c25SAlexey Moksyakov switch (opcode) { 1352ad599c25SAlexey Moksyakov case AArch64::STPWpost: 1353ad599c25SAlexey Moksyakov case AArch64::STPXpost: 1354ad599c25SAlexey Moksyakov case AArch64::STPSpost: 1355ad599c25SAlexey Moksyakov case AArch64::STPDpost: 1356ad599c25SAlexey Moksyakov case AArch64::STPQpost: 1357ad599c25SAlexey Moksyakov return true; 1358ad599c25SAlexey Moksyakov default: 1359ad599c25SAlexey Moksyakov break; 1360ad599c25SAlexey Moksyakov } 1361ad599c25SAlexey Moksyakov 1362ad599c25SAlexey Moksyakov return false; 1363ad599c25SAlexey Moksyakov }; 1364ad599c25SAlexey Moksyakov 1365ad599c25SAlexey Moksyakov auto isStorePairPreIndex = [&]() { 1366ad599c25SAlexey Moksyakov switch (opcode) { 1367ad599c25SAlexey Moksyakov case AArch64::STPWpre: 1368ad599c25SAlexey Moksyakov case AArch64::STPXpre: 1369ad599c25SAlexey Moksyakov case AArch64::STPSpre: 1370ad599c25SAlexey Moksyakov case AArch64::STPDpre: 1371ad599c25SAlexey Moksyakov case AArch64::STPQpre: 1372ad599c25SAlexey Moksyakov return true; 1373ad599c25SAlexey Moksyakov default: 1374ad599c25SAlexey Moksyakov break; 1375ad599c25SAlexey Moksyakov } 1376ad599c25SAlexey Moksyakov 1377ad599c25SAlexey Moksyakov return false; 1378ad599c25SAlexey Moksyakov }; 1379ad599c25SAlexey Moksyakov 1380ad599c25SAlexey Moksyakov return isStorePairImmOffset() || isStorePairPostIndex() || 1381ad599c25SAlexey Moksyakov isStorePairPreIndex(); 1382ad599c25SAlexey Moksyakov } 1383ad599c25SAlexey Moksyakov 1384ad599c25SAlexey Moksyakov bool isStoreReg(const MCInst &Inst) const { 1385ad599c25SAlexey Moksyakov const unsigned opcode = Inst.getOpcode(); 1386ad599c25SAlexey Moksyakov 1387ad599c25SAlexey Moksyakov auto isStoreRegUnscaleImm = [&]() { 1388ad599c25SAlexey Moksyakov switch (opcode) { 1389ad599c25SAlexey Moksyakov case AArch64::STURBi: 1390ad599c25SAlexey Moksyakov case AArch64::STURBBi: 1391ad599c25SAlexey Moksyakov case AArch64::STURHi: 1392ad599c25SAlexey Moksyakov case AArch64::STURHHi: 1393ad599c25SAlexey Moksyakov case AArch64::STURWi: 1394ad599c25SAlexey Moksyakov case AArch64::STURXi: 1395ad599c25SAlexey Moksyakov case AArch64::STURSi: 1396ad599c25SAlexey Moksyakov case AArch64::STURDi: 1397ad599c25SAlexey Moksyakov case AArch64::STURQi: 1398ad599c25SAlexey Moksyakov return true; 1399ad599c25SAlexey Moksyakov default: 1400ad599c25SAlexey Moksyakov break; 1401ad599c25SAlexey Moksyakov } 1402ad599c25SAlexey Moksyakov 1403ad599c25SAlexey Moksyakov return false; 1404ad599c25SAlexey Moksyakov }; 1405ad599c25SAlexey Moksyakov 1406ad599c25SAlexey Moksyakov auto isStoreRegScaledImm = [&]() { 1407ad599c25SAlexey Moksyakov switch (opcode) { 1408ad599c25SAlexey Moksyakov case AArch64::STRBui: 1409ad599c25SAlexey Moksyakov case AArch64::STRBBui: 1410ad599c25SAlexey Moksyakov case AArch64::STRHui: 1411ad599c25SAlexey Moksyakov case AArch64::STRHHui: 1412ad599c25SAlexey Moksyakov case AArch64::STRWui: 1413ad599c25SAlexey Moksyakov case AArch64::STRXui: 1414ad599c25SAlexey Moksyakov case AArch64::STRSui: 1415ad599c25SAlexey Moksyakov case AArch64::STRDui: 1416ad599c25SAlexey Moksyakov case AArch64::STRQui: 1417ad599c25SAlexey Moksyakov return true; 1418ad599c25SAlexey Moksyakov default: 1419ad599c25SAlexey Moksyakov break; 1420ad599c25SAlexey Moksyakov } 1421ad599c25SAlexey Moksyakov 1422ad599c25SAlexey Moksyakov return false; 1423ad599c25SAlexey Moksyakov }; 1424ad599c25SAlexey Moksyakov 1425ad599c25SAlexey Moksyakov auto isStoreRegImmPostIndexed = [&]() { 1426ad599c25SAlexey Moksyakov switch (opcode) { 1427ad599c25SAlexey Moksyakov case AArch64::STRBpost: 1428ad599c25SAlexey Moksyakov case AArch64::STRBBpost: 1429ad599c25SAlexey Moksyakov case AArch64::STRHpost: 1430ad599c25SAlexey Moksyakov case AArch64::STRHHpost: 1431ad599c25SAlexey Moksyakov case AArch64::STRWpost: 1432ad599c25SAlexey Moksyakov case AArch64::STRXpost: 1433ad599c25SAlexey Moksyakov case AArch64::STRSpost: 1434ad599c25SAlexey Moksyakov case AArch64::STRDpost: 1435ad599c25SAlexey Moksyakov case AArch64::STRQpost: 1436ad599c25SAlexey Moksyakov return true; 1437ad599c25SAlexey Moksyakov default: 1438ad599c25SAlexey Moksyakov break; 1439ad599c25SAlexey Moksyakov } 1440ad599c25SAlexey Moksyakov 1441ad599c25SAlexey Moksyakov return false; 1442ad599c25SAlexey Moksyakov }; 1443ad599c25SAlexey Moksyakov 1444ad599c25SAlexey Moksyakov auto isStoreRegImmPreIndexed = [&]() { 1445ad599c25SAlexey Moksyakov switch (opcode) { 1446ad599c25SAlexey Moksyakov case AArch64::STRBpre: 1447ad599c25SAlexey Moksyakov case AArch64::STRBBpre: 1448ad599c25SAlexey Moksyakov case AArch64::STRHpre: 1449ad599c25SAlexey Moksyakov case AArch64::STRHHpre: 1450ad599c25SAlexey Moksyakov case AArch64::STRWpre: 1451ad599c25SAlexey Moksyakov case AArch64::STRXpre: 1452ad599c25SAlexey Moksyakov case AArch64::STRSpre: 1453ad599c25SAlexey Moksyakov case AArch64::STRDpre: 1454ad599c25SAlexey Moksyakov case AArch64::STRQpre: 1455ad599c25SAlexey Moksyakov return true; 1456ad599c25SAlexey Moksyakov default: 1457ad599c25SAlexey Moksyakov break; 1458ad599c25SAlexey Moksyakov } 1459ad599c25SAlexey Moksyakov 1460ad599c25SAlexey Moksyakov return false; 1461ad599c25SAlexey Moksyakov }; 1462ad599c25SAlexey Moksyakov 1463ad599c25SAlexey Moksyakov auto isStoreRegUnscaleUnpriv = [&]() { 1464ad599c25SAlexey Moksyakov switch (opcode) { 1465ad599c25SAlexey Moksyakov case AArch64::STTRBi: 1466ad599c25SAlexey Moksyakov case AArch64::STTRHi: 1467ad599c25SAlexey Moksyakov case AArch64::STTRWi: 1468ad599c25SAlexey Moksyakov case AArch64::STTRXi: 1469ad599c25SAlexey Moksyakov return true; 1470ad599c25SAlexey Moksyakov default: 1471ad599c25SAlexey Moksyakov break; 1472ad599c25SAlexey Moksyakov } 1473ad599c25SAlexey Moksyakov 1474ad599c25SAlexey Moksyakov return false; 1475ad599c25SAlexey Moksyakov }; 1476ad599c25SAlexey Moksyakov 1477ad599c25SAlexey Moksyakov auto isStoreRegTrunc = [&]() { 1478ad599c25SAlexey Moksyakov switch (opcode) { 1479ad599c25SAlexey Moksyakov case AArch64::STRBBroW: 1480ad599c25SAlexey Moksyakov case AArch64::STRBBroX: 1481ad599c25SAlexey Moksyakov case AArch64::STRBroW: 1482ad599c25SAlexey Moksyakov case AArch64::STRBroX: 1483ad599c25SAlexey Moksyakov case AArch64::STRDroW: 1484ad599c25SAlexey Moksyakov case AArch64::STRDroX: 1485ad599c25SAlexey Moksyakov case AArch64::STRHHroW: 1486ad599c25SAlexey Moksyakov case AArch64::STRHHroX: 1487ad599c25SAlexey Moksyakov case AArch64::STRHroW: 1488ad599c25SAlexey Moksyakov case AArch64::STRHroX: 1489ad599c25SAlexey Moksyakov case AArch64::STRQroW: 1490ad599c25SAlexey Moksyakov case AArch64::STRQroX: 1491ad599c25SAlexey Moksyakov case AArch64::STRSroW: 1492ad599c25SAlexey Moksyakov case AArch64::STRSroX: 1493ad599c25SAlexey Moksyakov case AArch64::STRWroW: 1494ad599c25SAlexey Moksyakov case AArch64::STRWroX: 1495ad599c25SAlexey Moksyakov case AArch64::STRXroW: 1496ad599c25SAlexey Moksyakov case AArch64::STRXroX: 1497ad599c25SAlexey Moksyakov return true; 1498ad599c25SAlexey Moksyakov default: 1499ad599c25SAlexey Moksyakov break; 1500ad599c25SAlexey Moksyakov } 1501ad599c25SAlexey Moksyakov 1502ad599c25SAlexey Moksyakov return false; 1503ad599c25SAlexey Moksyakov }; 1504ad599c25SAlexey Moksyakov 1505ad599c25SAlexey Moksyakov return isStoreRegUnscaleImm() || isStoreRegScaledImm() || 1506ad599c25SAlexey Moksyakov isStoreRegImmPreIndexed() || isStoreRegImmPostIndexed() || 1507ad599c25SAlexey Moksyakov isStoreRegUnscaleUnpriv() || isStoreRegTrunc(); 1508ad599c25SAlexey Moksyakov } 1509ad599c25SAlexey Moksyakov 1510ad599c25SAlexey Moksyakov bool mayStore(const MCInst &Inst) const override { 1511ad599c25SAlexey Moksyakov return isStorePair(Inst) || isStoreReg(Inst) || 1512ad599c25SAlexey Moksyakov isAArch64ExclusiveStore(Inst); 1513ad599c25SAlexey Moksyakov } 1514ad599c25SAlexey Moksyakov 1515ad599c25SAlexey Moksyakov bool isStoreToStack(const MCInst &Inst) const { 1516ad599c25SAlexey Moksyakov if (!mayStore(Inst)) 1517ad599c25SAlexey Moksyakov return false; 1518ad599c25SAlexey Moksyakov 1519ad599c25SAlexey Moksyakov for (const MCOperand &Operand : useOperands(Inst)) { 1520ad599c25SAlexey Moksyakov if (!Operand.isReg()) 1521ad599c25SAlexey Moksyakov continue; 1522ad599c25SAlexey Moksyakov 1523ad599c25SAlexey Moksyakov unsigned Reg = Operand.getReg(); 1524ad599c25SAlexey Moksyakov if (Reg == AArch64::SP || Reg == AArch64::WSP) 1525ad599c25SAlexey Moksyakov return true; 1526ad599c25SAlexey Moksyakov } 1527ad599c25SAlexey Moksyakov 1528ad599c25SAlexey Moksyakov return false; 1529ad599c25SAlexey Moksyakov } 1530a34c753fSRafael Auler 1531bba790dbSMaksim Panchenko void createDirectCall(MCInst &Inst, const MCSymbol *Target, MCContext *Ctx, 15326e4c2305SElvina Yakubova bool IsTailCall) override { 15336e4c2305SElvina Yakubova Inst.setOpcode(IsTailCall ? AArch64::B : AArch64::BL); 15346e4c2305SElvina Yakubova Inst.clear(); 15356e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createExpr(getTargetExprFor( 15366e4c2305SElvina Yakubova Inst, MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), 15376e4c2305SElvina Yakubova *Ctx, 0))); 15386e4c2305SElvina Yakubova if (IsTailCall) 15396e4c2305SElvina Yakubova convertJmpToTailCall(Inst); 15406e4c2305SElvina Yakubova } 15416e4c2305SElvina Yakubova 154240c2e0faSMaksim Panchenko bool analyzeBranch(InstructionIterator Begin, InstructionIterator End, 154340c2e0faSMaksim Panchenko const MCSymbol *&TBB, const MCSymbol *&FBB, 1544a34c753fSRafael Auler MCInst *&CondBranch, 1545a34c753fSRafael Auler MCInst *&UncondBranch) const override { 1546a34c753fSRafael Auler auto I = End; 1547a34c753fSRafael Auler 1548a34c753fSRafael Auler while (I != Begin) { 1549a34c753fSRafael Auler --I; 1550a34c753fSRafael Auler 1551a34c753fSRafael Auler // Ignore nops and CFIs 1552a34c753fSRafael Auler if (isPseudo(*I) || isNoop(*I)) 1553a34c753fSRafael Auler continue; 1554a34c753fSRafael Auler 1555a34c753fSRafael Auler // Stop when we find the first non-terminator 1556a34c753fSRafael Auler if (!isTerminator(*I) || isTailCall(*I) || !isBranch(*I)) 1557a34c753fSRafael Auler break; 1558a34c753fSRafael Auler 1559a34c753fSRafael Auler // Handle unconditional branches. 1560a34c753fSRafael Auler if (isUnconditionalBranch(*I)) { 1561a34c753fSRafael Auler // If any code was seen after this unconditional branch, we've seen 1562a34c753fSRafael Auler // unreachable code. Ignore them. 1563a34c753fSRafael Auler CondBranch = nullptr; 1564a34c753fSRafael Auler UncondBranch = &*I; 1565a34c753fSRafael Auler const MCSymbol *Sym = getTargetSymbol(*I); 1566a34c753fSRafael Auler assert(Sym != nullptr && 1567a34c753fSRafael Auler "Couldn't extract BB symbol from jump operand"); 1568a34c753fSRafael Auler TBB = Sym; 1569a34c753fSRafael Auler continue; 1570a34c753fSRafael Auler } 1571a34c753fSRafael Auler 1572a34c753fSRafael Auler // Handle conditional branches and ignore indirect branches 157389ceb779SAmir Ayupov if (isIndirectBranch(*I)) 1574a34c753fSRafael Auler return false; 1575a34c753fSRafael Auler 1576a34c753fSRafael Auler if (CondBranch == nullptr) { 1577a34c753fSRafael Auler const MCSymbol *TargetBB = getTargetSymbol(*I); 1578a34c753fSRafael Auler if (TargetBB == nullptr) { 1579a34c753fSRafael Auler // Unrecognized branch target 1580a34c753fSRafael Auler return false; 1581a34c753fSRafael Auler } 1582a34c753fSRafael Auler FBB = TBB; 1583a34c753fSRafael Auler TBB = TargetBB; 1584a34c753fSRafael Auler CondBranch = &*I; 1585a34c753fSRafael Auler continue; 1586a34c753fSRafael Auler } 1587a34c753fSRafael Auler 1588a34c753fSRafael Auler llvm_unreachable("multiple conditional branches in one BB"); 1589a34c753fSRafael Auler } 1590a34c753fSRafael Auler return true; 1591a34c753fSRafael Auler } 1592a34c753fSRafael Auler 159369706eafSMaksim Panchenko void createLongJmp(InstructionListType &Seq, const MCSymbol *Target, 1594a34c753fSRafael Auler MCContext *Ctx, bool IsTailCall) override { 1595a34c753fSRafael Auler // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call 1596a34c753fSRafael Auler // Standard for the ARM 64-bit Architecture (AArch64)". 1597a34c753fSRafael Auler // The sequence of instructions we create here is the following: 1598a34c753fSRafael Auler // movz ip0, #:abs_g3:<addr> 1599a34c753fSRafael Auler // movk ip0, #:abs_g2_nc:<addr> 1600a34c753fSRafael Auler // movk ip0, #:abs_g1_nc:<addr> 1601a34c753fSRafael Auler // movk ip0, #:abs_g0_nc:<addr> 1602a34c753fSRafael Auler // br ip0 1603a34c753fSRafael Auler MCInst Inst; 1604a34c753fSRafael Auler Inst.setOpcode(AArch64::MOVZXi); 1605a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1606a34c753fSRafael Auler Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( 1607a34c753fSRafael Auler MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), 1608a34c753fSRafael Auler AArch64MCExpr::VK_ABS_G3, *Ctx))); 1609a34c753fSRafael Auler Inst.addOperand(MCOperand::createImm(0x30)); 1610a34c753fSRafael Auler Seq.emplace_back(Inst); 1611a34c753fSRafael Auler 1612a34c753fSRafael Auler Inst.clear(); 1613a34c753fSRafael Auler Inst.setOpcode(AArch64::MOVKXi); 1614a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1615a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1616a34c753fSRafael Auler Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( 1617a34c753fSRafael Auler MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), 1618a34c753fSRafael Auler AArch64MCExpr::VK_ABS_G2_NC, *Ctx))); 1619a34c753fSRafael Auler Inst.addOperand(MCOperand::createImm(0x20)); 1620a34c753fSRafael Auler Seq.emplace_back(Inst); 1621a34c753fSRafael Auler 1622a34c753fSRafael Auler Inst.clear(); 1623a34c753fSRafael Auler Inst.setOpcode(AArch64::MOVKXi); 1624a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1625a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1626a34c753fSRafael Auler Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( 1627a34c753fSRafael Auler MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), 1628a34c753fSRafael Auler AArch64MCExpr::VK_ABS_G1_NC, *Ctx))); 1629a34c753fSRafael Auler Inst.addOperand(MCOperand::createImm(0x10)); 1630a34c753fSRafael Auler Seq.emplace_back(Inst); 1631a34c753fSRafael Auler 1632a34c753fSRafael Auler Inst.clear(); 1633a34c753fSRafael Auler Inst.setOpcode(AArch64::MOVKXi); 1634a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1635a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1636a34c753fSRafael Auler Inst.addOperand(MCOperand::createExpr(AArch64MCExpr::create( 1637a34c753fSRafael Auler MCSymbolRefExpr::create(Target, MCSymbolRefExpr::VK_None, *Ctx), 1638a34c753fSRafael Auler AArch64MCExpr::VK_ABS_G0_NC, *Ctx))); 1639a34c753fSRafael Auler Inst.addOperand(MCOperand::createImm(0)); 1640a34c753fSRafael Auler Seq.emplace_back(Inst); 1641a34c753fSRafael Auler 1642a34c753fSRafael Auler Inst.clear(); 1643a34c753fSRafael Auler Inst.setOpcode(AArch64::BR); 1644a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::X16)); 1645a34c753fSRafael Auler if (IsTailCall) 1646a34c753fSRafael Auler setTailCall(Inst); 1647a34c753fSRafael Auler Seq.emplace_back(Inst); 1648a34c753fSRafael Auler } 1649a34c753fSRafael Auler 165069706eafSMaksim Panchenko void createShortJmp(InstructionListType &Seq, const MCSymbol *Target, 1651a34c753fSRafael Auler MCContext *Ctx, bool IsTailCall) override { 1652a34c753fSRafael Auler // ip0 (r16) is reserved to the linker (refer to 5.3.1.1 of "Procedure Call 1653a34c753fSRafael Auler // Standard for the ARM 64-bit Architecture (AArch64)". 1654a34c753fSRafael Auler // The sequence of instructions we create here is the following: 1655a34c753fSRafael Auler // adrp ip0, imm 1656a34c753fSRafael Auler // add ip0, ip0, imm 1657a34c753fSRafael Auler // br ip0 1658a34c753fSRafael Auler MCPhysReg Reg = AArch64::X16; 165969706eafSMaksim Panchenko InstructionListType Insts = materializeAddress(Target, Ctx, Reg); 1660a34c753fSRafael Auler Insts.emplace_back(); 1661a34c753fSRafael Auler MCInst &Inst = Insts.back(); 1662a34c753fSRafael Auler Inst.clear(); 1663a34c753fSRafael Auler Inst.setOpcode(AArch64::BR); 1664a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(Reg)); 1665a34c753fSRafael Auler if (IsTailCall) 1666a34c753fSRafael Auler setTailCall(Inst); 1667a34c753fSRafael Auler Seq.swap(Insts); 1668a34c753fSRafael Auler } 1669a34c753fSRafael Auler 1670a34c753fSRafael Auler /// Matching pattern here is 1671a34c753fSRafael Auler /// 1672a34c753fSRafael Auler /// ADRP x16, imm 1673a34c753fSRafael Auler /// ADD x16, x16, imm 1674a34c753fSRafael Auler /// BR x16 1675a34c753fSRafael Auler /// 167635efe1d8SVladislav Khmelevsky uint64_t matchLinkerVeneer(InstructionIterator Begin, InstructionIterator End, 1677a34c753fSRafael Auler uint64_t Address, const MCInst &CurInst, 1678a34c753fSRafael Auler MCInst *&TargetHiBits, MCInst *&TargetLowBits, 1679a34c753fSRafael Auler uint64_t &Target) const override { 1680a34c753fSRafael Auler if (CurInst.getOpcode() != AArch64::BR || !CurInst.getOperand(0).isReg() || 1681a34c753fSRafael Auler CurInst.getOperand(0).getReg() != AArch64::X16) 168235efe1d8SVladislav Khmelevsky return 0; 1683a34c753fSRafael Auler 1684a34c753fSRafael Auler auto I = End; 1685a34c753fSRafael Auler if (I == Begin) 168635efe1d8SVladislav Khmelevsky return 0; 1687a34c753fSRafael Auler 1688a34c753fSRafael Auler --I; 1689a34c753fSRafael Auler Address -= 4; 16908aab58baSMaksim Panchenko if (I == Begin || I->getOpcode() != AArch64::ADDXri || 16918aab58baSMaksim Panchenko MCPlus::getNumPrimeOperands(*I) < 3 || !I->getOperand(0).isReg() || 1692a34c753fSRafael Auler !I->getOperand(1).isReg() || 1693a34c753fSRafael Auler I->getOperand(0).getReg() != AArch64::X16 || 16948aab58baSMaksim Panchenko I->getOperand(1).getReg() != AArch64::X16 || !I->getOperand(2).isImm()) 169535efe1d8SVladislav Khmelevsky return 0; 1696a34c753fSRafael Auler TargetLowBits = &*I; 1697a34c753fSRafael Auler uint64_t Addr = I->getOperand(2).getImm() & 0xFFF; 1698a34c753fSRafael Auler 1699a34c753fSRafael Auler --I; 1700a34c753fSRafael Auler Address -= 4; 1701a34c753fSRafael Auler if (I->getOpcode() != AArch64::ADRP || 17028aab58baSMaksim Panchenko MCPlus::getNumPrimeOperands(*I) < 2 || !I->getOperand(0).isReg() || 17038aab58baSMaksim Panchenko !I->getOperand(1).isImm() || I->getOperand(0).getReg() != AArch64::X16) 170435efe1d8SVladislav Khmelevsky return 0; 1705a34c753fSRafael Auler TargetHiBits = &*I; 1706a34c753fSRafael Auler Addr |= (Address + ((int64_t)I->getOperand(1).getImm() << 12)) & 1707a34c753fSRafael Auler 0xFFFFFFFFFFFFF000ULL; 1708a34c753fSRafael Auler Target = Addr; 170935efe1d8SVladislav Khmelevsky return 3; 1710a34c753fSRafael Auler } 1711a34c753fSRafael Auler 1712be89e794SMaksim Panchenko /// Match the following pattern: 1713be89e794SMaksim Panchenko /// 1714be89e794SMaksim Panchenko /// LDR x16, .L1 1715be89e794SMaksim Panchenko /// BR x16 1716be89e794SMaksim Panchenko /// L1: 1717be89e794SMaksim Panchenko /// .quad Target 1718be89e794SMaksim Panchenko /// 1719be89e794SMaksim Panchenko /// Populate \p TargetAddress with the Target value on successful match. 1720be89e794SMaksim Panchenko bool matchAbsLongVeneer(const BinaryFunction &BF, 1721be89e794SMaksim Panchenko uint64_t &TargetAddress) const override { 1722be89e794SMaksim Panchenko if (BF.size() != 1 || BF.getMaxSize() < 16) 1723be89e794SMaksim Panchenko return false; 1724be89e794SMaksim Panchenko 1725be89e794SMaksim Panchenko if (!BF.hasConstantIsland()) 1726be89e794SMaksim Panchenko return false; 1727be89e794SMaksim Panchenko 1728be89e794SMaksim Panchenko const BinaryBasicBlock &BB = BF.front(); 1729be89e794SMaksim Panchenko if (BB.size() != 2) 1730be89e794SMaksim Panchenko return false; 1731be89e794SMaksim Panchenko 1732be89e794SMaksim Panchenko const MCInst &LDRInst = BB.getInstructionAtIndex(0); 1733be89e794SMaksim Panchenko if (LDRInst.getOpcode() != AArch64::LDRXl) 1734be89e794SMaksim Panchenko return false; 1735be89e794SMaksim Panchenko 1736be89e794SMaksim Panchenko if (!LDRInst.getOperand(0).isReg() || 1737be89e794SMaksim Panchenko LDRInst.getOperand(0).getReg() != AArch64::X16) 1738be89e794SMaksim Panchenko return false; 1739be89e794SMaksim Panchenko 1740be89e794SMaksim Panchenko const MCSymbol *TargetSym = getTargetSymbol(LDRInst, 1); 1741be89e794SMaksim Panchenko if (!TargetSym) 1742be89e794SMaksim Panchenko return false; 1743be89e794SMaksim Panchenko 1744be89e794SMaksim Panchenko const MCInst &BRInst = BB.getInstructionAtIndex(1); 1745be89e794SMaksim Panchenko if (BRInst.getOpcode() != AArch64::BR) 1746be89e794SMaksim Panchenko return false; 1747be89e794SMaksim Panchenko if (!BRInst.getOperand(0).isReg() || 1748be89e794SMaksim Panchenko BRInst.getOperand(0).getReg() != AArch64::X16) 1749be89e794SMaksim Panchenko return false; 1750be89e794SMaksim Panchenko 1751be89e794SMaksim Panchenko const BinaryFunction::IslandInfo &IInfo = BF.getIslandInfo(); 1752be89e794SMaksim Panchenko if (IInfo.HasDynamicRelocations) 1753be89e794SMaksim Panchenko return false; 1754be89e794SMaksim Panchenko 1755be89e794SMaksim Panchenko auto Iter = IInfo.Offsets.find(8); 1756be89e794SMaksim Panchenko if (Iter == IInfo.Offsets.end() || Iter->second != TargetSym) 1757be89e794SMaksim Panchenko return false; 1758be89e794SMaksim Panchenko 1759be89e794SMaksim Panchenko // Extract the absolute value stored inside the island. 1760be89e794SMaksim Panchenko StringRef SectionContents = BF.getOriginSection()->getContents(); 1761be89e794SMaksim Panchenko StringRef FunctionContents = SectionContents.substr( 1762be89e794SMaksim Panchenko BF.getAddress() - BF.getOriginSection()->getAddress(), BF.getMaxSize()); 1763be89e794SMaksim Panchenko 1764be89e794SMaksim Panchenko const BinaryContext &BC = BF.getBinaryContext(); 1765be89e794SMaksim Panchenko DataExtractor DE(FunctionContents, BC.AsmInfo->isLittleEndian(), 1766be89e794SMaksim Panchenko BC.AsmInfo->getCodePointerSize()); 1767be89e794SMaksim Panchenko uint64_t Offset = 8; 1768be89e794SMaksim Panchenko TargetAddress = DE.getAddress(&Offset); 1769be89e794SMaksim Panchenko 1770be89e794SMaksim Panchenko return true; 1771be89e794SMaksim Panchenko } 1772be89e794SMaksim Panchenko 177317ed8f29SVladislav Khmelevsky bool matchAdrpAddPair(const MCInst &Adrp, const MCInst &Add) const override { 177417ed8f29SVladislav Khmelevsky if (!isADRP(Adrp) || !isAddXri(Add)) 177517ed8f29SVladislav Khmelevsky return false; 177617ed8f29SVladislav Khmelevsky 177717ed8f29SVladislav Khmelevsky assert(Adrp.getOperand(0).isReg() && 177817ed8f29SVladislav Khmelevsky "Unexpected operand in ADRP instruction"); 177917ed8f29SVladislav Khmelevsky MCPhysReg AdrpReg = Adrp.getOperand(0).getReg(); 178017ed8f29SVladislav Khmelevsky assert(Add.getOperand(1).isReg() && 178117ed8f29SVladislav Khmelevsky "Unexpected operand in ADDXri instruction"); 178217ed8f29SVladislav Khmelevsky MCPhysReg AddReg = Add.getOperand(1).getReg(); 178317ed8f29SVladislav Khmelevsky return AdrpReg == AddReg; 178417ed8f29SVladislav Khmelevsky } 178517ed8f29SVladislav Khmelevsky 1786a34c753fSRafael Auler bool replaceImmWithSymbolRef(MCInst &Inst, const MCSymbol *Symbol, 1787a34c753fSRafael Auler int64_t Addend, MCContext *Ctx, int64_t &Value, 1788a34c753fSRafael Auler uint64_t RelType) const override { 1789a34c753fSRafael Auler unsigned ImmOpNo = -1U; 1790a34c753fSRafael Auler for (unsigned Index = 0; Index < MCPlus::getNumPrimeOperands(Inst); 1791a34c753fSRafael Auler ++Index) { 1792a34c753fSRafael Auler if (Inst.getOperand(Index).isImm()) { 1793a34c753fSRafael Auler ImmOpNo = Index; 1794a34c753fSRafael Auler break; 1795a34c753fSRafael Auler } 1796a34c753fSRafael Auler } 1797a34c753fSRafael Auler if (ImmOpNo == -1U) 1798a34c753fSRafael Auler return false; 1799a34c753fSRafael Auler 1800a34c753fSRafael Auler Value = Inst.getOperand(ImmOpNo).getImm(); 1801a34c753fSRafael Auler 1802a34c753fSRafael Auler setOperandToSymbolRef(Inst, ImmOpNo, Symbol, Addend, Ctx, RelType); 1803a34c753fSRafael Auler 1804a34c753fSRafael Auler return true; 1805a34c753fSRafael Auler } 1806a34c753fSRafael Auler 1807bba790dbSMaksim Panchenko void createUncondBranch(MCInst &Inst, const MCSymbol *TBB, 1808a34c753fSRafael Auler MCContext *Ctx) const override { 1809a34c753fSRafael Auler Inst.setOpcode(AArch64::B); 1810a34c753fSRafael Auler Inst.clear(); 1811a34c753fSRafael Auler Inst.addOperand(MCOperand::createExpr(getTargetExprFor( 1812a34c753fSRafael Auler Inst, MCSymbolRefExpr::create(TBB, MCSymbolRefExpr::VK_None, *Ctx), 1813a34c753fSRafael Auler *Ctx, 0))); 1814a34c753fSRafael Auler } 1815a34c753fSRafael Auler 1816edda8577SAmir Ayupov bool shouldRecordCodeRelocation(uint64_t RelType) const override { 1817edda8577SAmir Ayupov switch (RelType) { 1818edda8577SAmir Ayupov case ELF::R_AARCH64_ABS64: 1819edda8577SAmir Ayupov case ELF::R_AARCH64_ABS32: 1820edda8577SAmir Ayupov case ELF::R_AARCH64_ABS16: 1821edda8577SAmir Ayupov case ELF::R_AARCH64_ADD_ABS_LO12_NC: 1822edda8577SAmir Ayupov case ELF::R_AARCH64_ADR_GOT_PAGE: 1823edda8577SAmir Ayupov case ELF::R_AARCH64_ADR_PREL_LO21: 1824edda8577SAmir Ayupov case ELF::R_AARCH64_ADR_PREL_PG_HI21: 1825edda8577SAmir Ayupov case ELF::R_AARCH64_ADR_PREL_PG_HI21_NC: 1826edda8577SAmir Ayupov case ELF::R_AARCH64_LD64_GOT_LO12_NC: 1827edda8577SAmir Ayupov case ELF::R_AARCH64_LDST8_ABS_LO12_NC: 1828edda8577SAmir Ayupov case ELF::R_AARCH64_LDST16_ABS_LO12_NC: 1829edda8577SAmir Ayupov case ELF::R_AARCH64_LDST32_ABS_LO12_NC: 1830edda8577SAmir Ayupov case ELF::R_AARCH64_LDST64_ABS_LO12_NC: 1831edda8577SAmir Ayupov case ELF::R_AARCH64_LDST128_ABS_LO12_NC: 1832edda8577SAmir Ayupov case ELF::R_AARCH64_TLSDESC_ADD_LO12: 1833edda8577SAmir Ayupov case ELF::R_AARCH64_TLSDESC_ADR_PAGE21: 1834edda8577SAmir Ayupov case ELF::R_AARCH64_TLSDESC_ADR_PREL21: 1835edda8577SAmir Ayupov case ELF::R_AARCH64_TLSDESC_LD64_LO12: 1836edda8577SAmir Ayupov case ELF::R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: 1837edda8577SAmir Ayupov case ELF::R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: 1838e11d49cbSAlexey Moksyakov case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0: 1839e11d49cbSAlexey Moksyakov case ELF::R_AARCH64_TLSLE_MOVW_TPREL_G0_NC: 1840edda8577SAmir Ayupov case ELF::R_AARCH64_MOVW_UABS_G0: 1841edda8577SAmir Ayupov case ELF::R_AARCH64_MOVW_UABS_G0_NC: 1842edda8577SAmir Ayupov case ELF::R_AARCH64_MOVW_UABS_G1: 1843edda8577SAmir Ayupov case ELF::R_AARCH64_MOVW_UABS_G1_NC: 1844edda8577SAmir Ayupov case ELF::R_AARCH64_MOVW_UABS_G2: 1845edda8577SAmir Ayupov case ELF::R_AARCH64_MOVW_UABS_G2_NC: 1846edda8577SAmir Ayupov case ELF::R_AARCH64_MOVW_UABS_G3: 1847edda8577SAmir Ayupov case ELF::R_AARCH64_PREL16: 1848edda8577SAmir Ayupov case ELF::R_AARCH64_PREL32: 1849edda8577SAmir Ayupov case ELF::R_AARCH64_PREL64: 1850edda8577SAmir Ayupov return true; 1851edda8577SAmir Ayupov case ELF::R_AARCH64_CALL26: 1852edda8577SAmir Ayupov case ELF::R_AARCH64_JUMP26: 1853edda8577SAmir Ayupov case ELF::R_AARCH64_TSTBR14: 1854edda8577SAmir Ayupov case ELF::R_AARCH64_CONDBR19: 1855edda8577SAmir Ayupov case ELF::R_AARCH64_TLSDESC_CALL: 1856edda8577SAmir Ayupov case ELF::R_AARCH64_TLSLE_ADD_TPREL_HI12: 1857edda8577SAmir Ayupov case ELF::R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: 1858edda8577SAmir Ayupov return false; 1859edda8577SAmir Ayupov default: 1860edda8577SAmir Ayupov llvm_unreachable("Unexpected AArch64 relocation type in code"); 1861edda8577SAmir Ayupov } 1862edda8577SAmir Ayupov } 1863edda8577SAmir Ayupov 186428fd2ca1SDenis Revunov StringRef getTrapFillValue() const override { 186528fd2ca1SDenis Revunov return StringRef("\0\0\0\0", 4); 186628fd2ca1SDenis Revunov } 186728fd2ca1SDenis Revunov 1868bba790dbSMaksim Panchenko void createReturn(MCInst &Inst) const override { 1869a34c753fSRafael Auler Inst.setOpcode(AArch64::RET); 1870a34c753fSRafael Auler Inst.clear(); 1871a34c753fSRafael Auler Inst.addOperand(MCOperand::createReg(AArch64::LR)); 1872a34c753fSRafael Auler } 1873a34c753fSRafael Auler 1874bba790dbSMaksim Panchenko void createStackPointerIncrement( 18756e4c2305SElvina Yakubova MCInst &Inst, int Size, 18766e4c2305SElvina Yakubova bool NoFlagsClobber = false /*unused for AArch64*/) const override { 18776e4c2305SElvina Yakubova Inst.setOpcode(AArch64::SUBXri); 18786e4c2305SElvina Yakubova Inst.clear(); 18796e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 18806e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 18816e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(Size)); 18826e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(0)); 18836e4c2305SElvina Yakubova } 18846e4c2305SElvina Yakubova 1885bba790dbSMaksim Panchenko void createStackPointerDecrement( 18866e4c2305SElvina Yakubova MCInst &Inst, int Size, 18876e4c2305SElvina Yakubova bool NoFlagsClobber = false /*unused for AArch64*/) const override { 18886e4c2305SElvina Yakubova Inst.setOpcode(AArch64::ADDXri); 18896e4c2305SElvina Yakubova Inst.clear(); 18906e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 18916e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(AArch64::SP)); 18926e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(Size)); 18936e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createImm(0)); 18946e4c2305SElvina Yakubova } 18956e4c2305SElvina Yakubova 18966e4c2305SElvina Yakubova void createIndirectBranch(MCInst &Inst, MCPhysReg MemBaseReg, 18976e4c2305SElvina Yakubova int64_t Disp) const { 18986e4c2305SElvina Yakubova Inst.setOpcode(AArch64::BR); 189959ab86bbSMaksim Panchenko Inst.clear(); 19006e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(MemBaseReg)); 19016e4c2305SElvina Yakubova } 19026e4c2305SElvina Yakubova 19036e4c2305SElvina Yakubova InstructionListType createInstrumentedIndCallHandlerExitBB() const override { 19046e4c2305SElvina Yakubova InstructionListType Insts(5); 19056e4c2305SElvina Yakubova // Code sequence for instrumented indirect call handler: 19066e4c2305SElvina Yakubova // msr nzcv, x1 19076e4c2305SElvina Yakubova // ldp x0, x1, [sp], #16 19086e4c2305SElvina Yakubova // ldr x16, [sp], #16 19096e4c2305SElvina Yakubova // ldp x0, x1, [sp], #16 19106e4c2305SElvina Yakubova // br x16 19116e4c2305SElvina Yakubova setSystemFlag(Insts[0], AArch64::X1); 19126e4c2305SElvina Yakubova createPopRegisters(Insts[1], AArch64::X0, AArch64::X1); 19136e4c2305SElvina Yakubova // Here we load address of the next function which should be called in the 19146e4c2305SElvina Yakubova // original binary to X16 register. Writing to X16 is permitted without 19156e4c2305SElvina Yakubova // needing to restore. 19166e4c2305SElvina Yakubova loadReg(Insts[2], AArch64::X16, AArch64::SP); 19176e4c2305SElvina Yakubova createPopRegisters(Insts[3], AArch64::X0, AArch64::X1); 19186e4c2305SElvina Yakubova createIndirectBranch(Insts[4], AArch64::X16, 0); 19196e4c2305SElvina Yakubova return Insts; 19206e4c2305SElvina Yakubova } 19216e4c2305SElvina Yakubova 19226e4c2305SElvina Yakubova InstructionListType 19236e4c2305SElvina Yakubova createInstrumentedIndTailCallHandlerExitBB() const override { 19246e4c2305SElvina Yakubova return createInstrumentedIndCallHandlerExitBB(); 19256e4c2305SElvina Yakubova } 19266e4c2305SElvina Yakubova 192770405a0bSElvina Yakubova InstructionListType createGetter(MCContext *Ctx, const char *name) const { 192870405a0bSElvina Yakubova InstructionListType Insts(4); 192970405a0bSElvina Yakubova MCSymbol *Locs = Ctx->getOrCreateSymbol(name); 193070405a0bSElvina Yakubova InstructionListType Addr = materializeAddress(Locs, Ctx, AArch64::X0); 193170405a0bSElvina Yakubova std::copy(Addr.begin(), Addr.end(), Insts.begin()); 193270405a0bSElvina Yakubova assert(Addr.size() == 2 && "Invalid Addr size"); 193370405a0bSElvina Yakubova loadReg(Insts[2], AArch64::X0, AArch64::X0); 193470405a0bSElvina Yakubova createReturn(Insts[3]); 193570405a0bSElvina Yakubova return Insts; 193670405a0bSElvina Yakubova } 193770405a0bSElvina Yakubova 193870405a0bSElvina Yakubova InstructionListType createNumCountersGetter(MCContext *Ctx) const override { 193970405a0bSElvina Yakubova return createGetter(Ctx, "__bolt_num_counters"); 194070405a0bSElvina Yakubova } 194170405a0bSElvina Yakubova 194270405a0bSElvina Yakubova InstructionListType 194370405a0bSElvina Yakubova createInstrLocationsGetter(MCContext *Ctx) const override { 194470405a0bSElvina Yakubova return createGetter(Ctx, "__bolt_instr_locations"); 194570405a0bSElvina Yakubova } 194670405a0bSElvina Yakubova 194770405a0bSElvina Yakubova InstructionListType createInstrTablesGetter(MCContext *Ctx) const override { 194870405a0bSElvina Yakubova return createGetter(Ctx, "__bolt_instr_tables"); 194970405a0bSElvina Yakubova } 195070405a0bSElvina Yakubova 195170405a0bSElvina Yakubova InstructionListType createInstrNumFuncsGetter(MCContext *Ctx) const override { 195270405a0bSElvina Yakubova return createGetter(Ctx, "__bolt_instr_num_funcs"); 195370405a0bSElvina Yakubova } 195470405a0bSElvina Yakubova 19556e4c2305SElvina Yakubova void convertIndirectCallToLoad(MCInst &Inst, MCPhysReg Reg) override { 19566e4c2305SElvina Yakubova bool IsTailCall = isTailCall(Inst); 19576e4c2305SElvina Yakubova if (IsTailCall) 19586e4c2305SElvina Yakubova removeAnnotation(Inst, MCPlus::MCAnnotation::kTailCall); 19596e4c2305SElvina Yakubova if (Inst.getOpcode() == AArch64::BR || Inst.getOpcode() == AArch64::BLR) { 19606e4c2305SElvina Yakubova Inst.setOpcode(AArch64::ORRXrs); 19616e4c2305SElvina Yakubova Inst.insert(Inst.begin(), MCOperand::createReg(Reg)); 19626e4c2305SElvina Yakubova Inst.insert(Inst.begin() + 1, MCOperand::createReg(AArch64::XZR)); 19636e4c2305SElvina Yakubova Inst.insert(Inst.begin() + 3, MCOperand::createImm(0)); 19646e4c2305SElvina Yakubova return; 19656e4c2305SElvina Yakubova } 19666e4c2305SElvina Yakubova llvm_unreachable("not implemented"); 19676e4c2305SElvina Yakubova } 19686e4c2305SElvina Yakubova 19696e4c2305SElvina Yakubova InstructionListType createLoadImmediate(const MCPhysReg Dest, 19706e4c2305SElvina Yakubova uint64_t Imm) const override { 19716e4c2305SElvina Yakubova InstructionListType Insts(4); 19726e4c2305SElvina Yakubova int Shift = 48; 19736e4c2305SElvina Yakubova for (int I = 0; I < 4; I++, Shift -= 16) { 19746e4c2305SElvina Yakubova Insts[I].setOpcode(AArch64::MOVKXi); 19756e4c2305SElvina Yakubova Insts[I].addOperand(MCOperand::createReg(Dest)); 19766e4c2305SElvina Yakubova Insts[I].addOperand(MCOperand::createReg(Dest)); 19776e4c2305SElvina Yakubova Insts[I].addOperand(MCOperand::createImm((Imm >> Shift) & 0xFFFF)); 19786e4c2305SElvina Yakubova Insts[I].addOperand(MCOperand::createImm(Shift)); 19796e4c2305SElvina Yakubova } 19806e4c2305SElvina Yakubova return Insts; 19816e4c2305SElvina Yakubova } 19826e4c2305SElvina Yakubova 19836e4c2305SElvina Yakubova void createIndirectCallInst(MCInst &Inst, bool IsTailCall, 19846e4c2305SElvina Yakubova MCPhysReg Reg) const { 19856e4c2305SElvina Yakubova Inst.clear(); 19866e4c2305SElvina Yakubova Inst.setOpcode(IsTailCall ? AArch64::BR : AArch64::BLR); 19876e4c2305SElvina Yakubova Inst.addOperand(MCOperand::createReg(Reg)); 19886e4c2305SElvina Yakubova } 19896e4c2305SElvina Yakubova 19906e4c2305SElvina Yakubova InstructionListType createInstrumentedIndirectCall(MCInst &&CallInst, 19916e4c2305SElvina Yakubova MCSymbol *HandlerFuncAddr, 19926e4c2305SElvina Yakubova int CallSiteID, 19936e4c2305SElvina Yakubova MCContext *Ctx) override { 19946e4c2305SElvina Yakubova InstructionListType Insts; 19956e4c2305SElvina Yakubova // Code sequence used to enter indirect call instrumentation helper: 19966e4c2305SElvina Yakubova // stp x0, x1, [sp, #-16]! createPushRegisters 19976e4c2305SElvina Yakubova // mov target x0 convertIndirectCallToLoad -> orr x0 target xzr 19986e4c2305SElvina Yakubova // mov x1 CallSiteID createLoadImmediate -> 19996e4c2305SElvina Yakubova // movk x1, #0x0, lsl #48 20006e4c2305SElvina Yakubova // movk x1, #0x0, lsl #32 20016e4c2305SElvina Yakubova // movk x1, #0x0, lsl #16 20026e4c2305SElvina Yakubova // movk x1, #0x0 20036e4c2305SElvina Yakubova // stp x0, x1, [sp, #-16]! 20046e4c2305SElvina Yakubova // bl *HandlerFuncAddr createIndirectCall -> 20056e4c2305SElvina Yakubova // adr x0 *HandlerFuncAddr -> adrp + add 20066e4c2305SElvina Yakubova // blr x0 20076e4c2305SElvina Yakubova Insts.emplace_back(); 20086e4c2305SElvina Yakubova createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1); 20096e4c2305SElvina Yakubova Insts.emplace_back(CallInst); 20106e4c2305SElvina Yakubova convertIndirectCallToLoad(Insts.back(), AArch64::X0); 20116e4c2305SElvina Yakubova InstructionListType LoadImm = 20126e4c2305SElvina Yakubova createLoadImmediate(getIntArgRegister(1), CallSiteID); 20136e4c2305SElvina Yakubova Insts.insert(Insts.end(), LoadImm.begin(), LoadImm.end()); 20146e4c2305SElvina Yakubova Insts.emplace_back(); 20156e4c2305SElvina Yakubova createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1); 20166e4c2305SElvina Yakubova Insts.resize(Insts.size() + 2); 20176e4c2305SElvina Yakubova InstructionListType Addr = 20186e4c2305SElvina Yakubova materializeAddress(HandlerFuncAddr, Ctx, AArch64::X0); 20196e4c2305SElvina Yakubova assert(Addr.size() == 2 && "Invalid Addr size"); 20206e4c2305SElvina Yakubova std::copy(Addr.begin(), Addr.end(), Insts.end() - Addr.size()); 20216e4c2305SElvina Yakubova Insts.emplace_back(); 20226e4c2305SElvina Yakubova createIndirectCallInst(Insts.back(), isTailCall(CallInst), AArch64::X0); 20236e4c2305SElvina Yakubova 20246e4c2305SElvina Yakubova // Carry over metadata including tail call marker if present. 20256e4c2305SElvina Yakubova stripAnnotations(Insts.back()); 20266e4c2305SElvina Yakubova moveAnnotations(std::move(CallInst), Insts.back()); 20276e4c2305SElvina Yakubova 20286e4c2305SElvina Yakubova return Insts; 20296e4c2305SElvina Yakubova } 20306e4c2305SElvina Yakubova 20316e4c2305SElvina Yakubova InstructionListType 20326e4c2305SElvina Yakubova createInstrumentedIndCallHandlerEntryBB(const MCSymbol *InstrTrampoline, 20336e4c2305SElvina Yakubova const MCSymbol *IndCallHandler, 20346e4c2305SElvina Yakubova MCContext *Ctx) override { 20356e4c2305SElvina Yakubova // Code sequence used to check whether InstrTampoline was initialized 20366e4c2305SElvina Yakubova // and call it if so, returns via IndCallHandler 20376e4c2305SElvina Yakubova // stp x0, x1, [sp, #-16]! 20386e4c2305SElvina Yakubova // mrs x1, nzcv 20396e4c2305SElvina Yakubova // adr x0, InstrTrampoline -> adrp + add 20406e4c2305SElvina Yakubova // ldr x0, [x0] 20416e4c2305SElvina Yakubova // subs x0, x0, #0x0 20426e4c2305SElvina Yakubova // b.eq IndCallHandler 20436e4c2305SElvina Yakubova // str x30, [sp, #-16]! 20446e4c2305SElvina Yakubova // blr x0 20456e4c2305SElvina Yakubova // ldr x30, [sp], #16 20466e4c2305SElvina Yakubova // b IndCallHandler 20476e4c2305SElvina Yakubova InstructionListType Insts; 20486e4c2305SElvina Yakubova Insts.emplace_back(); 20496e4c2305SElvina Yakubova createPushRegisters(Insts.back(), AArch64::X0, AArch64::X1); 20506e4c2305SElvina Yakubova Insts.emplace_back(); 20516e4c2305SElvina Yakubova getSystemFlag(Insts.back(), getIntArgRegister(1)); 20526e4c2305SElvina Yakubova Insts.emplace_back(); 20536e4c2305SElvina Yakubova Insts.emplace_back(); 20546e4c2305SElvina Yakubova InstructionListType Addr = 20556e4c2305SElvina Yakubova materializeAddress(InstrTrampoline, Ctx, AArch64::X0); 20566e4c2305SElvina Yakubova std::copy(Addr.begin(), Addr.end(), Insts.end() - Addr.size()); 20576e4c2305SElvina Yakubova assert(Addr.size() == 2 && "Invalid Addr size"); 20586e4c2305SElvina Yakubova Insts.emplace_back(); 20596e4c2305SElvina Yakubova loadReg(Insts.back(), AArch64::X0, AArch64::X0); 20606e4c2305SElvina Yakubova InstructionListType cmpJmp = 20616e4c2305SElvina Yakubova createCmpJE(AArch64::X0, 0, IndCallHandler, Ctx); 20626e4c2305SElvina Yakubova Insts.insert(Insts.end(), cmpJmp.begin(), cmpJmp.end()); 20636e4c2305SElvina Yakubova Insts.emplace_back(); 20646e4c2305SElvina Yakubova storeReg(Insts.back(), AArch64::LR, AArch64::SP); 20656e4c2305SElvina Yakubova Insts.emplace_back(); 20666e4c2305SElvina Yakubova Insts.back().setOpcode(AArch64::BLR); 20676e4c2305SElvina Yakubova Insts.back().addOperand(MCOperand::createReg(AArch64::X0)); 20686e4c2305SElvina Yakubova Insts.emplace_back(); 20696e4c2305SElvina Yakubova loadReg(Insts.back(), AArch64::LR, AArch64::SP); 20706e4c2305SElvina Yakubova Insts.emplace_back(); 20716e4c2305SElvina Yakubova createDirectCall(Insts.back(), IndCallHandler, Ctx, /*IsTailCall*/ true); 20726e4c2305SElvina Yakubova return Insts; 20736e4c2305SElvina Yakubova } 20746e4c2305SElvina Yakubova 20756e4c2305SElvina Yakubova InstructionListType 20766e4c2305SElvina Yakubova createInstrIncMemory(const MCSymbol *Target, MCContext *Ctx, bool IsLeaf, 20776e4c2305SElvina Yakubova unsigned CodePointerSize) const override { 20786e4c2305SElvina Yakubova unsigned int I = 0; 20796e4c2305SElvina Yakubova InstructionListType Instrs(IsLeaf ? 12 : 10); 20806e4c2305SElvina Yakubova 20816e4c2305SElvina Yakubova if (IsLeaf) 20826e4c2305SElvina Yakubova createStackPointerIncrement(Instrs[I++], 128); 20836e4c2305SElvina Yakubova createPushRegisters(Instrs[I++], AArch64::X0, AArch64::X1); 20846e4c2305SElvina Yakubova getSystemFlag(Instrs[I++], AArch64::X1); 20856e4c2305SElvina Yakubova InstructionListType Addr = materializeAddress(Target, Ctx, AArch64::X0); 20866e4c2305SElvina Yakubova assert(Addr.size() == 2 && "Invalid Addr size"); 20876e4c2305SElvina Yakubova std::copy(Addr.begin(), Addr.end(), Instrs.begin() + I); 20886e4c2305SElvina Yakubova I += Addr.size(); 20896e4c2305SElvina Yakubova storeReg(Instrs[I++], AArch64::X2, AArch64::SP); 20906e4c2305SElvina Yakubova InstructionListType Insts = createIncMemory(AArch64::X0, AArch64::X2); 20916e4c2305SElvina Yakubova assert(Insts.size() == 2 && "Invalid Insts size"); 20926e4c2305SElvina Yakubova std::copy(Insts.begin(), Insts.end(), Instrs.begin() + I); 20936e4c2305SElvina Yakubova I += Insts.size(); 20946e4c2305SElvina Yakubova loadReg(Instrs[I++], AArch64::X2, AArch64::SP); 20956e4c2305SElvina Yakubova setSystemFlag(Instrs[I++], AArch64::X1); 20966e4c2305SElvina Yakubova createPopRegisters(Instrs[I++], AArch64::X0, AArch64::X1); 20976e4c2305SElvina Yakubova if (IsLeaf) 20986e4c2305SElvina Yakubova createStackPointerDecrement(Instrs[I++], 128); 20996e4c2305SElvina Yakubova return Instrs; 21006e4c2305SElvina Yakubova } 21016e4c2305SElvina Yakubova 21026e4c2305SElvina Yakubova std::vector<MCInst> createSymbolTrampoline(const MCSymbol *TgtSym, 21036e4c2305SElvina Yakubova MCContext *Ctx) override { 21046e4c2305SElvina Yakubova std::vector<MCInst> Insts; 21056e4c2305SElvina Yakubova createShortJmp(Insts, TgtSym, Ctx, /*IsTailCall*/ true); 21066e4c2305SElvina Yakubova return Insts; 21076e4c2305SElvina Yakubova } 21086e4c2305SElvina Yakubova 210969706eafSMaksim Panchenko InstructionListType materializeAddress(const MCSymbol *Target, MCContext *Ctx, 2110a34c753fSRafael Auler MCPhysReg RegName, 2111a34c753fSRafael Auler int64_t Addend = 0) const override { 2112a34c753fSRafael Auler // Get page-aligned address and add page offset 211369706eafSMaksim Panchenko InstructionListType Insts(2); 2114a34c753fSRafael Auler Insts[0].setOpcode(AArch64::ADRP); 2115a34c753fSRafael Auler Insts[0].clear(); 2116a34c753fSRafael Auler Insts[0].addOperand(MCOperand::createReg(RegName)); 2117a34c753fSRafael Auler Insts[0].addOperand(MCOperand::createImm(0)); 2118a34c753fSRafael Auler setOperandToSymbolRef(Insts[0], /* OpNum */ 1, Target, Addend, Ctx, 2119a34c753fSRafael Auler ELF::R_AARCH64_NONE); 2120a34c753fSRafael Auler Insts[1].setOpcode(AArch64::ADDXri); 2121a34c753fSRafael Auler Insts[1].clear(); 2122a34c753fSRafael Auler Insts[1].addOperand(MCOperand::createReg(RegName)); 2123a34c753fSRafael Auler Insts[1].addOperand(MCOperand::createReg(RegName)); 2124a34c753fSRafael Auler Insts[1].addOperand(MCOperand::createImm(0)); 2125a34c753fSRafael Auler Insts[1].addOperand(MCOperand::createImm(0)); 2126a34c753fSRafael Auler setOperandToSymbolRef(Insts[1], /* OpNum */ 2, Target, Addend, Ctx, 2127a34c753fSRafael Auler ELF::R_AARCH64_ADD_ABS_LO12_NC); 2128a34c753fSRafael Auler return Insts; 2129a34c753fSRafael Auler } 213062020a3aSzhoujiapeng 213162020a3aSzhoujiapeng std::optional<Relocation> 213262020a3aSzhoujiapeng createRelocation(const MCFixup &Fixup, 213362020a3aSzhoujiapeng const MCAsmBackend &MAB) const override { 213462020a3aSzhoujiapeng const MCFixupKindInfo &FKI = MAB.getFixupKindInfo(Fixup.getKind()); 213562020a3aSzhoujiapeng 213662020a3aSzhoujiapeng assert(FKI.TargetOffset == 0 && "0-bit relocation offset expected"); 213762020a3aSzhoujiapeng const uint64_t RelOffset = Fixup.getOffset(); 213862020a3aSzhoujiapeng 213962020a3aSzhoujiapeng uint64_t RelType; 214062020a3aSzhoujiapeng if (Fixup.getKind() == MCFixupKind(AArch64::fixup_aarch64_pcrel_call26)) 214162020a3aSzhoujiapeng RelType = ELF::R_AARCH64_CALL26; 214271c2a132Ssinan else if (Fixup.getKind() == 214371c2a132Ssinan MCFixupKind(AArch64::fixup_aarch64_pcrel_branch26)) 214471c2a132Ssinan RelType = ELF::R_AARCH64_JUMP26; 214562020a3aSzhoujiapeng else if (FKI.Flags & MCFixupKindInfo::FKF_IsPCRel) { 214662020a3aSzhoujiapeng switch (FKI.TargetSize) { 214762020a3aSzhoujiapeng default: 214862020a3aSzhoujiapeng return std::nullopt; 214962020a3aSzhoujiapeng case 16: 215062020a3aSzhoujiapeng RelType = ELF::R_AARCH64_PREL16; 215162020a3aSzhoujiapeng break; 215262020a3aSzhoujiapeng case 32: 215362020a3aSzhoujiapeng RelType = ELF::R_AARCH64_PREL32; 215462020a3aSzhoujiapeng break; 215562020a3aSzhoujiapeng case 64: 215662020a3aSzhoujiapeng RelType = ELF::R_AARCH64_PREL64; 215762020a3aSzhoujiapeng break; 215862020a3aSzhoujiapeng } 215962020a3aSzhoujiapeng } else { 216062020a3aSzhoujiapeng switch (FKI.TargetSize) { 216162020a3aSzhoujiapeng default: 216262020a3aSzhoujiapeng return std::nullopt; 216362020a3aSzhoujiapeng case 16: 216462020a3aSzhoujiapeng RelType = ELF::R_AARCH64_ABS16; 216562020a3aSzhoujiapeng break; 216662020a3aSzhoujiapeng case 32: 216762020a3aSzhoujiapeng RelType = ELF::R_AARCH64_ABS32; 216862020a3aSzhoujiapeng break; 216962020a3aSzhoujiapeng case 64: 217062020a3aSzhoujiapeng RelType = ELF::R_AARCH64_ABS64; 217162020a3aSzhoujiapeng break; 217262020a3aSzhoujiapeng } 217362020a3aSzhoujiapeng } 217462020a3aSzhoujiapeng 217562020a3aSzhoujiapeng auto [RelSymbol, RelAddend] = extractFixupExpr(Fixup); 217662020a3aSzhoujiapeng 217762020a3aSzhoujiapeng return Relocation({RelOffset, RelSymbol, RelType, RelAddend, 0}); 217862020a3aSzhoujiapeng } 2179b6b49288SJob Noorman 2180b6b49288SJob Noorman uint16_t getMinFunctionAlignment() const override { return 4; } 21811fa02b96SNicholas 21821fa02b96SNicholas std::optional<uint32_t> 21831fa02b96SNicholas getInstructionSize(const MCInst &Inst) const override { 21841fa02b96SNicholas return 4; 21851fa02b96SNicholas } 2186a34c753fSRafael Auler }; 2187a34c753fSRafael Auler 2188a34c753fSRafael Auler } // end anonymous namespace 2189a34c753fSRafael Auler 2190a34c753fSRafael Auler namespace llvm { 2191a34c753fSRafael Auler namespace bolt { 2192a34c753fSRafael Auler 2193a34c753fSRafael Auler MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *Analysis, 2194a34c753fSRafael Auler const MCInstrInfo *Info, 21958fb83bf5SJob Noorman const MCRegisterInfo *RegInfo, 21968fb83bf5SJob Noorman const MCSubtargetInfo *STI) { 21978fb83bf5SJob Noorman return new AArch64MCPlusBuilder(Analysis, Info, RegInfo, STI); 2198a34c753fSRafael Auler } 2199a34c753fSRafael Auler 220040c2e0faSMaksim Panchenko } // namespace bolt 220140c2e0faSMaksim Panchenko } // namespace llvm 2202