1 //===- AArch64AsmPrinter.cpp - AArch64 LLVM assembly writer ---------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains a printer that converts from our internal representation 10 // of machine-dependent LLVM code to the AArch64 assembly language. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "AArch64.h" 15 #include "AArch64MCInstLower.h" 16 #include "AArch64MachineFunctionInfo.h" 17 #include "AArch64RegisterInfo.h" 18 #include "AArch64Subtarget.h" 19 #include "AArch64TargetObjectFile.h" 20 #include "MCTargetDesc/AArch64AddressingModes.h" 21 #include "MCTargetDesc/AArch64InstPrinter.h" 22 #include "MCTargetDesc/AArch64MCExpr.h" 23 #include "MCTargetDesc/AArch64MCTargetDesc.h" 24 #include "MCTargetDesc/AArch64TargetStreamer.h" 25 #include "TargetInfo/AArch64TargetInfo.h" 26 #include "Utils/AArch64BaseInfo.h" 27 #include "llvm/ADT/SmallString.h" 28 #include "llvm/ADT/SmallVector.h" 29 #include "llvm/ADT/StringRef.h" 30 #include "llvm/ADT/Twine.h" 31 #include "llvm/BinaryFormat/COFF.h" 32 #include "llvm/BinaryFormat/ELF.h" 33 #include "llvm/BinaryFormat/MachO.h" 34 #include "llvm/CodeGen/AsmPrinter.h" 35 #include "llvm/CodeGen/FaultMaps.h" 36 #include "llvm/CodeGen/MachineBasicBlock.h" 37 #include "llvm/CodeGen/MachineFunction.h" 38 #include "llvm/CodeGen/MachineInstr.h" 39 #include "llvm/CodeGen/MachineJumpTableInfo.h" 40 #include "llvm/CodeGen/MachineModuleInfoImpls.h" 41 #include "llvm/CodeGen/MachineOperand.h" 42 #include "llvm/CodeGen/StackMaps.h" 43 #include "llvm/CodeGen/TargetRegisterInfo.h" 44 #include "llvm/IR/DataLayout.h" 45 #include "llvm/IR/DebugInfoMetadata.h" 46 #include "llvm/IR/Module.h" 47 #include "llvm/MC/MCAsmInfo.h" 48 #include "llvm/MC/MCContext.h" 49 #include "llvm/MC/MCInst.h" 50 #include "llvm/MC/MCInstBuilder.h" 51 #include "llvm/MC/MCSectionELF.h" 52 #include "llvm/MC/MCSectionMachO.h" 53 #include "llvm/MC/MCStreamer.h" 54 #include "llvm/MC/MCSymbol.h" 55 #include "llvm/MC/TargetRegistry.h" 56 #include "llvm/Support/Casting.h" 57 #include "llvm/Support/CommandLine.h" 58 #include "llvm/Support/ErrorHandling.h" 59 #include "llvm/Support/raw_ostream.h" 60 #include "llvm/Target/TargetMachine.h" 61 #include "llvm/TargetParser/Triple.h" 62 #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" 63 #include <algorithm> 64 #include <cassert> 65 #include <cstdint> 66 #include <map> 67 #include <memory> 68 69 using namespace llvm; 70 71 enum PtrauthCheckMode { Default, Unchecked, Poison, Trap }; 72 static cl::opt<PtrauthCheckMode> PtrauthAuthChecks( 73 "aarch64-ptrauth-auth-checks", cl::Hidden, 74 cl::values(clEnumValN(Unchecked, "none", "don't test for failure"), 75 clEnumValN(Poison, "poison", "poison on failure"), 76 clEnumValN(Trap, "trap", "trap on failure")), 77 cl::desc("Check pointer authentication auth/resign failures"), 78 cl::init(Default)); 79 80 #define DEBUG_TYPE "asm-printer" 81 82 namespace { 83 84 class AArch64AsmPrinter : public AsmPrinter { 85 AArch64MCInstLower MCInstLowering; 86 FaultMaps FM; 87 const AArch64Subtarget *STI; 88 bool ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = false; 89 90 public: 91 AArch64AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) 92 : AsmPrinter(TM, std::move(Streamer)), MCInstLowering(OutContext, *this), 93 FM(*this) {} 94 95 StringRef getPassName() const override { return "AArch64 Assembly Printer"; } 96 97 /// Wrapper for MCInstLowering.lowerOperand() for the 98 /// tblgen'erated pseudo lowering. 99 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const { 100 return MCInstLowering.lowerOperand(MO, MCOp); 101 } 102 103 const MCExpr *lowerConstantPtrAuth(const ConstantPtrAuth &CPA) override; 104 105 const MCExpr *lowerBlockAddressConstant(const BlockAddress &BA) override; 106 107 void emitStartOfAsmFile(Module &M) override; 108 void emitJumpTableInfo() override; 109 std::tuple<const MCSymbol *, uint64_t, const MCSymbol *, 110 codeview::JumpTableEntrySize> 111 getCodeViewJumpTableInfo(int JTI, const MachineInstr *BranchInstr, 112 const MCSymbol *BranchLabel) const override; 113 114 void emitFunctionEntryLabel() override; 115 116 void LowerJumpTableDest(MCStreamer &OutStreamer, const MachineInstr &MI); 117 118 void LowerHardenedBRJumpTable(const MachineInstr &MI); 119 120 void LowerMOPS(MCStreamer &OutStreamer, const MachineInstr &MI); 121 122 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, 123 const MachineInstr &MI); 124 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, 125 const MachineInstr &MI); 126 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM, 127 const MachineInstr &MI); 128 void LowerFAULTING_OP(const MachineInstr &MI); 129 130 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI); 131 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI); 132 void LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI); 133 void LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, bool Typed); 134 135 typedef std::tuple<unsigned, bool, uint32_t, bool, uint64_t> 136 HwasanMemaccessTuple; 137 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols; 138 void LowerKCFI_CHECK(const MachineInstr &MI); 139 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI); 140 void emitHwasanMemaccessSymbols(Module &M); 141 142 void emitSled(const MachineInstr &MI, SledKind Kind); 143 144 // Emit the sequence for BRA/BLRA (authenticate + branch/call). 145 void emitPtrauthBranch(const MachineInstr *MI); 146 147 // Emit the sequence for AUT or AUTPAC. 148 void emitPtrauthAuthResign(const MachineInstr *MI); 149 150 // Emit the sequence to compute a discriminator into x17, or reuse AddrDisc. 151 unsigned emitPtrauthDiscriminator(uint16_t Disc, unsigned AddrDisc, 152 unsigned &InstsEmitted); 153 154 // Emit the sequence for LOADauthptrstatic 155 void LowerLOADauthptrstatic(const MachineInstr &MI); 156 157 // Emit the sequence for LOADgotPAC/MOVaddrPAC (either GOT adrp-ldr or 158 // adrp-add followed by PAC sign) 159 void LowerMOVaddrPAC(const MachineInstr &MI); 160 161 /// tblgen'erated driver function for lowering simple MI->MC 162 /// pseudo instructions. 163 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer, 164 const MachineInstr *MI); 165 166 void emitInstruction(const MachineInstr *MI) override; 167 168 void emitFunctionHeaderComment() override; 169 170 void getAnalysisUsage(AnalysisUsage &AU) const override { 171 AsmPrinter::getAnalysisUsage(AU); 172 AU.setPreservesAll(); 173 } 174 175 bool runOnMachineFunction(MachineFunction &MF) override { 176 AArch64FI = MF.getInfo<AArch64FunctionInfo>(); 177 STI = &MF.getSubtarget<AArch64Subtarget>(); 178 179 SetupMachineFunction(MF); 180 181 if (STI->isTargetCOFF()) { 182 bool Local = MF.getFunction().hasLocalLinkage(); 183 COFF::SymbolStorageClass Scl = 184 Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL; 185 int Type = 186 COFF::IMAGE_SYM_DTYPE_FUNCTION << COFF::SCT_COMPLEX_TYPE_SHIFT; 187 188 OutStreamer->beginCOFFSymbolDef(CurrentFnSym); 189 OutStreamer->emitCOFFSymbolStorageClass(Scl); 190 OutStreamer->emitCOFFSymbolType(Type); 191 OutStreamer->endCOFFSymbolDef(); 192 } 193 194 // Emit the rest of the function body. 195 emitFunctionBody(); 196 197 // Emit the XRay table for this function. 198 emitXRayTable(); 199 200 // We didn't modify anything. 201 return false; 202 } 203 204 const MCExpr *lowerConstant(const Constant *CV) override; 205 206 private: 207 void printOperand(const MachineInstr *MI, unsigned OpNum, raw_ostream &O); 208 bool printAsmMRegister(const MachineOperand &MO, char Mode, raw_ostream &O); 209 bool printAsmRegInClass(const MachineOperand &MO, 210 const TargetRegisterClass *RC, unsigned AltName, 211 raw_ostream &O); 212 213 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 214 const char *ExtraCode, raw_ostream &O) override; 215 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, 216 const char *ExtraCode, raw_ostream &O) override; 217 218 void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS); 219 220 void emitFunctionBodyEnd() override; 221 void emitGlobalAlias(const Module &M, const GlobalAlias &GA) override; 222 223 MCSymbol *GetCPISymbol(unsigned CPID) const override; 224 void emitEndOfAsmFile(Module &M) override; 225 226 AArch64FunctionInfo *AArch64FI = nullptr; 227 228 /// Emit the LOHs contained in AArch64FI. 229 void emitLOHs(); 230 231 /// Emit instruction to set float register to zero. 232 void emitFMov0(const MachineInstr &MI); 233 234 using MInstToMCSymbol = std::map<const MachineInstr *, MCSymbol *>; 235 236 MInstToMCSymbol LOHInstToLabel; 237 238 bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const override { 239 return ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags; 240 } 241 242 const MCSubtargetInfo *getIFuncMCSubtargetInfo() const override { 243 assert(STI); 244 return STI; 245 } 246 void emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI, 247 MCSymbol *LazyPointer) override; 248 void emitMachOIFuncStubHelperBody(Module &M, const GlobalIFunc &GI, 249 MCSymbol *LazyPointer) override; 250 }; 251 252 } // end anonymous namespace 253 254 void AArch64AsmPrinter::emitStartOfAsmFile(Module &M) { 255 const Triple &TT = TM.getTargetTriple(); 256 257 if (TT.isOSBinFormatCOFF()) { 258 // Emit an absolute @feat.00 symbol 259 MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00")); 260 OutStreamer->beginCOFFSymbolDef(S); 261 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC); 262 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL); 263 OutStreamer->endCOFFSymbolDef(); 264 int64_t Feat00Value = 0; 265 266 if (M.getModuleFlag("cfguard")) { 267 // Object is CFG-aware. 268 Feat00Value |= COFF::Feat00Flags::GuardCF; 269 } 270 271 if (M.getModuleFlag("ehcontguard")) { 272 // Object also has EHCont. 273 Feat00Value |= COFF::Feat00Flags::GuardEHCont; 274 } 275 276 if (M.getModuleFlag("ms-kernel")) { 277 // Object is compiled with /kernel. 278 Feat00Value |= COFF::Feat00Flags::Kernel; 279 } 280 281 OutStreamer->emitSymbolAttribute(S, MCSA_Global); 282 OutStreamer->emitAssignment( 283 S, MCConstantExpr::create(Feat00Value, MMI->getContext())); 284 } 285 286 if (!TT.isOSBinFormatELF()) 287 return; 288 289 // Assemble feature flags that may require creation of a note section. 290 unsigned Flags = 0; 291 if (const auto *BTE = mdconst::extract_or_null<ConstantInt>( 292 M.getModuleFlag("branch-target-enforcement"))) 293 if (!BTE->isZero()) 294 Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_BTI; 295 296 if (const auto *GCS = mdconst::extract_or_null<ConstantInt>( 297 M.getModuleFlag("guarded-control-stack"))) 298 if (!GCS->isZero()) 299 Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_GCS; 300 301 if (const auto *Sign = mdconst::extract_or_null<ConstantInt>( 302 M.getModuleFlag("sign-return-address"))) 303 if (!Sign->isZero()) 304 Flags |= ELF::GNU_PROPERTY_AARCH64_FEATURE_1_PAC; 305 306 uint64_t PAuthABIPlatform = -1; 307 if (const auto *PAP = mdconst::extract_or_null<ConstantInt>( 308 M.getModuleFlag("aarch64-elf-pauthabi-platform"))) 309 PAuthABIPlatform = PAP->getZExtValue(); 310 uint64_t PAuthABIVersion = -1; 311 if (const auto *PAV = mdconst::extract_or_null<ConstantInt>( 312 M.getModuleFlag("aarch64-elf-pauthabi-version"))) 313 PAuthABIVersion = PAV->getZExtValue(); 314 315 // Emit a .note.gnu.property section with the flags. 316 auto *TS = 317 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer()); 318 TS->emitNoteSection(Flags, PAuthABIPlatform, PAuthABIVersion); 319 } 320 321 void AArch64AsmPrinter::emitFunctionHeaderComment() { 322 const AArch64FunctionInfo *FI = MF->getInfo<AArch64FunctionInfo>(); 323 std::optional<std::string> OutlinerString = FI->getOutliningStyle(); 324 if (OutlinerString != std::nullopt) 325 OutStreamer->getCommentOS() << ' ' << OutlinerString; 326 } 327 328 void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr &MI) 329 { 330 const Function &F = MF->getFunction(); 331 if (F.hasFnAttribute("patchable-function-entry")) { 332 unsigned Num; 333 if (F.getFnAttribute("patchable-function-entry") 334 .getValueAsString() 335 .getAsInteger(10, Num)) 336 return; 337 emitNops(Num); 338 return; 339 } 340 341 emitSled(MI, SledKind::FUNCTION_ENTER); 342 } 343 344 void AArch64AsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr &MI) { 345 emitSled(MI, SledKind::FUNCTION_EXIT); 346 } 347 348 void AArch64AsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr &MI) { 349 emitSled(MI, SledKind::TAIL_CALL); 350 } 351 352 void AArch64AsmPrinter::emitSled(const MachineInstr &MI, SledKind Kind) { 353 static const int8_t NoopsInSledCount = 7; 354 // We want to emit the following pattern: 355 // 356 // .Lxray_sled_N: 357 // ALIGN 358 // B #32 359 // ; 7 NOP instructions (28 bytes) 360 // .tmpN 361 // 362 // We need the 28 bytes (7 instructions) because at runtime, we'd be patching 363 // over the full 32 bytes (8 instructions) with the following pattern: 364 // 365 // STP X0, X30, [SP, #-16]! ; push X0 and the link register to the stack 366 // LDR W17, #12 ; W17 := function ID 367 // LDR X16,#12 ; X16 := addr of __xray_FunctionEntry or __xray_FunctionExit 368 // BLR X16 ; call the tracing trampoline 369 // ;DATA: 32 bits of function ID 370 // ;DATA: lower 32 bits of the address of the trampoline 371 // ;DATA: higher 32 bits of the address of the trampoline 372 // LDP X0, X30, [SP], #16 ; pop X0 and the link register from the stack 373 // 374 OutStreamer->emitCodeAlignment(Align(4), &getSubtargetInfo()); 375 auto CurSled = OutContext.createTempSymbol("xray_sled_", true); 376 OutStreamer->emitLabel(CurSled); 377 auto Target = OutContext.createTempSymbol(); 378 379 // Emit "B #32" instruction, which jumps over the next 28 bytes. 380 // The operand has to be the number of 4-byte instructions to jump over, 381 // including the current instruction. 382 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B).addImm(8)); 383 384 for (int8_t I = 0; I < NoopsInSledCount; I++) 385 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 386 387 OutStreamer->emitLabel(Target); 388 recordSled(CurSled, MI, Kind, 2); 389 } 390 391 // Emit the following code for Intrinsic::{xray_customevent,xray_typedevent} 392 // (built-in functions __xray_customevent/__xray_typedevent). 393 // 394 // .Lxray_event_sled_N: 395 // b 1f 396 // save x0 and x1 (and also x2 for TYPED_EVENT_CALL) 397 // set up x0 and x1 (and also x2 for TYPED_EVENT_CALL) 398 // bl __xray_CustomEvent or __xray_TypedEvent 399 // restore x0 and x1 (and also x2 for TYPED_EVENT_CALL) 400 // 1: 401 // 402 // There are 6 instructions for EVENT_CALL and 9 for TYPED_EVENT_CALL. 403 // 404 // Then record a sled of kind CUSTOM_EVENT or TYPED_EVENT. 405 // After patching, b .+N will become a nop. 406 void AArch64AsmPrinter::LowerPATCHABLE_EVENT_CALL(const MachineInstr &MI, 407 bool Typed) { 408 auto &O = *OutStreamer; 409 MCSymbol *CurSled = OutContext.createTempSymbol("xray_sled_", true); 410 O.emitLabel(CurSled); 411 MCInst MovX0Op0 = MCInstBuilder(AArch64::ORRXrs) 412 .addReg(AArch64::X0) 413 .addReg(AArch64::XZR) 414 .addReg(MI.getOperand(0).getReg()) 415 .addImm(0); 416 MCInst MovX1Op1 = MCInstBuilder(AArch64::ORRXrs) 417 .addReg(AArch64::X1) 418 .addReg(AArch64::XZR) 419 .addReg(MI.getOperand(1).getReg()) 420 .addImm(0); 421 bool MachO = TM.getTargetTriple().isOSBinFormatMachO(); 422 auto *Sym = MCSymbolRefExpr::create( 423 OutContext.getOrCreateSymbol( 424 Twine(MachO ? "_" : "") + 425 (Typed ? "__xray_TypedEvent" : "__xray_CustomEvent")), 426 OutContext); 427 if (Typed) { 428 O.AddComment("Begin XRay typed event"); 429 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(9)); 430 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre) 431 .addReg(AArch64::SP) 432 .addReg(AArch64::X0) 433 .addReg(AArch64::X1) 434 .addReg(AArch64::SP) 435 .addImm(-4)); 436 EmitToStreamer(O, MCInstBuilder(AArch64::STRXui) 437 .addReg(AArch64::X2) 438 .addReg(AArch64::SP) 439 .addImm(2)); 440 EmitToStreamer(O, MovX0Op0); 441 EmitToStreamer(O, MovX1Op1); 442 EmitToStreamer(O, MCInstBuilder(AArch64::ORRXrs) 443 .addReg(AArch64::X2) 444 .addReg(AArch64::XZR) 445 .addReg(MI.getOperand(2).getReg()) 446 .addImm(0)); 447 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym)); 448 EmitToStreamer(O, MCInstBuilder(AArch64::LDRXui) 449 .addReg(AArch64::X2) 450 .addReg(AArch64::SP) 451 .addImm(2)); 452 O.AddComment("End XRay typed event"); 453 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost) 454 .addReg(AArch64::SP) 455 .addReg(AArch64::X0) 456 .addReg(AArch64::X1) 457 .addReg(AArch64::SP) 458 .addImm(4)); 459 460 recordSled(CurSled, MI, SledKind::TYPED_EVENT, 2); 461 } else { 462 O.AddComment("Begin XRay custom event"); 463 EmitToStreamer(O, MCInstBuilder(AArch64::B).addImm(6)); 464 EmitToStreamer(O, MCInstBuilder(AArch64::STPXpre) 465 .addReg(AArch64::SP) 466 .addReg(AArch64::X0) 467 .addReg(AArch64::X1) 468 .addReg(AArch64::SP) 469 .addImm(-2)); 470 EmitToStreamer(O, MovX0Op0); 471 EmitToStreamer(O, MovX1Op1); 472 EmitToStreamer(O, MCInstBuilder(AArch64::BL).addExpr(Sym)); 473 O.AddComment("End XRay custom event"); 474 EmitToStreamer(O, MCInstBuilder(AArch64::LDPXpost) 475 .addReg(AArch64::SP) 476 .addReg(AArch64::X0) 477 .addReg(AArch64::X1) 478 .addReg(AArch64::SP) 479 .addImm(2)); 480 481 recordSled(CurSled, MI, SledKind::CUSTOM_EVENT, 2); 482 } 483 } 484 485 void AArch64AsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) { 486 Register AddrReg = MI.getOperand(0).getReg(); 487 assert(std::next(MI.getIterator())->isCall() && 488 "KCFI_CHECK not followed by a call instruction"); 489 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg && 490 "KCFI_CHECK call target doesn't match call operand"); 491 492 // Default to using the intra-procedure-call temporary registers for 493 // comparing the hashes. 494 unsigned ScratchRegs[] = {AArch64::W16, AArch64::W17}; 495 if (AddrReg == AArch64::XZR) { 496 // Checking XZR makes no sense. Instead of emitting a load, zero 497 // ScratchRegs[0] and use it for the ESR AddrIndex below. 498 AddrReg = getXRegFromWReg(ScratchRegs[0]); 499 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) 500 .addReg(AddrReg) 501 .addReg(AArch64::XZR) 502 .addReg(AArch64::XZR) 503 .addImm(0)); 504 } else { 505 // If one of the scratch registers is used for the call target (e.g. 506 // with AArch64::TCRETURNriBTI), we can clobber another caller-saved 507 // temporary register instead (in this case, AArch64::W9) as the check 508 // is immediately followed by the call instruction. 509 for (auto &Reg : ScratchRegs) { 510 if (Reg == getWRegFromXReg(AddrReg)) { 511 Reg = AArch64::W9; 512 break; 513 } 514 } 515 assert(ScratchRegs[0] != AddrReg && ScratchRegs[1] != AddrReg && 516 "Invalid scratch registers for KCFI_CHECK"); 517 518 // Adjust the offset for patchable-function-prefix. This assumes that 519 // patchable-function-prefix is the same for all functions. 520 int64_t PrefixNops = 0; 521 (void)MI.getMF() 522 ->getFunction() 523 .getFnAttribute("patchable-function-prefix") 524 .getValueAsString() 525 .getAsInteger(10, PrefixNops); 526 527 // Load the target function type hash. 528 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDURWi) 529 .addReg(ScratchRegs[0]) 530 .addReg(AddrReg) 531 .addImm(-(PrefixNops * 4 + 4))); 532 } 533 534 // Load the expected type hash. 535 const int64_t Type = MI.getOperand(1).getImm(); 536 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi) 537 .addReg(ScratchRegs[1]) 538 .addReg(ScratchRegs[1]) 539 .addImm(Type & 0xFFFF) 540 .addImm(0)); 541 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKWi) 542 .addReg(ScratchRegs[1]) 543 .addReg(ScratchRegs[1]) 544 .addImm((Type >> 16) & 0xFFFF) 545 .addImm(16)); 546 547 // Compare the hashes and trap if there's a mismatch. 548 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSWrs) 549 .addReg(AArch64::WZR) 550 .addReg(ScratchRegs[0]) 551 .addReg(ScratchRegs[1]) 552 .addImm(0)); 553 554 MCSymbol *Pass = OutContext.createTempSymbol(); 555 EmitToStreamer(*OutStreamer, 556 MCInstBuilder(AArch64::Bcc) 557 .addImm(AArch64CC::EQ) 558 .addExpr(MCSymbolRefExpr::create(Pass, OutContext))); 559 560 // The base ESR is 0x8000 and the register information is encoded in bits 561 // 0-9 as follows: 562 // - 0-4: n, where the register Xn contains the target address 563 // - 5-9: m, where the register Wm contains the expected type hash 564 // Where n, m are in [0, 30]. 565 unsigned TypeIndex = ScratchRegs[1] - AArch64::W0; 566 unsigned AddrIndex; 567 switch (AddrReg) { 568 default: 569 AddrIndex = AddrReg - AArch64::X0; 570 break; 571 case AArch64::FP: 572 AddrIndex = 29; 573 break; 574 case AArch64::LR: 575 AddrIndex = 30; 576 break; 577 } 578 579 assert(AddrIndex < 31 && TypeIndex < 31); 580 581 unsigned ESR = 0x8000 | ((TypeIndex & 31) << 5) | (AddrIndex & 31); 582 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BRK).addImm(ESR)); 583 OutStreamer->emitLabel(Pass); 584 } 585 586 void AArch64AsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) { 587 Register Reg = MI.getOperand(0).getReg(); 588 bool IsShort = 589 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES) || 590 (MI.getOpcode() == 591 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW)); 592 uint32_t AccessInfo = MI.getOperand(1).getImm(); 593 bool IsFixedShadow = 594 ((MI.getOpcode() == AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW) || 595 (MI.getOpcode() == 596 AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW)); 597 uint64_t FixedShadowOffset = IsFixedShadow ? MI.getOperand(2).getImm() : 0; 598 599 MCSymbol *&Sym = HwasanMemaccessSymbols[HwasanMemaccessTuple( 600 Reg, IsShort, AccessInfo, IsFixedShadow, FixedShadowOffset)]; 601 if (!Sym) { 602 // FIXME: Make this work on non-ELF. 603 if (!TM.getTargetTriple().isOSBinFormatELF()) 604 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF"); 605 606 std::string SymName = "__hwasan_check_x" + utostr(Reg - AArch64::X0) + "_" + 607 utostr(AccessInfo); 608 if (IsFixedShadow) 609 SymName += "_fixed_" + utostr(FixedShadowOffset); 610 if (IsShort) 611 SymName += "_short_v2"; 612 Sym = OutContext.getOrCreateSymbol(SymName); 613 } 614 615 EmitToStreamer(*OutStreamer, 616 MCInstBuilder(AArch64::BL) 617 .addExpr(MCSymbolRefExpr::create(Sym, OutContext))); 618 } 619 620 void AArch64AsmPrinter::emitHwasanMemaccessSymbols(Module &M) { 621 if (HwasanMemaccessSymbols.empty()) 622 return; 623 624 const Triple &TT = TM.getTargetTriple(); 625 assert(TT.isOSBinFormatELF()); 626 std::unique_ptr<MCSubtargetInfo> STI( 627 TM.getTarget().createMCSubtargetInfo(TT.str(), "", "")); 628 assert(STI && "Unable to create subtarget info"); 629 630 MCSymbol *HwasanTagMismatchV1Sym = 631 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch"); 632 MCSymbol *HwasanTagMismatchV2Sym = 633 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2"); 634 635 const MCSymbolRefExpr *HwasanTagMismatchV1Ref = 636 MCSymbolRefExpr::create(HwasanTagMismatchV1Sym, OutContext); 637 const MCSymbolRefExpr *HwasanTagMismatchV2Ref = 638 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext); 639 640 for (auto &P : HwasanMemaccessSymbols) { 641 unsigned Reg = std::get<0>(P.first); 642 bool IsShort = std::get<1>(P.first); 643 uint32_t AccessInfo = std::get<2>(P.first); 644 bool IsFixedShadow = std::get<3>(P.first); 645 uint64_t FixedShadowOffset = std::get<4>(P.first); 646 const MCSymbolRefExpr *HwasanTagMismatchRef = 647 IsShort ? HwasanTagMismatchV2Ref : HwasanTagMismatchV1Ref; 648 MCSymbol *Sym = P.second; 649 650 bool HasMatchAllTag = 651 (AccessInfo >> HWASanAccessInfo::HasMatchAllShift) & 1; 652 uint8_t MatchAllTag = 653 (AccessInfo >> HWASanAccessInfo::MatchAllShift) & 0xff; 654 unsigned Size = 655 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf); 656 bool CompileKernel = 657 (AccessInfo >> HWASanAccessInfo::CompileKernelShift) & 1; 658 659 OutStreamer->switchSection(OutContext.getELFSection( 660 ".text.hot", ELF::SHT_PROGBITS, 661 ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(), 662 /*IsComdat=*/true)); 663 664 OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction); 665 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak); 666 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden); 667 OutStreamer->emitLabel(Sym); 668 669 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SBFMXri) 670 .addReg(AArch64::X16) 671 .addReg(Reg) 672 .addImm(4) 673 .addImm(55), 674 *STI); 675 676 if (IsFixedShadow) { 677 // Aarch64 makes it difficult to embed large constants in the code. 678 // Fortuitously, kShadowBaseAlignment == 32, so we use the 32-bit 679 // left-shift option in the MOV instruction. Combined with the 16-bit 680 // immediate, this is enough to represent any offset up to 2**48. 681 OutStreamer->emitInstruction(MCInstBuilder(AArch64::MOVZXi) 682 .addReg(AArch64::X17) 683 .addImm(FixedShadowOffset >> 32) 684 .addImm(32), 685 *STI); 686 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBroX) 687 .addReg(AArch64::W16) 688 .addReg(AArch64::X17) 689 .addReg(AArch64::X16) 690 .addImm(0) 691 .addImm(0), 692 *STI); 693 } else { 694 OutStreamer->emitInstruction( 695 MCInstBuilder(AArch64::LDRBBroX) 696 .addReg(AArch64::W16) 697 .addReg(IsShort ? AArch64::X20 : AArch64::X9) 698 .addReg(AArch64::X16) 699 .addImm(0) 700 .addImm(0), 701 *STI); 702 } 703 704 OutStreamer->emitInstruction( 705 MCInstBuilder(AArch64::SUBSXrs) 706 .addReg(AArch64::XZR) 707 .addReg(AArch64::X16) 708 .addReg(Reg) 709 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSR, 56)), 710 *STI); 711 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol(); 712 OutStreamer->emitInstruction( 713 MCInstBuilder(AArch64::Bcc) 714 .addImm(AArch64CC::NE) 715 .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym, 716 OutContext)), 717 *STI); 718 MCSymbol *ReturnSym = OutContext.createTempSymbol(); 719 OutStreamer->emitLabel(ReturnSym); 720 OutStreamer->emitInstruction( 721 MCInstBuilder(AArch64::RET).addReg(AArch64::LR), *STI); 722 OutStreamer->emitLabel(HandleMismatchOrPartialSym); 723 724 if (HasMatchAllTag) { 725 OutStreamer->emitInstruction(MCInstBuilder(AArch64::UBFMXri) 726 .addReg(AArch64::X17) 727 .addReg(Reg) 728 .addImm(56) 729 .addImm(63), 730 *STI); 731 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSXri) 732 .addReg(AArch64::XZR) 733 .addReg(AArch64::X17) 734 .addImm(MatchAllTag) 735 .addImm(0), 736 *STI); 737 OutStreamer->emitInstruction( 738 MCInstBuilder(AArch64::Bcc) 739 .addImm(AArch64CC::EQ) 740 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)), 741 *STI); 742 } 743 744 if (IsShort) { 745 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWri) 746 .addReg(AArch64::WZR) 747 .addReg(AArch64::W16) 748 .addImm(15) 749 .addImm(0), 750 *STI); 751 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol(); 752 OutStreamer->emitInstruction( 753 MCInstBuilder(AArch64::Bcc) 754 .addImm(AArch64CC::HI) 755 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)), 756 *STI); 757 758 OutStreamer->emitInstruction( 759 MCInstBuilder(AArch64::ANDXri) 760 .addReg(AArch64::X17) 761 .addReg(Reg) 762 .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)), 763 *STI); 764 if (Size != 1) 765 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) 766 .addReg(AArch64::X17) 767 .addReg(AArch64::X17) 768 .addImm(Size - 1) 769 .addImm(0), 770 *STI); 771 OutStreamer->emitInstruction(MCInstBuilder(AArch64::SUBSWrs) 772 .addReg(AArch64::WZR) 773 .addReg(AArch64::W16) 774 .addReg(AArch64::W17) 775 .addImm(0), 776 *STI); 777 OutStreamer->emitInstruction( 778 MCInstBuilder(AArch64::Bcc) 779 .addImm(AArch64CC::LS) 780 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)), 781 *STI); 782 783 OutStreamer->emitInstruction( 784 MCInstBuilder(AArch64::ORRXri) 785 .addReg(AArch64::X16) 786 .addReg(Reg) 787 .addImm(AArch64_AM::encodeLogicalImmediate(0xf, 64)), 788 *STI); 789 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRBBui) 790 .addReg(AArch64::W16) 791 .addReg(AArch64::X16) 792 .addImm(0), 793 *STI); 794 OutStreamer->emitInstruction( 795 MCInstBuilder(AArch64::SUBSXrs) 796 .addReg(AArch64::XZR) 797 .addReg(AArch64::X16) 798 .addReg(Reg) 799 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSR, 56)), 800 *STI); 801 OutStreamer->emitInstruction( 802 MCInstBuilder(AArch64::Bcc) 803 .addImm(AArch64CC::EQ) 804 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)), 805 *STI); 806 807 OutStreamer->emitLabel(HandleMismatchSym); 808 } 809 810 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) 811 .addReg(AArch64::SP) 812 .addReg(AArch64::X0) 813 .addReg(AArch64::X1) 814 .addReg(AArch64::SP) 815 .addImm(-32), 816 *STI); 817 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXi) 818 .addReg(AArch64::FP) 819 .addReg(AArch64::LR) 820 .addReg(AArch64::SP) 821 .addImm(29), 822 *STI); 823 824 if (Reg != AArch64::X0) 825 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ORRXrs) 826 .addReg(AArch64::X0) 827 .addReg(AArch64::XZR) 828 .addReg(Reg) 829 .addImm(0), 830 *STI); 831 OutStreamer->emitInstruction( 832 MCInstBuilder(AArch64::MOVZXi) 833 .addReg(AArch64::X1) 834 .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask) 835 .addImm(0), 836 *STI); 837 838 if (CompileKernel) { 839 // The Linux kernel's dynamic loader doesn't support GOT relative 840 // relocations, but it doesn't support late binding either, so just call 841 // the function directly. 842 OutStreamer->emitInstruction( 843 MCInstBuilder(AArch64::B).addExpr(HwasanTagMismatchRef), *STI); 844 } else { 845 // Intentionally load the GOT entry and branch to it, rather than possibly 846 // late binding the function, which may clobber the registers before we 847 // have a chance to save them. 848 OutStreamer->emitInstruction( 849 MCInstBuilder(AArch64::ADRP) 850 .addReg(AArch64::X16) 851 .addExpr(AArch64MCExpr::create( 852 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_PAGE, 853 OutContext)), 854 *STI); 855 OutStreamer->emitInstruction( 856 MCInstBuilder(AArch64::LDRXui) 857 .addReg(AArch64::X16) 858 .addReg(AArch64::X16) 859 .addExpr(AArch64MCExpr::create( 860 HwasanTagMismatchRef, AArch64MCExpr::VariantKind::VK_GOT_LO12, 861 OutContext)), 862 *STI); 863 OutStreamer->emitInstruction( 864 MCInstBuilder(AArch64::BR).addReg(AArch64::X16), *STI); 865 } 866 } 867 } 868 869 static void emitAuthenticatedPointer(MCStreamer &OutStreamer, 870 MCSymbol *StubLabel, 871 const MCExpr *StubAuthPtrRef) { 872 // sym$auth_ptr$key$disc: 873 OutStreamer.emitLabel(StubLabel); 874 OutStreamer.emitValue(StubAuthPtrRef, /*size=*/8); 875 } 876 877 void AArch64AsmPrinter::emitEndOfAsmFile(Module &M) { 878 emitHwasanMemaccessSymbols(M); 879 880 const Triple &TT = TM.getTargetTriple(); 881 if (TT.isOSBinFormatMachO()) { 882 // Output authenticated pointers as indirect symbols, if we have any. 883 MachineModuleInfoMachO &MMIMacho = 884 MMI->getObjFileInfo<MachineModuleInfoMachO>(); 885 886 auto Stubs = MMIMacho.getAuthGVStubList(); 887 888 if (!Stubs.empty()) { 889 // Switch to the "__auth_ptr" section. 890 OutStreamer->switchSection( 891 OutContext.getMachOSection("__DATA", "__auth_ptr", MachO::S_REGULAR, 892 SectionKind::getMetadata())); 893 emitAlignment(Align(8)); 894 895 for (const auto &Stub : Stubs) 896 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second); 897 898 OutStreamer->addBlankLine(); 899 } 900 901 // Funny Darwin hack: This flag tells the linker that no global symbols 902 // contain code that falls through to other global symbols (e.g. the obvious 903 // implementation of multiple entry points). If this doesn't occur, the 904 // linker can safely perform dead code stripping. Since LLVM never 905 // generates code that does this, it is always safe to set. 906 OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols); 907 } 908 909 if (TT.isOSBinFormatELF()) { 910 // Output authenticated pointers as indirect symbols, if we have any. 911 MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>(); 912 913 auto Stubs = MMIELF.getAuthGVStubList(); 914 915 if (!Stubs.empty()) { 916 const TargetLoweringObjectFile &TLOF = getObjFileLowering(); 917 OutStreamer->switchSection(TLOF.getDataSection()); 918 emitAlignment(Align(8)); 919 920 for (const auto &Stub : Stubs) 921 emitAuthenticatedPointer(*OutStreamer, Stub.first, Stub.second); 922 923 OutStreamer->addBlankLine(); 924 } 925 } 926 927 // Emit stack and fault map information. 928 FM.serializeToFaultMapSection(); 929 930 } 931 932 void AArch64AsmPrinter::emitLOHs() { 933 SmallVector<MCSymbol *, 3> MCArgs; 934 935 for (const auto &D : AArch64FI->getLOHContainer()) { 936 for (const MachineInstr *MI : D.getArgs()) { 937 MInstToMCSymbol::iterator LabelIt = LOHInstToLabel.find(MI); 938 assert(LabelIt != LOHInstToLabel.end() && 939 "Label hasn't been inserted for LOH related instruction"); 940 MCArgs.push_back(LabelIt->second); 941 } 942 OutStreamer->emitLOHDirective(D.getKind(), MCArgs); 943 MCArgs.clear(); 944 } 945 } 946 947 void AArch64AsmPrinter::emitFunctionBodyEnd() { 948 if (!AArch64FI->getLOHRelated().empty()) 949 emitLOHs(); 950 } 951 952 /// GetCPISymbol - Return the symbol for the specified constant pool entry. 953 MCSymbol *AArch64AsmPrinter::GetCPISymbol(unsigned CPID) const { 954 // Darwin uses a linker-private symbol name for constant-pools (to 955 // avoid addends on the relocation?), ELF has no such concept and 956 // uses a normal private symbol. 957 if (!getDataLayout().getLinkerPrivateGlobalPrefix().empty()) 958 return OutContext.getOrCreateSymbol( 959 Twine(getDataLayout().getLinkerPrivateGlobalPrefix()) + "CPI" + 960 Twine(getFunctionNumber()) + "_" + Twine(CPID)); 961 962 return AsmPrinter::GetCPISymbol(CPID); 963 } 964 965 void AArch64AsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNum, 966 raw_ostream &O) { 967 const MachineOperand &MO = MI->getOperand(OpNum); 968 switch (MO.getType()) { 969 default: 970 llvm_unreachable("<unknown operand type>"); 971 case MachineOperand::MO_Register: { 972 Register Reg = MO.getReg(); 973 assert(Reg.isPhysical()); 974 assert(!MO.getSubReg() && "Subregs should be eliminated!"); 975 O << AArch64InstPrinter::getRegisterName(Reg); 976 break; 977 } 978 case MachineOperand::MO_Immediate: { 979 O << MO.getImm(); 980 break; 981 } 982 case MachineOperand::MO_GlobalAddress: { 983 PrintSymbolOperand(MO, O); 984 break; 985 } 986 case MachineOperand::MO_BlockAddress: { 987 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress()); 988 Sym->print(O, MAI); 989 break; 990 } 991 } 992 } 993 994 bool AArch64AsmPrinter::printAsmMRegister(const MachineOperand &MO, char Mode, 995 raw_ostream &O) { 996 Register Reg = MO.getReg(); 997 switch (Mode) { 998 default: 999 return true; // Unknown mode. 1000 case 'w': 1001 Reg = getWRegFromXReg(Reg); 1002 break; 1003 case 'x': 1004 Reg = getXRegFromWReg(Reg); 1005 break; 1006 case 't': 1007 Reg = getXRegFromXRegTuple(Reg); 1008 break; 1009 } 1010 1011 O << AArch64InstPrinter::getRegisterName(Reg); 1012 return false; 1013 } 1014 1015 // Prints the register in MO using class RC using the offset in the 1016 // new register class. This should not be used for cross class 1017 // printing. 1018 bool AArch64AsmPrinter::printAsmRegInClass(const MachineOperand &MO, 1019 const TargetRegisterClass *RC, 1020 unsigned AltName, raw_ostream &O) { 1021 assert(MO.isReg() && "Should only get here with a register!"); 1022 const TargetRegisterInfo *RI = STI->getRegisterInfo(); 1023 Register Reg = MO.getReg(); 1024 unsigned RegToPrint = RC->getRegister(RI->getEncodingValue(Reg)); 1025 if (!RI->regsOverlap(RegToPrint, Reg)) 1026 return true; 1027 O << AArch64InstPrinter::getRegisterName(RegToPrint, AltName); 1028 return false; 1029 } 1030 1031 bool AArch64AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 1032 const char *ExtraCode, raw_ostream &O) { 1033 const MachineOperand &MO = MI->getOperand(OpNum); 1034 1035 // First try the generic code, which knows about modifiers like 'c' and 'n'. 1036 if (!AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O)) 1037 return false; 1038 1039 // Does this asm operand have a single letter operand modifier? 1040 if (ExtraCode && ExtraCode[0]) { 1041 if (ExtraCode[1] != 0) 1042 return true; // Unknown modifier. 1043 1044 switch (ExtraCode[0]) { 1045 default: 1046 return true; // Unknown modifier. 1047 case 'w': // Print W register 1048 case 'x': // Print X register 1049 if (MO.isReg()) 1050 return printAsmMRegister(MO, ExtraCode[0], O); 1051 if (MO.isImm() && MO.getImm() == 0) { 1052 unsigned Reg = ExtraCode[0] == 'w' ? AArch64::WZR : AArch64::XZR; 1053 O << AArch64InstPrinter::getRegisterName(Reg); 1054 return false; 1055 } 1056 printOperand(MI, OpNum, O); 1057 return false; 1058 case 'b': // Print B register. 1059 case 'h': // Print H register. 1060 case 's': // Print S register. 1061 case 'd': // Print D register. 1062 case 'q': // Print Q register. 1063 case 'z': // Print Z register. 1064 if (MO.isReg()) { 1065 const TargetRegisterClass *RC; 1066 switch (ExtraCode[0]) { 1067 case 'b': 1068 RC = &AArch64::FPR8RegClass; 1069 break; 1070 case 'h': 1071 RC = &AArch64::FPR16RegClass; 1072 break; 1073 case 's': 1074 RC = &AArch64::FPR32RegClass; 1075 break; 1076 case 'd': 1077 RC = &AArch64::FPR64RegClass; 1078 break; 1079 case 'q': 1080 RC = &AArch64::FPR128RegClass; 1081 break; 1082 case 'z': 1083 RC = &AArch64::ZPRRegClass; 1084 break; 1085 default: 1086 return true; 1087 } 1088 return printAsmRegInClass(MO, RC, AArch64::NoRegAltName, O); 1089 } 1090 printOperand(MI, OpNum, O); 1091 return false; 1092 } 1093 } 1094 1095 // According to ARM, we should emit x and v registers unless we have a 1096 // modifier. 1097 if (MO.isReg()) { 1098 Register Reg = MO.getReg(); 1099 1100 // If this is a w or x register, print an x register. 1101 if (AArch64::GPR32allRegClass.contains(Reg) || 1102 AArch64::GPR64allRegClass.contains(Reg)) 1103 return printAsmMRegister(MO, 'x', O); 1104 1105 // If this is an x register tuple, print an x register. 1106 if (AArch64::GPR64x8ClassRegClass.contains(Reg)) 1107 return printAsmMRegister(MO, 't', O); 1108 1109 unsigned AltName = AArch64::NoRegAltName; 1110 const TargetRegisterClass *RegClass; 1111 if (AArch64::ZPRRegClass.contains(Reg)) { 1112 RegClass = &AArch64::ZPRRegClass; 1113 } else if (AArch64::PPRRegClass.contains(Reg)) { 1114 RegClass = &AArch64::PPRRegClass; 1115 } else if (AArch64::PNRRegClass.contains(Reg)) { 1116 RegClass = &AArch64::PNRRegClass; 1117 } else { 1118 RegClass = &AArch64::FPR128RegClass; 1119 AltName = AArch64::vreg; 1120 } 1121 1122 // If this is a b, h, s, d, or q register, print it as a v register. 1123 return printAsmRegInClass(MO, RegClass, AltName, O); 1124 } 1125 1126 printOperand(MI, OpNum, O); 1127 return false; 1128 } 1129 1130 bool AArch64AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 1131 unsigned OpNum, 1132 const char *ExtraCode, 1133 raw_ostream &O) { 1134 if (ExtraCode && ExtraCode[0] && ExtraCode[0] != 'a') 1135 return true; // Unknown modifier. 1136 1137 const MachineOperand &MO = MI->getOperand(OpNum); 1138 assert(MO.isReg() && "unexpected inline asm memory operand"); 1139 O << "[" << AArch64InstPrinter::getRegisterName(MO.getReg()) << "]"; 1140 return false; 1141 } 1142 1143 void AArch64AsmPrinter::PrintDebugValueComment(const MachineInstr *MI, 1144 raw_ostream &OS) { 1145 unsigned NOps = MI->getNumOperands(); 1146 assert(NOps == 4); 1147 OS << '\t' << MAI->getCommentString() << "DEBUG_VALUE: "; 1148 // cast away const; DIetc do not take const operands for some reason. 1149 OS << MI->getDebugVariable()->getName(); 1150 OS << " <- "; 1151 // Frame address. Currently handles register +- offset only. 1152 assert(MI->isIndirectDebugValue()); 1153 OS << '['; 1154 for (unsigned I = 0, E = std::distance(MI->debug_operands().begin(), 1155 MI->debug_operands().end()); 1156 I < E; ++I) { 1157 if (I != 0) 1158 OS << ", "; 1159 printOperand(MI, I, OS); 1160 } 1161 OS << ']'; 1162 OS << "+"; 1163 printOperand(MI, NOps - 2, OS); 1164 } 1165 1166 void AArch64AsmPrinter::emitJumpTableInfo() { 1167 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); 1168 if (!MJTI) return; 1169 1170 const std::vector<MachineJumpTableEntry> &JT = MJTI->getJumpTables(); 1171 if (JT.empty()) return; 1172 1173 const TargetLoweringObjectFile &TLOF = getObjFileLowering(); 1174 MCSection *ReadOnlySec = TLOF.getSectionForJumpTable(MF->getFunction(), TM); 1175 OutStreamer->switchSection(ReadOnlySec); 1176 1177 auto AFI = MF->getInfo<AArch64FunctionInfo>(); 1178 for (unsigned JTI = 0, e = JT.size(); JTI != e; ++JTI) { 1179 const std::vector<MachineBasicBlock*> &JTBBs = JT[JTI].MBBs; 1180 1181 // If this jump table was deleted, ignore it. 1182 if (JTBBs.empty()) continue; 1183 1184 unsigned Size = AFI->getJumpTableEntrySize(JTI); 1185 emitAlignment(Align(Size)); 1186 OutStreamer->emitLabel(GetJTISymbol(JTI)); 1187 1188 const MCSymbol *BaseSym = AArch64FI->getJumpTableEntryPCRelSymbol(JTI); 1189 const MCExpr *Base = MCSymbolRefExpr::create(BaseSym, OutContext); 1190 1191 for (auto *JTBB : JTBBs) { 1192 const MCExpr *Value = 1193 MCSymbolRefExpr::create(JTBB->getSymbol(), OutContext); 1194 1195 // Each entry is: 1196 // .byte/.hword (LBB - Lbase)>>2 1197 // or plain: 1198 // .word LBB - Lbase 1199 Value = MCBinaryExpr::createSub(Value, Base, OutContext); 1200 if (Size != 4) 1201 Value = MCBinaryExpr::createLShr( 1202 Value, MCConstantExpr::create(2, OutContext), OutContext); 1203 1204 OutStreamer->emitValue(Value, Size); 1205 } 1206 } 1207 } 1208 1209 std::tuple<const MCSymbol *, uint64_t, const MCSymbol *, 1210 codeview::JumpTableEntrySize> 1211 AArch64AsmPrinter::getCodeViewJumpTableInfo(int JTI, 1212 const MachineInstr *BranchInstr, 1213 const MCSymbol *BranchLabel) const { 1214 const auto AFI = MF->getInfo<AArch64FunctionInfo>(); 1215 const auto Base = AArch64FI->getJumpTableEntryPCRelSymbol(JTI); 1216 codeview::JumpTableEntrySize EntrySize; 1217 switch (AFI->getJumpTableEntrySize(JTI)) { 1218 case 1: 1219 EntrySize = codeview::JumpTableEntrySize::UInt8ShiftLeft; 1220 break; 1221 case 2: 1222 EntrySize = codeview::JumpTableEntrySize::UInt16ShiftLeft; 1223 break; 1224 case 4: 1225 EntrySize = codeview::JumpTableEntrySize::Int32; 1226 break; 1227 default: 1228 llvm_unreachable("Unexpected jump table entry size"); 1229 } 1230 return std::make_tuple(Base, 0, BranchLabel, EntrySize); 1231 } 1232 1233 void AArch64AsmPrinter::emitFunctionEntryLabel() { 1234 if (MF->getFunction().getCallingConv() == CallingConv::AArch64_VectorCall || 1235 MF->getFunction().getCallingConv() == 1236 CallingConv::AArch64_SVE_VectorCall || 1237 MF->getInfo<AArch64FunctionInfo>()->isSVECC()) { 1238 auto *TS = 1239 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer()); 1240 TS->emitDirectiveVariantPCS(CurrentFnSym); 1241 } 1242 1243 AsmPrinter::emitFunctionEntryLabel(); 1244 1245 if (TM.getTargetTriple().isWindowsArm64EC() && 1246 !MF->getFunction().hasLocalLinkage()) { 1247 // For ARM64EC targets, a function definition's name is mangled differently 1248 // from the normal symbol, emit required aliases here. 1249 auto emitFunctionAlias = [&](MCSymbol *Src, MCSymbol *Dst) { 1250 OutStreamer->emitSymbolAttribute(Src, MCSA_WeakAntiDep); 1251 OutStreamer->emitAssignment( 1252 Src, MCSymbolRefExpr::create(Dst, MCSymbolRefExpr::VK_None, 1253 MMI->getContext())); 1254 }; 1255 1256 auto getSymbolFromMetadata = [&](StringRef Name) { 1257 MCSymbol *Sym = nullptr; 1258 if (MDNode *Node = MF->getFunction().getMetadata(Name)) { 1259 StringRef NameStr = cast<MDString>(Node->getOperand(0))->getString(); 1260 Sym = MMI->getContext().getOrCreateSymbol(NameStr); 1261 } 1262 return Sym; 1263 }; 1264 1265 if (MCSymbol *UnmangledSym = 1266 getSymbolFromMetadata("arm64ec_unmangled_name")) { 1267 MCSymbol *ECMangledSym = getSymbolFromMetadata("arm64ec_ecmangled_name"); 1268 1269 if (ECMangledSym) { 1270 // An external function, emit the alias from the unmangled symbol to 1271 // mangled symbol name and the alias from the mangled symbol to guest 1272 // exit thunk. 1273 emitFunctionAlias(UnmangledSym, ECMangledSym); 1274 emitFunctionAlias(ECMangledSym, CurrentFnSym); 1275 } else { 1276 // A function implementation, emit the alias from the unmangled symbol 1277 // to mangled symbol name. 1278 emitFunctionAlias(UnmangledSym, CurrentFnSym); 1279 } 1280 } 1281 } 1282 } 1283 1284 void AArch64AsmPrinter::emitGlobalAlias(const Module &M, 1285 const GlobalAlias &GA) { 1286 if (auto F = dyn_cast_or_null<Function>(GA.getAliasee())) { 1287 // Global aliases must point to a definition, but unmangled patchable 1288 // symbols are special and need to point to an undefined symbol with "EXP+" 1289 // prefix. Such undefined symbol is resolved by the linker by creating 1290 // x86 thunk that jumps back to the actual EC target. 1291 if (MDNode *Node = F->getMetadata("arm64ec_exp_name")) { 1292 StringRef ExpStr = cast<MDString>(Node->getOperand(0))->getString(); 1293 MCSymbol *ExpSym = MMI->getContext().getOrCreateSymbol(ExpStr); 1294 MCSymbol *Sym = MMI->getContext().getOrCreateSymbol(GA.getName()); 1295 1296 OutStreamer->beginCOFFSymbolDef(ExpSym); 1297 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL); 1298 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION 1299 << COFF::SCT_COMPLEX_TYPE_SHIFT); 1300 OutStreamer->endCOFFSymbolDef(); 1301 1302 OutStreamer->beginCOFFSymbolDef(Sym); 1303 OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_EXTERNAL); 1304 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION 1305 << COFF::SCT_COMPLEX_TYPE_SHIFT); 1306 OutStreamer->endCOFFSymbolDef(); 1307 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak); 1308 OutStreamer->emitAssignment( 1309 Sym, MCSymbolRefExpr::create(ExpSym, MCSymbolRefExpr::VK_None, 1310 MMI->getContext())); 1311 return; 1312 } 1313 } 1314 AsmPrinter::emitGlobalAlias(M, GA); 1315 } 1316 1317 /// Small jump tables contain an unsigned byte or half, representing the offset 1318 /// from the lowest-addressed possible destination to the desired basic 1319 /// block. Since all instructions are 4-byte aligned, this is further compressed 1320 /// by counting in instructions rather than bytes (i.e. divided by 4). So, to 1321 /// materialize the correct destination we need: 1322 /// 1323 /// adr xDest, .LBB0_0 1324 /// ldrb wScratch, [xTable, xEntry] (with "lsl #1" for ldrh). 1325 /// add xDest, xDest, xScratch (with "lsl #2" for smaller entries) 1326 void AArch64AsmPrinter::LowerJumpTableDest(llvm::MCStreamer &OutStreamer, 1327 const llvm::MachineInstr &MI) { 1328 Register DestReg = MI.getOperand(0).getReg(); 1329 Register ScratchReg = MI.getOperand(1).getReg(); 1330 Register ScratchRegW = 1331 STI->getRegisterInfo()->getSubReg(ScratchReg, AArch64::sub_32); 1332 Register TableReg = MI.getOperand(2).getReg(); 1333 Register EntryReg = MI.getOperand(3).getReg(); 1334 int JTIdx = MI.getOperand(4).getIndex(); 1335 int Size = AArch64FI->getJumpTableEntrySize(JTIdx); 1336 1337 // This has to be first because the compression pass based its reachability 1338 // calculations on the start of the JumpTableDest instruction. 1339 auto Label = 1340 MF->getInfo<AArch64FunctionInfo>()->getJumpTableEntryPCRelSymbol(JTIdx); 1341 1342 // If we don't already have a symbol to use as the base, use the ADR 1343 // instruction itself. 1344 if (!Label) { 1345 Label = MF->getContext().createTempSymbol(); 1346 AArch64FI->setJumpTableEntryInfo(JTIdx, Size, Label); 1347 OutStreamer.emitLabel(Label); 1348 } 1349 1350 auto LabelExpr = MCSymbolRefExpr::create(Label, MF->getContext()); 1351 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADR) 1352 .addReg(DestReg) 1353 .addExpr(LabelExpr)); 1354 1355 // Load the number of instruction-steps to offset from the label. 1356 unsigned LdrOpcode; 1357 switch (Size) { 1358 case 1: LdrOpcode = AArch64::LDRBBroX; break; 1359 case 2: LdrOpcode = AArch64::LDRHHroX; break; 1360 case 4: LdrOpcode = AArch64::LDRSWroX; break; 1361 default: 1362 llvm_unreachable("Unknown jump table size"); 1363 } 1364 1365 EmitToStreamer(OutStreamer, MCInstBuilder(LdrOpcode) 1366 .addReg(Size == 4 ? ScratchReg : ScratchRegW) 1367 .addReg(TableReg) 1368 .addReg(EntryReg) 1369 .addImm(0) 1370 .addImm(Size == 1 ? 0 : 1)); 1371 1372 // Add to the already materialized base label address, multiplying by 4 if 1373 // compressed. 1374 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::ADDXrs) 1375 .addReg(DestReg) 1376 .addReg(DestReg) 1377 .addReg(ScratchReg) 1378 .addImm(Size == 4 ? 0 : 2)); 1379 } 1380 1381 void AArch64AsmPrinter::LowerHardenedBRJumpTable(const MachineInstr &MI) { 1382 unsigned InstsEmitted = 0; 1383 1384 const MachineJumpTableInfo *MJTI = MF->getJumpTableInfo(); 1385 assert(MJTI && "Can't lower jump-table dispatch without JTI"); 1386 1387 const std::vector<MachineJumpTableEntry> &JTs = MJTI->getJumpTables(); 1388 assert(!JTs.empty() && "Invalid JT index for jump-table dispatch"); 1389 1390 // Emit: 1391 // mov x17, #<size of table> ; depending on table size, with MOVKs 1392 // cmp x16, x17 ; or #imm if table size fits in 12-bit 1393 // csel x16, x16, xzr, ls ; check for index overflow 1394 // 1395 // adrp x17, Ltable@PAGE ; materialize table address 1396 // add x17, Ltable@PAGEOFF 1397 // ldrsw x16, [x17, x16, lsl #2] ; load table entry 1398 // 1399 // Lanchor: 1400 // adr x17, Lanchor ; compute target address 1401 // add x16, x17, x16 1402 // br x16 ; branch to target 1403 1404 MachineOperand JTOp = MI.getOperand(0); 1405 1406 unsigned JTI = JTOp.getIndex(); 1407 assert(!AArch64FI->getJumpTableEntryPCRelSymbol(JTI) && 1408 "unsupported compressed jump table"); 1409 1410 const uint64_t NumTableEntries = JTs[JTI].MBBs.size(); 1411 1412 // cmp only supports a 12-bit immediate. If we need more, materialize the 1413 // immediate, using x17 as a scratch register. 1414 uint64_t MaxTableEntry = NumTableEntries - 1; 1415 if (isUInt<12>(MaxTableEntry)) { 1416 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXri) 1417 .addReg(AArch64::XZR) 1418 .addReg(AArch64::X16) 1419 .addImm(MaxTableEntry) 1420 .addImm(0)); 1421 ++InstsEmitted; 1422 } else { 1423 EmitToStreamer(*OutStreamer, 1424 MCInstBuilder(AArch64::MOVZXi) 1425 .addReg(AArch64::X17) 1426 .addImm(static_cast<uint16_t>(MaxTableEntry)) 1427 .addImm(0)); 1428 ++InstsEmitted; 1429 // It's sad that we have to manually materialize instructions, but we can't 1430 // trivially reuse the main pseudo expansion logic. 1431 // A MOVK sequence is easy enough to generate and handles the general case. 1432 for (int Offset = 16; Offset < 64; Offset += 16) { 1433 if ((MaxTableEntry >> Offset) == 0) 1434 break; 1435 EmitToStreamer(*OutStreamer, 1436 MCInstBuilder(AArch64::MOVKXi) 1437 .addReg(AArch64::X17) 1438 .addReg(AArch64::X17) 1439 .addImm(static_cast<uint16_t>(MaxTableEntry >> Offset)) 1440 .addImm(Offset)); 1441 ++InstsEmitted; 1442 } 1443 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs) 1444 .addReg(AArch64::XZR) 1445 .addReg(AArch64::X16) 1446 .addReg(AArch64::X17) 1447 .addImm(0)); 1448 ++InstsEmitted; 1449 } 1450 1451 // This picks entry #0 on failure. 1452 // We might want to trap instead. 1453 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::CSELXr) 1454 .addReg(AArch64::X16) 1455 .addReg(AArch64::X16) 1456 .addReg(AArch64::XZR) 1457 .addImm(AArch64CC::LS)); 1458 ++InstsEmitted; 1459 1460 // Prepare the @PAGE/@PAGEOFF low/high operands. 1461 MachineOperand JTMOHi(JTOp), JTMOLo(JTOp); 1462 MCOperand JTMCHi, JTMCLo; 1463 1464 JTMOHi.setTargetFlags(AArch64II::MO_PAGE); 1465 JTMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC); 1466 1467 MCInstLowering.lowerOperand(JTMOHi, JTMCHi); 1468 MCInstLowering.lowerOperand(JTMOLo, JTMCLo); 1469 1470 EmitToStreamer( 1471 *OutStreamer, 1472 MCInstBuilder(AArch64::ADRP).addReg(AArch64::X17).addOperand(JTMCHi)); 1473 ++InstsEmitted; 1474 1475 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXri) 1476 .addReg(AArch64::X17) 1477 .addReg(AArch64::X17) 1478 .addOperand(JTMCLo) 1479 .addImm(0)); 1480 ++InstsEmitted; 1481 1482 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRSWroX) 1483 .addReg(AArch64::X16) 1484 .addReg(AArch64::X17) 1485 .addReg(AArch64::X16) 1486 .addImm(0) 1487 .addImm(1)); 1488 ++InstsEmitted; 1489 1490 MCSymbol *AdrLabel = MF->getContext().createTempSymbol(); 1491 const auto *AdrLabelE = MCSymbolRefExpr::create(AdrLabel, MF->getContext()); 1492 AArch64FI->setJumpTableEntryInfo(JTI, 4, AdrLabel); 1493 1494 OutStreamer->emitLabel(AdrLabel); 1495 EmitToStreamer( 1496 *OutStreamer, 1497 MCInstBuilder(AArch64::ADR).addReg(AArch64::X17).addExpr(AdrLabelE)); 1498 ++InstsEmitted; 1499 1500 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ADDXrs) 1501 .addReg(AArch64::X16) 1502 .addReg(AArch64::X17) 1503 .addReg(AArch64::X16) 1504 .addImm(0)); 1505 ++InstsEmitted; 1506 1507 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::BR).addReg(AArch64::X16)); 1508 ++InstsEmitted; 1509 1510 (void)InstsEmitted; 1511 assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4); 1512 } 1513 1514 void AArch64AsmPrinter::LowerMOPS(llvm::MCStreamer &OutStreamer, 1515 const llvm::MachineInstr &MI) { 1516 unsigned Opcode = MI.getOpcode(); 1517 assert(STI->hasMOPS()); 1518 assert(STI->hasMTE() || Opcode != AArch64::MOPSMemorySetTaggingPseudo); 1519 1520 const auto Ops = [Opcode]() -> std::array<unsigned, 3> { 1521 if (Opcode == AArch64::MOPSMemoryCopyPseudo) 1522 return {AArch64::CPYFP, AArch64::CPYFM, AArch64::CPYFE}; 1523 if (Opcode == AArch64::MOPSMemoryMovePseudo) 1524 return {AArch64::CPYP, AArch64::CPYM, AArch64::CPYE}; 1525 if (Opcode == AArch64::MOPSMemorySetPseudo) 1526 return {AArch64::SETP, AArch64::SETM, AArch64::SETE}; 1527 if (Opcode == AArch64::MOPSMemorySetTaggingPseudo) 1528 return {AArch64::SETGP, AArch64::SETGM, AArch64::MOPSSETGE}; 1529 llvm_unreachable("Unhandled memory operation pseudo"); 1530 }(); 1531 const bool IsSet = Opcode == AArch64::MOPSMemorySetPseudo || 1532 Opcode == AArch64::MOPSMemorySetTaggingPseudo; 1533 1534 for (auto Op : Ops) { 1535 int i = 0; 1536 auto MCIB = MCInstBuilder(Op); 1537 // Destination registers 1538 MCIB.addReg(MI.getOperand(i++).getReg()); 1539 MCIB.addReg(MI.getOperand(i++).getReg()); 1540 if (!IsSet) 1541 MCIB.addReg(MI.getOperand(i++).getReg()); 1542 // Input registers 1543 MCIB.addReg(MI.getOperand(i++).getReg()); 1544 MCIB.addReg(MI.getOperand(i++).getReg()); 1545 MCIB.addReg(MI.getOperand(i++).getReg()); 1546 1547 EmitToStreamer(OutStreamer, MCIB); 1548 } 1549 } 1550 1551 void AArch64AsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM, 1552 const MachineInstr &MI) { 1553 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes(); 1554 1555 auto &Ctx = OutStreamer.getContext(); 1556 MCSymbol *MILabel = Ctx.createTempSymbol(); 1557 OutStreamer.emitLabel(MILabel); 1558 1559 SM.recordStackMap(*MILabel, MI); 1560 assert(NumNOPBytes % 4 == 0 && "Invalid number of NOP bytes requested!"); 1561 1562 // Scan ahead to trim the shadow. 1563 const MachineBasicBlock &MBB = *MI.getParent(); 1564 MachineBasicBlock::const_iterator MII(MI); 1565 ++MII; 1566 while (NumNOPBytes > 0) { 1567 if (MII == MBB.end() || MII->isCall() || 1568 MII->getOpcode() == AArch64::DBG_VALUE || 1569 MII->getOpcode() == TargetOpcode::PATCHPOINT || 1570 MII->getOpcode() == TargetOpcode::STACKMAP) 1571 break; 1572 ++MII; 1573 NumNOPBytes -= 4; 1574 } 1575 1576 // Emit nops. 1577 for (unsigned i = 0; i < NumNOPBytes; i += 4) 1578 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 1579 } 1580 1581 // Lower a patchpoint of the form: 1582 // [<def>], <id>, <numBytes>, <target>, <numArgs> 1583 void AArch64AsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM, 1584 const MachineInstr &MI) { 1585 auto &Ctx = OutStreamer.getContext(); 1586 MCSymbol *MILabel = Ctx.createTempSymbol(); 1587 OutStreamer.emitLabel(MILabel); 1588 SM.recordPatchPoint(*MILabel, MI); 1589 1590 PatchPointOpers Opers(&MI); 1591 1592 int64_t CallTarget = Opers.getCallTarget().getImm(); 1593 unsigned EncodedBytes = 0; 1594 if (CallTarget) { 1595 assert((CallTarget & 0xFFFFFFFFFFFF) == CallTarget && 1596 "High 16 bits of call target should be zero."); 1597 Register ScratchReg = MI.getOperand(Opers.getNextScratchIdx()).getReg(); 1598 EncodedBytes = 16; 1599 // Materialize the jump address: 1600 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVZXi) 1601 .addReg(ScratchReg) 1602 .addImm((CallTarget >> 32) & 0xFFFF) 1603 .addImm(32)); 1604 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) 1605 .addReg(ScratchReg) 1606 .addReg(ScratchReg) 1607 .addImm((CallTarget >> 16) & 0xFFFF) 1608 .addImm(16)); 1609 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::MOVKXi) 1610 .addReg(ScratchReg) 1611 .addReg(ScratchReg) 1612 .addImm(CallTarget & 0xFFFF) 1613 .addImm(0)); 1614 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::BLR).addReg(ScratchReg)); 1615 } 1616 // Emit padding. 1617 unsigned NumBytes = Opers.getNumPatchBytes(); 1618 assert(NumBytes >= EncodedBytes && 1619 "Patchpoint can't request size less than the length of a call."); 1620 assert((NumBytes - EncodedBytes) % 4 == 0 && 1621 "Invalid number of NOP bytes requested!"); 1622 for (unsigned i = EncodedBytes; i < NumBytes; i += 4) 1623 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 1624 } 1625 1626 void AArch64AsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM, 1627 const MachineInstr &MI) { 1628 StatepointOpers SOpers(&MI); 1629 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) { 1630 assert(PatchBytes % 4 == 0 && "Invalid number of NOP bytes requested!"); 1631 for (unsigned i = 0; i < PatchBytes; i += 4) 1632 EmitToStreamer(OutStreamer, MCInstBuilder(AArch64::HINT).addImm(0)); 1633 } else { 1634 // Lower call target and choose correct opcode 1635 const MachineOperand &CallTarget = SOpers.getCallTarget(); 1636 MCOperand CallTargetMCOp; 1637 unsigned CallOpcode; 1638 switch (CallTarget.getType()) { 1639 case MachineOperand::MO_GlobalAddress: 1640 case MachineOperand::MO_ExternalSymbol: 1641 MCInstLowering.lowerOperand(CallTarget, CallTargetMCOp); 1642 CallOpcode = AArch64::BL; 1643 break; 1644 case MachineOperand::MO_Immediate: 1645 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm()); 1646 CallOpcode = AArch64::BL; 1647 break; 1648 case MachineOperand::MO_Register: 1649 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg()); 1650 CallOpcode = AArch64::BLR; 1651 break; 1652 default: 1653 llvm_unreachable("Unsupported operand type in statepoint call target"); 1654 break; 1655 } 1656 1657 EmitToStreamer(OutStreamer, 1658 MCInstBuilder(CallOpcode).addOperand(CallTargetMCOp)); 1659 } 1660 1661 auto &Ctx = OutStreamer.getContext(); 1662 MCSymbol *MILabel = Ctx.createTempSymbol(); 1663 OutStreamer.emitLabel(MILabel); 1664 SM.recordStatepoint(*MILabel, MI); 1665 } 1666 1667 void AArch64AsmPrinter::LowerFAULTING_OP(const MachineInstr &FaultingMI) { 1668 // FAULTING_LOAD_OP <def>, <faltinf type>, <MBB handler>, 1669 // <opcode>, <operands> 1670 1671 Register DefRegister = FaultingMI.getOperand(0).getReg(); 1672 FaultMaps::FaultKind FK = 1673 static_cast<FaultMaps::FaultKind>(FaultingMI.getOperand(1).getImm()); 1674 MCSymbol *HandlerLabel = FaultingMI.getOperand(2).getMBB()->getSymbol(); 1675 unsigned Opcode = FaultingMI.getOperand(3).getImm(); 1676 unsigned OperandsBeginIdx = 4; 1677 1678 auto &Ctx = OutStreamer->getContext(); 1679 MCSymbol *FaultingLabel = Ctx.createTempSymbol(); 1680 OutStreamer->emitLabel(FaultingLabel); 1681 1682 assert(FK < FaultMaps::FaultKindMax && "Invalid Faulting Kind!"); 1683 FM.recordFaultingOp(FK, FaultingLabel, HandlerLabel); 1684 1685 MCInst MI; 1686 MI.setOpcode(Opcode); 1687 1688 if (DefRegister != (Register)0) 1689 MI.addOperand(MCOperand::createReg(DefRegister)); 1690 1691 for (const MachineOperand &MO : 1692 llvm::drop_begin(FaultingMI.operands(), OperandsBeginIdx)) { 1693 MCOperand Dest; 1694 lowerOperand(MO, Dest); 1695 MI.addOperand(Dest); 1696 } 1697 1698 OutStreamer->AddComment("on-fault: " + HandlerLabel->getName()); 1699 OutStreamer->emitInstruction(MI, getSubtargetInfo()); 1700 } 1701 1702 void AArch64AsmPrinter::emitFMov0(const MachineInstr &MI) { 1703 Register DestReg = MI.getOperand(0).getReg(); 1704 if (STI->hasZeroCycleZeroingFP() && !STI->hasZeroCycleZeroingFPWorkaround() && 1705 STI->isNeonAvailable()) { 1706 // Convert H/S register to corresponding D register 1707 if (AArch64::H0 <= DestReg && DestReg <= AArch64::H31) 1708 DestReg = AArch64::D0 + (DestReg - AArch64::H0); 1709 else if (AArch64::S0 <= DestReg && DestReg <= AArch64::S31) 1710 DestReg = AArch64::D0 + (DestReg - AArch64::S0); 1711 else 1712 assert(AArch64::D0 <= DestReg && DestReg <= AArch64::D31); 1713 1714 MCInst MOVI; 1715 MOVI.setOpcode(AArch64::MOVID); 1716 MOVI.addOperand(MCOperand::createReg(DestReg)); 1717 MOVI.addOperand(MCOperand::createImm(0)); 1718 EmitToStreamer(*OutStreamer, MOVI); 1719 } else { 1720 MCInst FMov; 1721 switch (MI.getOpcode()) { 1722 default: llvm_unreachable("Unexpected opcode"); 1723 case AArch64::FMOVH0: 1724 FMov.setOpcode(STI->hasFullFP16() ? AArch64::FMOVWHr : AArch64::FMOVWSr); 1725 if (!STI->hasFullFP16()) 1726 DestReg = (AArch64::S0 + (DestReg - AArch64::H0)); 1727 FMov.addOperand(MCOperand::createReg(DestReg)); 1728 FMov.addOperand(MCOperand::createReg(AArch64::WZR)); 1729 break; 1730 case AArch64::FMOVS0: 1731 FMov.setOpcode(AArch64::FMOVWSr); 1732 FMov.addOperand(MCOperand::createReg(DestReg)); 1733 FMov.addOperand(MCOperand::createReg(AArch64::WZR)); 1734 break; 1735 case AArch64::FMOVD0: 1736 FMov.setOpcode(AArch64::FMOVXDr); 1737 FMov.addOperand(MCOperand::createReg(DestReg)); 1738 FMov.addOperand(MCOperand::createReg(AArch64::XZR)); 1739 break; 1740 } 1741 EmitToStreamer(*OutStreamer, FMov); 1742 } 1743 } 1744 1745 unsigned AArch64AsmPrinter::emitPtrauthDiscriminator(uint16_t Disc, 1746 unsigned AddrDisc, 1747 unsigned &InstsEmitted) { 1748 // So far we've used NoRegister in pseudos. Now we need real encodings. 1749 if (AddrDisc == AArch64::NoRegister) 1750 AddrDisc = AArch64::XZR; 1751 1752 // If there is no constant discriminator, there's no blend involved: 1753 // just use the address discriminator register as-is (XZR or not). 1754 if (!Disc) 1755 return AddrDisc; 1756 1757 // If there's only a constant discriminator, MOV it into x17. 1758 if (AddrDisc == AArch64::XZR) { 1759 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi) 1760 .addReg(AArch64::X17) 1761 .addImm(Disc) 1762 .addImm(/*shift=*/0)); 1763 ++InstsEmitted; 1764 return AArch64::X17; 1765 } 1766 1767 // If there are both, emit a blend into x17. 1768 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) 1769 .addReg(AArch64::X17) 1770 .addReg(AArch64::XZR) 1771 .addReg(AddrDisc) 1772 .addImm(0)); 1773 ++InstsEmitted; 1774 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi) 1775 .addReg(AArch64::X17) 1776 .addReg(AArch64::X17) 1777 .addImm(Disc) 1778 .addImm(/*shift=*/48)); 1779 ++InstsEmitted; 1780 return AArch64::X17; 1781 } 1782 1783 void AArch64AsmPrinter::emitPtrauthAuthResign(const MachineInstr *MI) { 1784 unsigned InstsEmitted = 0; 1785 const bool IsAUTPAC = MI->getOpcode() == AArch64::AUTPAC; 1786 1787 // We can expand AUT/AUTPAC into 3 possible sequences: 1788 // - unchecked: 1789 // autia x16, x0 1790 // pacib x16, x1 ; if AUTPAC 1791 // 1792 // - checked and clearing: 1793 // mov x17, x0 1794 // movk x17, #disc, lsl #48 1795 // autia x16, x17 1796 // mov x17, x16 1797 // xpaci x17 1798 // cmp x16, x17 1799 // b.eq Lsuccess 1800 // mov x16, x17 1801 // b Lend 1802 // Lsuccess: 1803 // mov x17, x1 1804 // movk x17, #disc, lsl #48 1805 // pacib x16, x17 1806 // Lend: 1807 // Where we only emit the AUT if we started with an AUT. 1808 // 1809 // - checked and trapping: 1810 // mov x17, x0 1811 // movk x17, #disc, lsl #48 1812 // autia x16, x0 1813 // mov x17, x16 1814 // xpaci x17 1815 // cmp x16, x17 1816 // b.eq Lsuccess 1817 // brk #<0xc470 + aut key> 1818 // Lsuccess: 1819 // mov x17, x1 1820 // movk x17, #disc, lsl #48 1821 // pacib x16, x17 ; if AUTPAC 1822 // Where the b.eq skips over the trap if the PAC is valid. 1823 // 1824 // This sequence is expensive, but we need more information to be able to 1825 // do better. 1826 // 1827 // We can't TBZ the poison bit because EnhancedPAC2 XORs the PAC bits 1828 // on failure. 1829 // We can't TST the PAC bits because we don't always know how the address 1830 // space is setup for the target environment (and the bottom PAC bit is 1831 // based on that). 1832 // Either way, we also don't always know whether TBI is enabled or not for 1833 // the specific target environment. 1834 1835 // By default, auth/resign sequences check for auth failures. 1836 bool ShouldCheck = true; 1837 // In the checked sequence, we only trap if explicitly requested. 1838 bool ShouldTrap = MF->getFunction().hasFnAttribute("ptrauth-auth-traps"); 1839 1840 // On an FPAC CPU, you get traps whether you want them or not: there's 1841 // no point in emitting checks or traps. 1842 if (STI->hasFPAC()) 1843 ShouldCheck = ShouldTrap = false; 1844 1845 // However, command-line flags can override this, for experimentation. 1846 switch (PtrauthAuthChecks) { 1847 case PtrauthCheckMode::Default: 1848 break; 1849 case PtrauthCheckMode::Unchecked: 1850 ShouldCheck = ShouldTrap = false; 1851 break; 1852 case PtrauthCheckMode::Poison: 1853 ShouldCheck = true; 1854 ShouldTrap = false; 1855 break; 1856 case PtrauthCheckMode::Trap: 1857 ShouldCheck = ShouldTrap = true; 1858 break; 1859 } 1860 1861 auto AUTKey = (AArch64PACKey::ID)MI->getOperand(0).getImm(); 1862 uint64_t AUTDisc = MI->getOperand(1).getImm(); 1863 unsigned AUTAddrDisc = MI->getOperand(2).getReg(); 1864 1865 unsigned XPACOpc = getXPACOpcodeForKey(AUTKey); 1866 1867 // Compute aut discriminator into x17 1868 assert(isUInt<16>(AUTDisc)); 1869 unsigned AUTDiscReg = 1870 emitPtrauthDiscriminator(AUTDisc, AUTAddrDisc, InstsEmitted); 1871 bool AUTZero = AUTDiscReg == AArch64::XZR; 1872 unsigned AUTOpc = getAUTOpcodeForKey(AUTKey, AUTZero); 1873 1874 // autiza x16 ; if AUTZero 1875 // autia x16, x17 ; if !AUTZero 1876 MCInst AUTInst; 1877 AUTInst.setOpcode(AUTOpc); 1878 AUTInst.addOperand(MCOperand::createReg(AArch64::X16)); 1879 AUTInst.addOperand(MCOperand::createReg(AArch64::X16)); 1880 if (!AUTZero) 1881 AUTInst.addOperand(MCOperand::createReg(AUTDiscReg)); 1882 EmitToStreamer(*OutStreamer, AUTInst); 1883 ++InstsEmitted; 1884 1885 // Unchecked or checked-but-non-trapping AUT is just an "AUT": we're done. 1886 if (!IsAUTPAC && (!ShouldCheck || !ShouldTrap)) { 1887 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4); 1888 return; 1889 } 1890 1891 MCSymbol *EndSym = nullptr; 1892 1893 // Checked sequences do an additional strip-and-compare. 1894 if (ShouldCheck) { 1895 MCSymbol *SuccessSym = createTempSymbol("auth_success_"); 1896 1897 // XPAC has tied src/dst: use x17 as a temporary copy. 1898 // mov x17, x16 1899 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) 1900 .addReg(AArch64::X17) 1901 .addReg(AArch64::XZR) 1902 .addReg(AArch64::X16) 1903 .addImm(0)); 1904 ++InstsEmitted; 1905 1906 // xpaci x17 1907 EmitToStreamer( 1908 *OutStreamer, 1909 MCInstBuilder(XPACOpc).addReg(AArch64::X17).addReg(AArch64::X17)); 1910 ++InstsEmitted; 1911 1912 // cmp x16, x17 1913 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::SUBSXrs) 1914 .addReg(AArch64::XZR) 1915 .addReg(AArch64::X16) 1916 .addReg(AArch64::X17) 1917 .addImm(0)); 1918 ++InstsEmitted; 1919 1920 // b.eq Lsuccess 1921 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::Bcc) 1922 .addImm(AArch64CC::EQ) 1923 .addExpr(MCSymbolRefExpr::create( 1924 SuccessSym, OutContext))); 1925 ++InstsEmitted; 1926 1927 if (ShouldTrap) { 1928 // Trapping sequences do a 'brk'. 1929 // brk #<0xc470 + aut key> 1930 EmitToStreamer(*OutStreamer, 1931 MCInstBuilder(AArch64::BRK).addImm(0xc470 | AUTKey)); 1932 ++InstsEmitted; 1933 } else { 1934 // Non-trapping checked sequences return the stripped result in x16, 1935 // skipping over the PAC if there is one. 1936 1937 // FIXME: can we simply return the AUT result, already in x16? without.. 1938 // ..traps this is usable as an oracle anyway, based on high bits 1939 // mov x17, x16 1940 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) 1941 .addReg(AArch64::X16) 1942 .addReg(AArch64::XZR) 1943 .addReg(AArch64::X17) 1944 .addImm(0)); 1945 ++InstsEmitted; 1946 1947 if (IsAUTPAC) { 1948 EndSym = createTempSymbol("resign_end_"); 1949 1950 // b Lend 1951 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::B) 1952 .addExpr(MCSymbolRefExpr::create( 1953 EndSym, OutContext))); 1954 ++InstsEmitted; 1955 } 1956 } 1957 1958 // If the auth check succeeds, we can continue. 1959 // Lsuccess: 1960 OutStreamer->emitLabel(SuccessSym); 1961 } 1962 1963 // We already emitted unchecked and checked-but-non-trapping AUTs. 1964 // That left us with trapping AUTs, and AUTPACs. 1965 // Trapping AUTs don't need PAC: we're done. 1966 if (!IsAUTPAC) { 1967 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4); 1968 return; 1969 } 1970 1971 auto PACKey = (AArch64PACKey::ID)MI->getOperand(3).getImm(); 1972 uint64_t PACDisc = MI->getOperand(4).getImm(); 1973 unsigned PACAddrDisc = MI->getOperand(5).getReg(); 1974 1975 // Compute pac discriminator into x17 1976 assert(isUInt<16>(PACDisc)); 1977 unsigned PACDiscReg = 1978 emitPtrauthDiscriminator(PACDisc, PACAddrDisc, InstsEmitted); 1979 bool PACZero = PACDiscReg == AArch64::XZR; 1980 unsigned PACOpc = getPACOpcodeForKey(PACKey, PACZero); 1981 1982 // pacizb x16 ; if PACZero 1983 // pacib x16, x17 ; if !PACZero 1984 MCInst PACInst; 1985 PACInst.setOpcode(PACOpc); 1986 PACInst.addOperand(MCOperand::createReg(AArch64::X16)); 1987 PACInst.addOperand(MCOperand::createReg(AArch64::X16)); 1988 if (!PACZero) 1989 PACInst.addOperand(MCOperand::createReg(PACDiscReg)); 1990 EmitToStreamer(*OutStreamer, PACInst); 1991 ++InstsEmitted; 1992 1993 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4); 1994 // Lend: 1995 if (EndSym) 1996 OutStreamer->emitLabel(EndSym); 1997 } 1998 1999 void AArch64AsmPrinter::emitPtrauthBranch(const MachineInstr *MI) { 2000 unsigned InstsEmitted = 0; 2001 bool IsCall = MI->getOpcode() == AArch64::BLRA; 2002 unsigned BrTarget = MI->getOperand(0).getReg(); 2003 2004 auto Key = (AArch64PACKey::ID)MI->getOperand(1).getImm(); 2005 assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) && 2006 "Invalid auth call key"); 2007 2008 uint64_t Disc = MI->getOperand(2).getImm(); 2009 assert(isUInt<16>(Disc)); 2010 2011 unsigned AddrDisc = MI->getOperand(3).getReg(); 2012 2013 // Compute discriminator into x17 2014 unsigned DiscReg = emitPtrauthDiscriminator(Disc, AddrDisc, InstsEmitted); 2015 bool IsZeroDisc = DiscReg == AArch64::XZR; 2016 2017 unsigned Opc; 2018 if (IsCall) { 2019 if (Key == AArch64PACKey::IA) 2020 Opc = IsZeroDisc ? AArch64::BLRAAZ : AArch64::BLRAA; 2021 else 2022 Opc = IsZeroDisc ? AArch64::BLRABZ : AArch64::BLRAB; 2023 } else { 2024 if (Key == AArch64PACKey::IA) 2025 Opc = IsZeroDisc ? AArch64::BRAAZ : AArch64::BRAA; 2026 else 2027 Opc = IsZeroDisc ? AArch64::BRABZ : AArch64::BRAB; 2028 } 2029 2030 MCInst BRInst; 2031 BRInst.setOpcode(Opc); 2032 BRInst.addOperand(MCOperand::createReg(BrTarget)); 2033 if (!IsZeroDisc) 2034 BRInst.addOperand(MCOperand::createReg(DiscReg)); 2035 EmitToStreamer(*OutStreamer, BRInst); 2036 ++InstsEmitted; 2037 2038 assert(STI->getInstrInfo()->getInstSizeInBytes(*MI) >= InstsEmitted * 4); 2039 } 2040 2041 const MCExpr * 2042 AArch64AsmPrinter::lowerConstantPtrAuth(const ConstantPtrAuth &CPA) { 2043 MCContext &Ctx = OutContext; 2044 2045 // Figure out the base symbol and the addend, if any. 2046 APInt Offset(64, 0); 2047 const Value *BaseGV = CPA.getPointer()->stripAndAccumulateConstantOffsets( 2048 getDataLayout(), Offset, /*AllowNonInbounds=*/true); 2049 2050 auto *BaseGVB = dyn_cast<GlobalValue>(BaseGV); 2051 2052 // If we can't understand the referenced ConstantExpr, there's nothing 2053 // else we can do: emit an error. 2054 if (!BaseGVB) { 2055 BaseGV->getContext().emitError( 2056 "cannot resolve target base/addend of ptrauth constant"); 2057 return nullptr; 2058 } 2059 2060 // If there is an addend, turn that into the appropriate MCExpr. 2061 const MCExpr *Sym = MCSymbolRefExpr::create(getSymbol(BaseGVB), Ctx); 2062 if (Offset.sgt(0)) 2063 Sym = MCBinaryExpr::createAdd( 2064 Sym, MCConstantExpr::create(Offset.getSExtValue(), Ctx), Ctx); 2065 else if (Offset.slt(0)) 2066 Sym = MCBinaryExpr::createSub( 2067 Sym, MCConstantExpr::create((-Offset).getSExtValue(), Ctx), Ctx); 2068 2069 uint64_t KeyID = CPA.getKey()->getZExtValue(); 2070 // We later rely on valid KeyID value in AArch64PACKeyIDToString call from 2071 // AArch64AuthMCExpr::printImpl, so fail fast. 2072 if (KeyID > AArch64PACKey::LAST) 2073 report_fatal_error("AArch64 PAC Key ID '" + Twine(KeyID) + 2074 "' out of range [0, " + 2075 Twine((unsigned)AArch64PACKey::LAST) + "]"); 2076 2077 uint64_t Disc = CPA.getDiscriminator()->getZExtValue(); 2078 if (!isUInt<16>(Disc)) 2079 report_fatal_error("AArch64 PAC Discriminator '" + Twine(Disc) + 2080 "' out of range [0, 0xFFFF]"); 2081 2082 // Finally build the complete @AUTH expr. 2083 return AArch64AuthMCExpr::create(Sym, Disc, AArch64PACKey::ID(KeyID), 2084 CPA.hasAddressDiscriminator(), Ctx); 2085 } 2086 2087 void AArch64AsmPrinter::LowerLOADauthptrstatic(const MachineInstr &MI) { 2088 unsigned DstReg = MI.getOperand(0).getReg(); 2089 const MachineOperand &GAOp = MI.getOperand(1); 2090 const uint64_t KeyC = MI.getOperand(2).getImm(); 2091 assert(KeyC <= AArch64PACKey::LAST && 2092 "key is out of range [0, AArch64PACKey::LAST]"); 2093 const auto Key = (AArch64PACKey::ID)KeyC; 2094 const uint64_t Disc = MI.getOperand(3).getImm(); 2095 assert(isUInt<16>(Disc) && 2096 "constant discriminator is out of range [0, 0xffff]"); 2097 2098 // Emit instruction sequence like the following: 2099 // ADRP x16, symbol$auth_ptr$key$disc 2100 // LDR x16, [x16, :lo12:symbol$auth_ptr$key$disc] 2101 // 2102 // Where the $auth_ptr$ symbol is the stub slot containing the signed pointer 2103 // to symbol. 2104 MCSymbol *AuthPtrStubSym; 2105 if (TM.getTargetTriple().isOSBinFormatELF()) { 2106 const auto &TLOF = 2107 static_cast<const AArch64_ELFTargetObjectFile &>(getObjFileLowering()); 2108 2109 assert(GAOp.getOffset() == 0 && 2110 "non-zero offset for $auth_ptr$ stub slots is not supported"); 2111 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal()); 2112 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc); 2113 } else { 2114 assert(TM.getTargetTriple().isOSBinFormatMachO() && 2115 "LOADauthptrstatic is implemented only for MachO/ELF"); 2116 2117 const auto &TLOF = static_cast<const AArch64_MachoTargetObjectFile &>( 2118 getObjFileLowering()); 2119 2120 assert(GAOp.getOffset() == 0 && 2121 "non-zero offset for $auth_ptr$ stub slots is not supported"); 2122 const MCSymbol *GASym = TM.getSymbol(GAOp.getGlobal()); 2123 AuthPtrStubSym = TLOF.getAuthPtrSlotSymbol(TM, MMI, GASym, Key, Disc); 2124 } 2125 2126 MachineOperand StubMOHi = 2127 MachineOperand::CreateMCSymbol(AuthPtrStubSym, AArch64II::MO_PAGE); 2128 MachineOperand StubMOLo = MachineOperand::CreateMCSymbol( 2129 AuthPtrStubSym, AArch64II::MO_PAGEOFF | AArch64II::MO_NC); 2130 MCOperand StubMCHi, StubMCLo; 2131 2132 MCInstLowering.lowerOperand(StubMOHi, StubMCHi); 2133 MCInstLowering.lowerOperand(StubMOLo, StubMCLo); 2134 2135 EmitToStreamer( 2136 *OutStreamer, 2137 MCInstBuilder(AArch64::ADRP).addReg(DstReg).addOperand(StubMCHi)); 2138 2139 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::LDRXui) 2140 .addReg(DstReg) 2141 .addReg(DstReg) 2142 .addOperand(StubMCLo)); 2143 } 2144 2145 void AArch64AsmPrinter::LowerMOVaddrPAC(const MachineInstr &MI) { 2146 unsigned InstsEmitted = 0; 2147 auto EmitAndIncrement = [this, &InstsEmitted](const MCInst &Inst) { 2148 EmitToStreamer(*OutStreamer, Inst); 2149 ++InstsEmitted; 2150 }; 2151 2152 const bool IsGOTLoad = MI.getOpcode() == AArch64::LOADgotPAC; 2153 MachineOperand GAOp = MI.getOperand(0); 2154 const uint64_t KeyC = MI.getOperand(1).getImm(); 2155 assert(KeyC <= AArch64PACKey::LAST && 2156 "key is out of range [0, AArch64PACKey::LAST]"); 2157 const auto Key = (AArch64PACKey::ID)KeyC; 2158 const unsigned AddrDisc = MI.getOperand(2).getReg(); 2159 const uint64_t Disc = MI.getOperand(3).getImm(); 2160 assert(isUInt<16>(Disc) && 2161 "constant discriminator is out of range [0, 0xffff]"); 2162 2163 const int64_t Offset = GAOp.getOffset(); 2164 GAOp.setOffset(0); 2165 2166 // Emit: 2167 // target materialization: 2168 // - via GOT: 2169 // adrp x16, :got:target 2170 // ldr x16, [x16, :got_lo12:target] 2171 // add offset to x16 if offset != 0 2172 // 2173 // - direct: 2174 // adrp x16, target 2175 // add x16, x16, :lo12:target 2176 // add offset to x16 if offset != 0 2177 // 2178 // add offset to x16: 2179 // - abs(offset) fits 24 bits: 2180 // add/sub x16, x16, #<offset>[, #lsl 12] (up to 2 instructions) 2181 // - abs(offset) does not fit 24 bits: 2182 // - offset < 0: 2183 // movn+movk sequence filling x17 register with the offset (up to 4 2184 // instructions) 2185 // add x16, x16, x17 2186 // - offset > 0: 2187 // movz+movk sequence filling x17 register with the offset (up to 4 2188 // instructions) 2189 // add x16, x16, x17 2190 // 2191 // signing: 2192 // - 0 discriminator: 2193 // paciza x16 2194 // - Non-0 discriminator, no address discriminator: 2195 // mov x17, #Disc 2196 // pacia x16, x17 2197 // - address discriminator (with potentially folded immediate discriminator): 2198 // pacia x16, xAddrDisc 2199 2200 MachineOperand GAMOHi(GAOp), GAMOLo(GAOp); 2201 MCOperand GAMCHi, GAMCLo; 2202 2203 GAMOHi.setTargetFlags(AArch64II::MO_PAGE); 2204 GAMOLo.setTargetFlags(AArch64II::MO_PAGEOFF | AArch64II::MO_NC); 2205 if (IsGOTLoad) { 2206 GAMOHi.addTargetFlag(AArch64II::MO_GOT); 2207 GAMOLo.addTargetFlag(AArch64II::MO_GOT); 2208 } 2209 2210 MCInstLowering.lowerOperand(GAMOHi, GAMCHi); 2211 MCInstLowering.lowerOperand(GAMOLo, GAMCLo); 2212 2213 EmitAndIncrement( 2214 MCInstBuilder(AArch64::ADRP).addReg(AArch64::X16).addOperand(GAMCHi)); 2215 2216 if (IsGOTLoad) { 2217 EmitAndIncrement(MCInstBuilder(AArch64::LDRXui) 2218 .addReg(AArch64::X16) 2219 .addReg(AArch64::X16) 2220 .addOperand(GAMCLo)); 2221 } else { 2222 EmitAndIncrement(MCInstBuilder(AArch64::ADDXri) 2223 .addReg(AArch64::X16) 2224 .addReg(AArch64::X16) 2225 .addOperand(GAMCLo) 2226 .addImm(0)); 2227 } 2228 2229 if (Offset != 0) { 2230 const uint64_t AbsOffset = (Offset > 0 ? Offset : -((uint64_t)Offset)); 2231 const bool IsNeg = Offset < 0; 2232 if (isUInt<24>(AbsOffset)) { 2233 for (int BitPos = 0; BitPos != 24 && (AbsOffset >> BitPos); 2234 BitPos += 12) { 2235 EmitAndIncrement( 2236 MCInstBuilder(IsNeg ? AArch64::SUBXri : AArch64::ADDXri) 2237 .addReg(AArch64::X16) 2238 .addReg(AArch64::X16) 2239 .addImm((AbsOffset >> BitPos) & 0xfff) 2240 .addImm(AArch64_AM::getShifterImm(AArch64_AM::LSL, BitPos))); 2241 } 2242 } else { 2243 const uint64_t UOffset = Offset; 2244 EmitAndIncrement(MCInstBuilder(IsNeg ? AArch64::MOVNXi : AArch64::MOVZXi) 2245 .addReg(AArch64::X17) 2246 .addImm((IsNeg ? ~UOffset : UOffset) & 0xffff) 2247 .addImm(/*shift=*/0)); 2248 auto NeedMovk = [IsNeg, UOffset](int BitPos) -> bool { 2249 assert(BitPos == 16 || BitPos == 32 || BitPos == 48); 2250 uint64_t Shifted = UOffset >> BitPos; 2251 if (!IsNeg) 2252 return Shifted != 0; 2253 for (int I = 0; I != 64 - BitPos; I += 16) 2254 if (((Shifted >> I) & 0xffff) != 0xffff) 2255 return true; 2256 return false; 2257 }; 2258 for (int BitPos = 16; BitPos != 64 && NeedMovk(BitPos); BitPos += 16) { 2259 EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi) 2260 .addReg(AArch64::X17) 2261 .addReg(AArch64::X17) 2262 .addImm((UOffset >> BitPos) & 0xffff) 2263 .addImm(/*shift=*/BitPos)); 2264 } 2265 EmitAndIncrement(MCInstBuilder(AArch64::ADDXrs) 2266 .addReg(AArch64::X16) 2267 .addReg(AArch64::X16) 2268 .addReg(AArch64::X17) 2269 .addImm(/*shift=*/0)); 2270 } 2271 } 2272 2273 unsigned DiscReg = AddrDisc; 2274 if (Disc != 0) { 2275 if (AddrDisc != AArch64::XZR) { 2276 EmitAndIncrement(MCInstBuilder(AArch64::ORRXrs) 2277 .addReg(AArch64::X17) 2278 .addReg(AArch64::XZR) 2279 .addReg(AddrDisc) 2280 .addImm(0)); 2281 EmitAndIncrement(MCInstBuilder(AArch64::MOVKXi) 2282 .addReg(AArch64::X17) 2283 .addReg(AArch64::X17) 2284 .addImm(Disc) 2285 .addImm(/*shift=*/48)); 2286 } else { 2287 EmitAndIncrement(MCInstBuilder(AArch64::MOVZXi) 2288 .addReg(AArch64::X17) 2289 .addImm(Disc) 2290 .addImm(/*shift=*/0)); 2291 } 2292 DiscReg = AArch64::X17; 2293 } 2294 2295 auto MIB = MCInstBuilder(getPACOpcodeForKey(Key, DiscReg == AArch64::XZR)) 2296 .addReg(AArch64::X16) 2297 .addReg(AArch64::X16); 2298 if (DiscReg != AArch64::XZR) 2299 MIB.addReg(DiscReg); 2300 EmitAndIncrement(MIB); 2301 2302 assert(STI->getInstrInfo()->getInstSizeInBytes(MI) >= InstsEmitted * 4); 2303 } 2304 2305 const MCExpr * 2306 AArch64AsmPrinter::lowerBlockAddressConstant(const BlockAddress &BA) { 2307 const MCExpr *BAE = AsmPrinter::lowerBlockAddressConstant(BA); 2308 const Function &Fn = *BA.getFunction(); 2309 2310 if (std::optional<uint16_t> BADisc = 2311 STI->getPtrAuthBlockAddressDiscriminatorIfEnabled(Fn)) 2312 return AArch64AuthMCExpr::create(BAE, *BADisc, AArch64PACKey::IA, 2313 /*HasAddressDiversity=*/false, OutContext); 2314 2315 return BAE; 2316 } 2317 2318 // Simple pseudo-instructions have their lowering (with expansion to real 2319 // instructions) auto-generated. 2320 #include "AArch64GenMCPseudoLowering.inc" 2321 2322 void AArch64AsmPrinter::emitInstruction(const MachineInstr *MI) { 2323 AArch64_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits()); 2324 2325 // Do any auto-generated pseudo lowerings. 2326 if (emitPseudoExpansionLowering(*OutStreamer, MI)) 2327 return; 2328 2329 if (MI->getOpcode() == AArch64::ADRP) { 2330 for (auto &Opd : MI->operands()) { 2331 if (Opd.isSymbol() && StringRef(Opd.getSymbolName()) == 2332 "swift_async_extendedFramePointerFlags") { 2333 ShouldEmitWeakSwiftAsyncExtendedFramePointerFlags = true; 2334 } 2335 } 2336 } 2337 2338 if (AArch64FI->getLOHRelated().count(MI)) { 2339 // Generate a label for LOH related instruction 2340 MCSymbol *LOHLabel = createTempSymbol("loh"); 2341 // Associate the instruction with the label 2342 LOHInstToLabel[MI] = LOHLabel; 2343 OutStreamer->emitLabel(LOHLabel); 2344 } 2345 2346 AArch64TargetStreamer *TS = 2347 static_cast<AArch64TargetStreamer *>(OutStreamer->getTargetStreamer()); 2348 // Do any manual lowerings. 2349 switch (MI->getOpcode()) { 2350 default: 2351 break; 2352 case AArch64::HINT: { 2353 // CurrentPatchableFunctionEntrySym can be CurrentFnBegin only for 2354 // -fpatchable-function-entry=N,0. The entry MBB is guaranteed to be 2355 // non-empty. If MI is the initial BTI, place the 2356 // __patchable_function_entries label after BTI. 2357 if (CurrentPatchableFunctionEntrySym && 2358 CurrentPatchableFunctionEntrySym == CurrentFnBegin && 2359 MI == &MF->front().front()) { 2360 int64_t Imm = MI->getOperand(0).getImm(); 2361 if ((Imm & 32) && (Imm & 6)) { 2362 MCInst Inst; 2363 MCInstLowering.Lower(MI, Inst); 2364 EmitToStreamer(*OutStreamer, Inst); 2365 CurrentPatchableFunctionEntrySym = createTempSymbol("patch"); 2366 OutStreamer->emitLabel(CurrentPatchableFunctionEntrySym); 2367 return; 2368 } 2369 } 2370 break; 2371 } 2372 case AArch64::MOVMCSym: { 2373 Register DestReg = MI->getOperand(0).getReg(); 2374 const MachineOperand &MO_Sym = MI->getOperand(1); 2375 MachineOperand Hi_MOSym(MO_Sym), Lo_MOSym(MO_Sym); 2376 MCOperand Hi_MCSym, Lo_MCSym; 2377 2378 Hi_MOSym.setTargetFlags(AArch64II::MO_G1 | AArch64II::MO_S); 2379 Lo_MOSym.setTargetFlags(AArch64II::MO_G0 | AArch64II::MO_NC); 2380 2381 MCInstLowering.lowerOperand(Hi_MOSym, Hi_MCSym); 2382 MCInstLowering.lowerOperand(Lo_MOSym, Lo_MCSym); 2383 2384 MCInst MovZ; 2385 MovZ.setOpcode(AArch64::MOVZXi); 2386 MovZ.addOperand(MCOperand::createReg(DestReg)); 2387 MovZ.addOperand(Hi_MCSym); 2388 MovZ.addOperand(MCOperand::createImm(16)); 2389 EmitToStreamer(*OutStreamer, MovZ); 2390 2391 MCInst MovK; 2392 MovK.setOpcode(AArch64::MOVKXi); 2393 MovK.addOperand(MCOperand::createReg(DestReg)); 2394 MovK.addOperand(MCOperand::createReg(DestReg)); 2395 MovK.addOperand(Lo_MCSym); 2396 MovK.addOperand(MCOperand::createImm(0)); 2397 EmitToStreamer(*OutStreamer, MovK); 2398 return; 2399 } 2400 case AArch64::MOVIv2d_ns: 2401 // It is generally beneficial to rewrite "fmov s0, wzr" to "movi d0, #0". 2402 // as movi is more efficient across all cores. Newer cores can eliminate 2403 // fmovs early and there is no difference with movi, but this not true for 2404 // all implementations. 2405 // 2406 // The floating-point version doesn't quite work in rare cases on older 2407 // CPUs, so on those targets we lower this instruction to movi.16b instead. 2408 if (STI->hasZeroCycleZeroingFPWorkaround() && 2409 MI->getOperand(1).getImm() == 0) { 2410 MCInst TmpInst; 2411 TmpInst.setOpcode(AArch64::MOVIv16b_ns); 2412 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); 2413 TmpInst.addOperand(MCOperand::createImm(MI->getOperand(1).getImm())); 2414 EmitToStreamer(*OutStreamer, TmpInst); 2415 return; 2416 } 2417 break; 2418 2419 case AArch64::DBG_VALUE: 2420 case AArch64::DBG_VALUE_LIST: 2421 if (isVerbose() && OutStreamer->hasRawTextSupport()) { 2422 SmallString<128> TmpStr; 2423 raw_svector_ostream OS(TmpStr); 2424 PrintDebugValueComment(MI, OS); 2425 OutStreamer->emitRawText(StringRef(OS.str())); 2426 } 2427 return; 2428 2429 case AArch64::EMITBKEY: { 2430 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType(); 2431 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI && 2432 ExceptionHandlingType != ExceptionHandling::ARM) 2433 return; 2434 2435 if (getFunctionCFISectionType(*MF) == CFISection::None) 2436 return; 2437 2438 OutStreamer->emitCFIBKeyFrame(); 2439 return; 2440 } 2441 2442 case AArch64::EMITMTETAGGED: { 2443 ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType(); 2444 if (ExceptionHandlingType != ExceptionHandling::DwarfCFI && 2445 ExceptionHandlingType != ExceptionHandling::ARM) 2446 return; 2447 2448 if (getFunctionCFISectionType(*MF) != CFISection::None) 2449 OutStreamer->emitCFIMTETaggedFrame(); 2450 return; 2451 } 2452 2453 case AArch64::AUT: 2454 case AArch64::AUTPAC: 2455 emitPtrauthAuthResign(MI); 2456 return; 2457 2458 case AArch64::LOADauthptrstatic: 2459 LowerLOADauthptrstatic(*MI); 2460 return; 2461 2462 case AArch64::LOADgotPAC: 2463 case AArch64::MOVaddrPAC: 2464 LowerMOVaddrPAC(*MI); 2465 return; 2466 2467 case AArch64::BRA: 2468 case AArch64::BLRA: 2469 emitPtrauthBranch(MI); 2470 return; 2471 2472 // Tail calls use pseudo instructions so they have the proper code-gen 2473 // attributes (isCall, isReturn, etc.). We lower them to the real 2474 // instruction here. 2475 case AArch64::AUTH_TCRETURN: 2476 case AArch64::AUTH_TCRETURN_BTI: { 2477 const uint64_t Key = MI->getOperand(2).getImm(); 2478 assert((Key == AArch64PACKey::IA || Key == AArch64PACKey::IB) && 2479 "Invalid auth key for tail-call return"); 2480 2481 const uint64_t Disc = MI->getOperand(3).getImm(); 2482 assert(isUInt<16>(Disc) && "Integer discriminator is too wide"); 2483 2484 Register AddrDisc = MI->getOperand(4).getReg(); 2485 2486 Register ScratchReg = MI->getOperand(0).getReg() == AArch64::X16 2487 ? AArch64::X17 2488 : AArch64::X16; 2489 2490 unsigned DiscReg = AddrDisc; 2491 if (Disc) { 2492 if (AddrDisc != AArch64::NoRegister) { 2493 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::ORRXrs) 2494 .addReg(ScratchReg) 2495 .addReg(AArch64::XZR) 2496 .addReg(AddrDisc) 2497 .addImm(0)); 2498 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVKXi) 2499 .addReg(ScratchReg) 2500 .addReg(ScratchReg) 2501 .addImm(Disc) 2502 .addImm(/*shift=*/48)); 2503 } else { 2504 EmitToStreamer(*OutStreamer, MCInstBuilder(AArch64::MOVZXi) 2505 .addReg(ScratchReg) 2506 .addImm(Disc) 2507 .addImm(/*shift=*/0)); 2508 } 2509 DiscReg = ScratchReg; 2510 } 2511 2512 const bool IsZero = DiscReg == AArch64::NoRegister; 2513 const unsigned Opcodes[2][2] = {{AArch64::BRAA, AArch64::BRAAZ}, 2514 {AArch64::BRAB, AArch64::BRABZ}}; 2515 2516 MCInst TmpInst; 2517 TmpInst.setOpcode(Opcodes[Key][IsZero]); 2518 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); 2519 if (!IsZero) 2520 TmpInst.addOperand(MCOperand::createReg(DiscReg)); 2521 EmitToStreamer(*OutStreamer, TmpInst); 2522 return; 2523 } 2524 2525 case AArch64::TCRETURNri: 2526 case AArch64::TCRETURNrix16x17: 2527 case AArch64::TCRETURNrix17: 2528 case AArch64::TCRETURNrinotx16: 2529 case AArch64::TCRETURNriALL: { 2530 MCInst TmpInst; 2531 TmpInst.setOpcode(AArch64::BR); 2532 TmpInst.addOperand(MCOperand::createReg(MI->getOperand(0).getReg())); 2533 EmitToStreamer(*OutStreamer, TmpInst); 2534 return; 2535 } 2536 case AArch64::TCRETURNdi: { 2537 MCOperand Dest; 2538 MCInstLowering.lowerOperand(MI->getOperand(0), Dest); 2539 MCInst TmpInst; 2540 TmpInst.setOpcode(AArch64::B); 2541 TmpInst.addOperand(Dest); 2542 EmitToStreamer(*OutStreamer, TmpInst); 2543 return; 2544 } 2545 case AArch64::SpeculationBarrierISBDSBEndBB: { 2546 // Print DSB SYS + ISB 2547 MCInst TmpInstDSB; 2548 TmpInstDSB.setOpcode(AArch64::DSB); 2549 TmpInstDSB.addOperand(MCOperand::createImm(0xf)); 2550 EmitToStreamer(*OutStreamer, TmpInstDSB); 2551 MCInst TmpInstISB; 2552 TmpInstISB.setOpcode(AArch64::ISB); 2553 TmpInstISB.addOperand(MCOperand::createImm(0xf)); 2554 EmitToStreamer(*OutStreamer, TmpInstISB); 2555 return; 2556 } 2557 case AArch64::SpeculationBarrierSBEndBB: { 2558 // Print SB 2559 MCInst TmpInstSB; 2560 TmpInstSB.setOpcode(AArch64::SB); 2561 EmitToStreamer(*OutStreamer, TmpInstSB); 2562 return; 2563 } 2564 case AArch64::TLSDESC_CALLSEQ: { 2565 /// lower this to: 2566 /// adrp x0, :tlsdesc:var 2567 /// ldr x1, [x0, #:tlsdesc_lo12:var] 2568 /// add x0, x0, #:tlsdesc_lo12:var 2569 /// .tlsdesccall var 2570 /// blr x1 2571 /// (TPIDR_EL0 offset now in x0) 2572 const MachineOperand &MO_Sym = MI->getOperand(0); 2573 MachineOperand MO_TLSDESC_LO12(MO_Sym), MO_TLSDESC(MO_Sym); 2574 MCOperand Sym, SymTLSDescLo12, SymTLSDesc; 2575 MO_TLSDESC_LO12.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGEOFF); 2576 MO_TLSDESC.setTargetFlags(AArch64II::MO_TLS | AArch64II::MO_PAGE); 2577 MCInstLowering.lowerOperand(MO_Sym, Sym); 2578 MCInstLowering.lowerOperand(MO_TLSDESC_LO12, SymTLSDescLo12); 2579 MCInstLowering.lowerOperand(MO_TLSDESC, SymTLSDesc); 2580 2581 MCInst Adrp; 2582 Adrp.setOpcode(AArch64::ADRP); 2583 Adrp.addOperand(MCOperand::createReg(AArch64::X0)); 2584 Adrp.addOperand(SymTLSDesc); 2585 EmitToStreamer(*OutStreamer, Adrp); 2586 2587 MCInst Ldr; 2588 if (STI->isTargetILP32()) { 2589 Ldr.setOpcode(AArch64::LDRWui); 2590 Ldr.addOperand(MCOperand::createReg(AArch64::W1)); 2591 } else { 2592 Ldr.setOpcode(AArch64::LDRXui); 2593 Ldr.addOperand(MCOperand::createReg(AArch64::X1)); 2594 } 2595 Ldr.addOperand(MCOperand::createReg(AArch64::X0)); 2596 Ldr.addOperand(SymTLSDescLo12); 2597 Ldr.addOperand(MCOperand::createImm(0)); 2598 EmitToStreamer(*OutStreamer, Ldr); 2599 2600 MCInst Add; 2601 if (STI->isTargetILP32()) { 2602 Add.setOpcode(AArch64::ADDWri); 2603 Add.addOperand(MCOperand::createReg(AArch64::W0)); 2604 Add.addOperand(MCOperand::createReg(AArch64::W0)); 2605 } else { 2606 Add.setOpcode(AArch64::ADDXri); 2607 Add.addOperand(MCOperand::createReg(AArch64::X0)); 2608 Add.addOperand(MCOperand::createReg(AArch64::X0)); 2609 } 2610 Add.addOperand(SymTLSDescLo12); 2611 Add.addOperand(MCOperand::createImm(AArch64_AM::getShiftValue(0))); 2612 EmitToStreamer(*OutStreamer, Add); 2613 2614 // Emit a relocation-annotation. This expands to no code, but requests 2615 // the following instruction gets an R_AARCH64_TLSDESC_CALL. 2616 MCInst TLSDescCall; 2617 TLSDescCall.setOpcode(AArch64::TLSDESCCALL); 2618 TLSDescCall.addOperand(Sym); 2619 EmitToStreamer(*OutStreamer, TLSDescCall); 2620 2621 MCInst Blr; 2622 Blr.setOpcode(AArch64::BLR); 2623 Blr.addOperand(MCOperand::createReg(AArch64::X1)); 2624 EmitToStreamer(*OutStreamer, Blr); 2625 2626 return; 2627 } 2628 2629 case AArch64::JumpTableDest32: 2630 case AArch64::JumpTableDest16: 2631 case AArch64::JumpTableDest8: 2632 LowerJumpTableDest(*OutStreamer, *MI); 2633 return; 2634 2635 case AArch64::BR_JumpTable: 2636 LowerHardenedBRJumpTable(*MI); 2637 return; 2638 2639 case AArch64::FMOVH0: 2640 case AArch64::FMOVS0: 2641 case AArch64::FMOVD0: 2642 emitFMov0(*MI); 2643 return; 2644 2645 case AArch64::MOPSMemoryCopyPseudo: 2646 case AArch64::MOPSMemoryMovePseudo: 2647 case AArch64::MOPSMemorySetPseudo: 2648 case AArch64::MOPSMemorySetTaggingPseudo: 2649 LowerMOPS(*OutStreamer, *MI); 2650 return; 2651 2652 case TargetOpcode::STACKMAP: 2653 return LowerSTACKMAP(*OutStreamer, SM, *MI); 2654 2655 case TargetOpcode::PATCHPOINT: 2656 return LowerPATCHPOINT(*OutStreamer, SM, *MI); 2657 2658 case TargetOpcode::STATEPOINT: 2659 return LowerSTATEPOINT(*OutStreamer, SM, *MI); 2660 2661 case TargetOpcode::FAULTING_OP: 2662 return LowerFAULTING_OP(*MI); 2663 2664 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: 2665 LowerPATCHABLE_FUNCTION_ENTER(*MI); 2666 return; 2667 2668 case TargetOpcode::PATCHABLE_FUNCTION_EXIT: 2669 LowerPATCHABLE_FUNCTION_EXIT(*MI); 2670 return; 2671 2672 case TargetOpcode::PATCHABLE_TAIL_CALL: 2673 LowerPATCHABLE_TAIL_CALL(*MI); 2674 return; 2675 case TargetOpcode::PATCHABLE_EVENT_CALL: 2676 return LowerPATCHABLE_EVENT_CALL(*MI, false); 2677 case TargetOpcode::PATCHABLE_TYPED_EVENT_CALL: 2678 return LowerPATCHABLE_EVENT_CALL(*MI, true); 2679 2680 case AArch64::KCFI_CHECK: 2681 LowerKCFI_CHECK(*MI); 2682 return; 2683 2684 case AArch64::HWASAN_CHECK_MEMACCESS: 2685 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES: 2686 case AArch64::HWASAN_CHECK_MEMACCESS_FIXEDSHADOW: 2687 case AArch64::HWASAN_CHECK_MEMACCESS_SHORTGRANULES_FIXEDSHADOW: 2688 LowerHWASAN_CHECK_MEMACCESS(*MI); 2689 return; 2690 2691 case AArch64::SEH_StackAlloc: 2692 TS->emitARM64WinCFIAllocStack(MI->getOperand(0).getImm()); 2693 return; 2694 2695 case AArch64::SEH_SaveFPLR: 2696 TS->emitARM64WinCFISaveFPLR(MI->getOperand(0).getImm()); 2697 return; 2698 2699 case AArch64::SEH_SaveFPLR_X: 2700 assert(MI->getOperand(0).getImm() < 0 && 2701 "Pre increment SEH opcode must have a negative offset"); 2702 TS->emitARM64WinCFISaveFPLRX(-MI->getOperand(0).getImm()); 2703 return; 2704 2705 case AArch64::SEH_SaveReg: 2706 TS->emitARM64WinCFISaveReg(MI->getOperand(0).getImm(), 2707 MI->getOperand(1).getImm()); 2708 return; 2709 2710 case AArch64::SEH_SaveReg_X: 2711 assert(MI->getOperand(1).getImm() < 0 && 2712 "Pre increment SEH opcode must have a negative offset"); 2713 TS->emitARM64WinCFISaveRegX(MI->getOperand(0).getImm(), 2714 -MI->getOperand(1).getImm()); 2715 return; 2716 2717 case AArch64::SEH_SaveRegP: 2718 if (MI->getOperand(1).getImm() == 30 && MI->getOperand(0).getImm() >= 19 && 2719 MI->getOperand(0).getImm() <= 28) { 2720 assert((MI->getOperand(0).getImm() - 19) % 2 == 0 && 2721 "Register paired with LR must be odd"); 2722 TS->emitARM64WinCFISaveLRPair(MI->getOperand(0).getImm(), 2723 MI->getOperand(2).getImm()); 2724 return; 2725 } 2726 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) && 2727 "Non-consecutive registers not allowed for save_regp"); 2728 TS->emitARM64WinCFISaveRegP(MI->getOperand(0).getImm(), 2729 MI->getOperand(2).getImm()); 2730 return; 2731 2732 case AArch64::SEH_SaveRegP_X: 2733 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) && 2734 "Non-consecutive registers not allowed for save_regp_x"); 2735 assert(MI->getOperand(2).getImm() < 0 && 2736 "Pre increment SEH opcode must have a negative offset"); 2737 TS->emitARM64WinCFISaveRegPX(MI->getOperand(0).getImm(), 2738 -MI->getOperand(2).getImm()); 2739 return; 2740 2741 case AArch64::SEH_SaveFReg: 2742 TS->emitARM64WinCFISaveFReg(MI->getOperand(0).getImm(), 2743 MI->getOperand(1).getImm()); 2744 return; 2745 2746 case AArch64::SEH_SaveFReg_X: 2747 assert(MI->getOperand(1).getImm() < 0 && 2748 "Pre increment SEH opcode must have a negative offset"); 2749 TS->emitARM64WinCFISaveFRegX(MI->getOperand(0).getImm(), 2750 -MI->getOperand(1).getImm()); 2751 return; 2752 2753 case AArch64::SEH_SaveFRegP: 2754 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) && 2755 "Non-consecutive registers not allowed for save_regp"); 2756 TS->emitARM64WinCFISaveFRegP(MI->getOperand(0).getImm(), 2757 MI->getOperand(2).getImm()); 2758 return; 2759 2760 case AArch64::SEH_SaveFRegP_X: 2761 assert((MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1) && 2762 "Non-consecutive registers not allowed for save_regp_x"); 2763 assert(MI->getOperand(2).getImm() < 0 && 2764 "Pre increment SEH opcode must have a negative offset"); 2765 TS->emitARM64WinCFISaveFRegPX(MI->getOperand(0).getImm(), 2766 -MI->getOperand(2).getImm()); 2767 return; 2768 2769 case AArch64::SEH_SetFP: 2770 TS->emitARM64WinCFISetFP(); 2771 return; 2772 2773 case AArch64::SEH_AddFP: 2774 TS->emitARM64WinCFIAddFP(MI->getOperand(0).getImm()); 2775 return; 2776 2777 case AArch64::SEH_Nop: 2778 TS->emitARM64WinCFINop(); 2779 return; 2780 2781 case AArch64::SEH_PrologEnd: 2782 TS->emitARM64WinCFIPrologEnd(); 2783 return; 2784 2785 case AArch64::SEH_EpilogStart: 2786 TS->emitARM64WinCFIEpilogStart(); 2787 return; 2788 2789 case AArch64::SEH_EpilogEnd: 2790 TS->emitARM64WinCFIEpilogEnd(); 2791 return; 2792 2793 case AArch64::SEH_PACSignLR: 2794 TS->emitARM64WinCFIPACSignLR(); 2795 return; 2796 2797 case AArch64::SEH_SaveAnyRegQP: 2798 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 && 2799 "Non-consecutive registers not allowed for save_any_reg"); 2800 assert(MI->getOperand(2).getImm() >= 0 && 2801 "SaveAnyRegQP SEH opcode offset must be non-negative"); 2802 assert(MI->getOperand(2).getImm() <= 1008 && 2803 "SaveAnyRegQP SEH opcode offset must fit into 6 bits"); 2804 TS->emitARM64WinCFISaveAnyRegQP(MI->getOperand(0).getImm(), 2805 MI->getOperand(2).getImm()); 2806 return; 2807 2808 case AArch64::SEH_SaveAnyRegQPX: 2809 assert(MI->getOperand(1).getImm() - MI->getOperand(0).getImm() == 1 && 2810 "Non-consecutive registers not allowed for save_any_reg"); 2811 assert(MI->getOperand(2).getImm() < 0 && 2812 "SaveAnyRegQPX SEH opcode offset must be negative"); 2813 assert(MI->getOperand(2).getImm() >= -1008 && 2814 "SaveAnyRegQPX SEH opcode offset must fit into 6 bits"); 2815 TS->emitARM64WinCFISaveAnyRegQPX(MI->getOperand(0).getImm(), 2816 -MI->getOperand(2).getImm()); 2817 return; 2818 } 2819 2820 // Finally, do the automated lowerings for everything else. 2821 MCInst TmpInst; 2822 MCInstLowering.Lower(MI, TmpInst); 2823 EmitToStreamer(*OutStreamer, TmpInst); 2824 } 2825 2826 void AArch64AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI, 2827 MCSymbol *LazyPointer) { 2828 // _ifunc: 2829 // adrp x16, lazy_pointer@GOTPAGE 2830 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] 2831 // ldr x16, [x16] 2832 // br x16 2833 2834 { 2835 MCInst Adrp; 2836 Adrp.setOpcode(AArch64::ADRP); 2837 Adrp.addOperand(MCOperand::createReg(AArch64::X16)); 2838 MCOperand SymPage; 2839 MCInstLowering.lowerOperand( 2840 MachineOperand::CreateMCSymbol(LazyPointer, 2841 AArch64II::MO_GOT | AArch64II::MO_PAGE), 2842 SymPage); 2843 Adrp.addOperand(SymPage); 2844 OutStreamer->emitInstruction(Adrp, *STI); 2845 } 2846 2847 { 2848 MCInst Ldr; 2849 Ldr.setOpcode(AArch64::LDRXui); 2850 Ldr.addOperand(MCOperand::createReg(AArch64::X16)); 2851 Ldr.addOperand(MCOperand::createReg(AArch64::X16)); 2852 MCOperand SymPageOff; 2853 MCInstLowering.lowerOperand( 2854 MachineOperand::CreateMCSymbol(LazyPointer, AArch64II::MO_GOT | 2855 AArch64II::MO_PAGEOFF), 2856 SymPageOff); 2857 Ldr.addOperand(SymPageOff); 2858 Ldr.addOperand(MCOperand::createImm(0)); 2859 OutStreamer->emitInstruction(Ldr, *STI); 2860 } 2861 2862 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDRXui) 2863 .addReg(AArch64::X16) 2864 .addReg(AArch64::X16) 2865 .addImm(0), 2866 *STI); 2867 2868 OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e() 2869 ? AArch64::BRAAZ 2870 : AArch64::BR) 2871 .addReg(AArch64::X16), 2872 *STI); 2873 } 2874 2875 void AArch64AsmPrinter::emitMachOIFuncStubHelperBody(Module &M, 2876 const GlobalIFunc &GI, 2877 MCSymbol *LazyPointer) { 2878 // These stub helpers are only ever called once, so here we're optimizing for 2879 // minimum size by using the pre-indexed store variants, which saves a few 2880 // bytes of instructions to bump & restore sp. 2881 2882 // _ifunc.stub_helper: 2883 // stp fp, lr, [sp, #-16]! 2884 // mov fp, sp 2885 // stp x1, x0, [sp, #-16]! 2886 // stp x3, x2, [sp, #-16]! 2887 // stp x5, x4, [sp, #-16]! 2888 // stp x7, x6, [sp, #-16]! 2889 // stp d1, d0, [sp, #-16]! 2890 // stp d3, d2, [sp, #-16]! 2891 // stp d5, d4, [sp, #-16]! 2892 // stp d7, d6, [sp, #-16]! 2893 // bl _resolver 2894 // adrp x16, lazy_pointer@GOTPAGE 2895 // ldr x16, [x16, lazy_pointer@GOTPAGEOFF] 2896 // str x0, [x16] 2897 // mov x16, x0 2898 // ldp d7, d6, [sp], #16 2899 // ldp d5, d4, [sp], #16 2900 // ldp d3, d2, [sp], #16 2901 // ldp d1, d0, [sp], #16 2902 // ldp x7, x6, [sp], #16 2903 // ldp x5, x4, [sp], #16 2904 // ldp x3, x2, [sp], #16 2905 // ldp x1, x0, [sp], #16 2906 // ldp fp, lr, [sp], #16 2907 // br x16 2908 2909 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) 2910 .addReg(AArch64::SP) 2911 .addReg(AArch64::FP) 2912 .addReg(AArch64::LR) 2913 .addReg(AArch64::SP) 2914 .addImm(-2), 2915 *STI); 2916 2917 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) 2918 .addReg(AArch64::FP) 2919 .addReg(AArch64::SP) 2920 .addImm(0) 2921 .addImm(0), 2922 *STI); 2923 2924 for (int I = 0; I != 4; ++I) 2925 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPXpre) 2926 .addReg(AArch64::SP) 2927 .addReg(AArch64::X1 + 2 * I) 2928 .addReg(AArch64::X0 + 2 * I) 2929 .addReg(AArch64::SP) 2930 .addImm(-2), 2931 *STI); 2932 2933 for (int I = 0; I != 4; ++I) 2934 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STPDpre) 2935 .addReg(AArch64::SP) 2936 .addReg(AArch64::D1 + 2 * I) 2937 .addReg(AArch64::D0 + 2 * I) 2938 .addReg(AArch64::SP) 2939 .addImm(-2), 2940 *STI); 2941 2942 OutStreamer->emitInstruction( 2943 MCInstBuilder(AArch64::BL) 2944 .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))), 2945 *STI); 2946 2947 { 2948 MCInst Adrp; 2949 Adrp.setOpcode(AArch64::ADRP); 2950 Adrp.addOperand(MCOperand::createReg(AArch64::X16)); 2951 MCOperand SymPage; 2952 MCInstLowering.lowerOperand( 2953 MachineOperand::CreateES(LazyPointer->getName().data() + 1, 2954 AArch64II::MO_GOT | AArch64II::MO_PAGE), 2955 SymPage); 2956 Adrp.addOperand(SymPage); 2957 OutStreamer->emitInstruction(Adrp, *STI); 2958 } 2959 2960 { 2961 MCInst Ldr; 2962 Ldr.setOpcode(AArch64::LDRXui); 2963 Ldr.addOperand(MCOperand::createReg(AArch64::X16)); 2964 Ldr.addOperand(MCOperand::createReg(AArch64::X16)); 2965 MCOperand SymPageOff; 2966 MCInstLowering.lowerOperand( 2967 MachineOperand::CreateES(LazyPointer->getName().data() + 1, 2968 AArch64II::MO_GOT | AArch64II::MO_PAGEOFF), 2969 SymPageOff); 2970 Ldr.addOperand(SymPageOff); 2971 Ldr.addOperand(MCOperand::createImm(0)); 2972 OutStreamer->emitInstruction(Ldr, *STI); 2973 } 2974 2975 OutStreamer->emitInstruction(MCInstBuilder(AArch64::STRXui) 2976 .addReg(AArch64::X0) 2977 .addReg(AArch64::X16) 2978 .addImm(0), 2979 *STI); 2980 2981 OutStreamer->emitInstruction(MCInstBuilder(AArch64::ADDXri) 2982 .addReg(AArch64::X16) 2983 .addReg(AArch64::X0) 2984 .addImm(0) 2985 .addImm(0), 2986 *STI); 2987 2988 for (int I = 3; I != -1; --I) 2989 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPDpost) 2990 .addReg(AArch64::SP) 2991 .addReg(AArch64::D1 + 2 * I) 2992 .addReg(AArch64::D0 + 2 * I) 2993 .addReg(AArch64::SP) 2994 .addImm(2), 2995 *STI); 2996 2997 for (int I = 3; I != -1; --I) 2998 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) 2999 .addReg(AArch64::SP) 3000 .addReg(AArch64::X1 + 2 * I) 3001 .addReg(AArch64::X0 + 2 * I) 3002 .addReg(AArch64::SP) 3003 .addImm(2), 3004 *STI); 3005 3006 OutStreamer->emitInstruction(MCInstBuilder(AArch64::LDPXpost) 3007 .addReg(AArch64::SP) 3008 .addReg(AArch64::FP) 3009 .addReg(AArch64::LR) 3010 .addReg(AArch64::SP) 3011 .addImm(2), 3012 *STI); 3013 3014 OutStreamer->emitInstruction(MCInstBuilder(TM.getTargetTriple().isArm64e() 3015 ? AArch64::BRAAZ 3016 : AArch64::BR) 3017 .addReg(AArch64::X16), 3018 *STI); 3019 } 3020 3021 const MCExpr *AArch64AsmPrinter::lowerConstant(const Constant *CV) { 3022 if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) { 3023 return MCSymbolRefExpr::create(MCInstLowering.GetGlobalValueSymbol(GV, 0), 3024 OutContext); 3025 } 3026 3027 return AsmPrinter::lowerConstant(CV); 3028 } 3029 3030 // Force static initialization. 3031 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmPrinter() { 3032 RegisterAsmPrinter<AArch64AsmPrinter> X(getTheAArch64leTarget()); 3033 RegisterAsmPrinter<AArch64AsmPrinter> Y(getTheAArch64beTarget()); 3034 RegisterAsmPrinter<AArch64AsmPrinter> Z(getTheARM64Target()); 3035 RegisterAsmPrinter<AArch64AsmPrinter> W(getTheARM64_32Target()); 3036 RegisterAsmPrinter<AArch64AsmPrinter> V(getTheAArch64_32Target()); 3037 } 3038