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