1122 lines · cpp
1//===-- X86AsmPrinter.cpp - Convert X86 LLVM code to AT&T assembly --------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains a printer that converts from our internal representation10// of machine-dependent LLVM code to X86 machine code.11//12//===----------------------------------------------------------------------===//13 14#include "X86AsmPrinter.h"15#include "MCTargetDesc/X86ATTInstPrinter.h"16#include "MCTargetDesc/X86BaseInfo.h"17#include "MCTargetDesc/X86MCTargetDesc.h"18#include "MCTargetDesc/X86TargetStreamer.h"19#include "TargetInfo/X86TargetInfo.h"20#include "X86.h"21#include "X86InstrInfo.h"22#include "X86MachineFunctionInfo.h"23#include "X86Subtarget.h"24#include "llvm-c/Visibility.h"25#include "llvm/Analysis/StaticDataProfileInfo.h"26#include "llvm/BinaryFormat/COFF.h"27#include "llvm/BinaryFormat/ELF.h"28#include "llvm/CodeGen/MachineConstantPool.h"29#include "llvm/CodeGen/MachineModuleInfoImpls.h"30#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"31#include "llvm/CodeGenTypes/MachineValueType.h"32#include "llvm/IR/DerivedTypes.h"33#include "llvm/IR/InlineAsm.h"34#include "llvm/IR/InstIterator.h"35#include "llvm/IR/Mangler.h"36#include "llvm/IR/Module.h"37#include "llvm/IR/Type.h"38#include "llvm/MC/MCAsmInfo.h"39#include "llvm/MC/MCCodeEmitter.h"40#include "llvm/MC/MCContext.h"41#include "llvm/MC/MCExpr.h"42#include "llvm/MC/MCInst.h"43#include "llvm/MC/MCInstBuilder.h"44#include "llvm/MC/MCSectionCOFF.h"45#include "llvm/MC/MCSectionELF.h"46#include "llvm/MC/MCSectionMachO.h"47#include "llvm/MC/MCStreamer.h"48#include "llvm/MC/MCSymbol.h"49#include "llvm/MC/TargetRegistry.h"50#include "llvm/Support/Debug.h"51#include "llvm/Support/ErrorHandling.h"52#include "llvm/Target/TargetMachine.h"53 54using namespace llvm;55 56X86AsmPrinter::X86AsmPrinter(TargetMachine &TM,57 std::unique_ptr<MCStreamer> Streamer)58 : AsmPrinter(TM, std::move(Streamer), ID), FM(*this) {}59 60//===----------------------------------------------------------------------===//61// Primitive Helper Functions.62//===----------------------------------------------------------------------===//63 64/// runOnMachineFunction - Emit the function body.65///66bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) {67 if (auto *PSIW = getAnalysisIfAvailable<ProfileSummaryInfoWrapperPass>())68 PSI = &PSIW->getPSI();69 if (auto *SDPIW = getAnalysisIfAvailable<StaticDataProfileInfoWrapperPass>())70 SDPI = &SDPIW->getStaticDataProfileInfo();71 72 Subtarget = &MF.getSubtarget<X86Subtarget>();73 74 SMShadowTracker.startFunction(MF);75 CodeEmitter.reset(TM.getTarget().createMCCodeEmitter(76 *Subtarget->getInstrInfo(), MF.getContext()));77 78 const Module *M = MF.getFunction().getParent();79 EmitFPOData = Subtarget->isTargetWin32() && M->getCodeViewFlag();80 81 IndCSPrefix = M->getModuleFlag("indirect_branch_cs_prefix");82 83 SetupMachineFunction(MF);84 85 if (Subtarget->isTargetCOFF()) {86 bool Local = MF.getFunction().hasLocalLinkage();87 OutStreamer->beginCOFFSymbolDef(CurrentFnSym);88 OutStreamer->emitCOFFSymbolStorageClass(89 Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL);90 OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION91 << COFF::SCT_COMPLEX_TYPE_SHIFT);92 OutStreamer->endCOFFSymbolDef();93 }94 95 // Emit the rest of the function body.96 emitFunctionBody();97 98 // Emit the XRay table for this function.99 emitXRayTable();100 101 EmitFPOData = false;102 103 IndCSPrefix = false;104 105 // We didn't modify anything.106 return false;107}108 109void X86AsmPrinter::emitFunctionBodyStart() {110 if (EmitFPOData) {111 auto *XTS =112 static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());113 XTS->emitFPOProc(114 CurrentFnSym,115 MF->getInfo<X86MachineFunctionInfo>()->getArgumentStackSize());116 }117}118 119void X86AsmPrinter::emitFunctionBodyEnd() {120 if (EmitFPOData) {121 auto *XTS =122 static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());123 XTS->emitFPOEndProc();124 }125}126 127uint32_t X86AsmPrinter::MaskKCFIType(uint32_t Value) {128 // If the type hash matches an invalid pattern, mask the value.129 const uint32_t InvalidValues[] = {130 0xFA1E0FF3, /* ENDBR64 */131 0xFB1E0FF3, /* ENDBR32 */132 };133 for (uint32_t N : InvalidValues) {134 // LowerKCFI_CHECK emits -Value for indirect call checks, so we must also135 // mask that. Note that -(Value + 1) == ~Value.136 if (N == Value || -N == Value)137 return Value + 1;138 }139 return Value;140}141 142void X86AsmPrinter::EmitKCFITypePadding(const MachineFunction &MF,143 bool HasType) {144 // Keep the function entry aligned, taking patchable-function-prefix into145 // account if set.146 int64_t PrefixBytes = 0;147 (void)MF.getFunction()148 .getFnAttribute("patchable-function-prefix")149 .getValueAsString()150 .getAsInteger(10, PrefixBytes);151 152 // Also take the type identifier into account if we're emitting153 // one. Otherwise, just pad with nops. The X86::MOV32ri instruction emitted154 // in X86AsmPrinter::emitKCFITypeId is 5 bytes long.155 if (HasType)156 PrefixBytes += 5;157 158 emitNops(offsetToAlignment(PrefixBytes, MF.getAlignment()));159}160 161/// emitKCFITypeId - Emit the KCFI type information in architecture specific162/// format.163void X86AsmPrinter::emitKCFITypeId(const MachineFunction &MF) {164 const Function &F = MF.getFunction();165 if (!F.getParent()->getModuleFlag("kcfi"))166 return;167 168 ConstantInt *Type = nullptr;169 if (const MDNode *MD = F.getMetadata(LLVMContext::MD_kcfi_type))170 Type = mdconst::extract<ConstantInt>(MD->getOperand(0));171 172 // If we don't have a type to emit, just emit padding if needed to maintain173 // the same alignment for all functions.174 if (!Type) {175 EmitKCFITypePadding(MF, /*HasType=*/false);176 return;177 }178 179 // Emit a function symbol for the type data to avoid unreachable instruction180 // warnings from binary validation tools, and use the same linkage as the181 // parent function. Note that using local linkage would result in duplicate182 // symbols for weak parent functions.183 MCSymbol *FnSym = OutContext.getOrCreateSymbol("__cfi_" + MF.getName());184 emitLinkage(&MF.getFunction(), FnSym);185 if (MAI->hasDotTypeDotSizeDirective())186 OutStreamer->emitSymbolAttribute(FnSym, MCSA_ELF_TypeFunction);187 OutStreamer->emitLabel(FnSym);188 189 // Embed the type hash in the X86::MOV32ri instruction to avoid special190 // casing object file parsers.191 EmitKCFITypePadding(MF);192 unsigned DestReg = X86::EAX;193 194 if (F.getParent()->getModuleFlag("kcfi-arity")) {195 // The ArityToRegMap assumes the 64-bit SysV ABI.196 [[maybe_unused]] const auto &Triple = MF.getTarget().getTargetTriple();197 assert(Triple.isX86_64() && !Triple.isOSWindows());198 199 // Determine the function's arity (i.e., the number of arguments) at the ABI200 // level by counting the number of parameters that are passed201 // as registers, such as pointers and 64-bit (or smaller) integers. The202 // Linux x86-64 ABI allows up to 6 integer parameters to be passed in GPRs.203 // Additional parameters or parameters larger than 64 bits may be passed on204 // the stack, in which case the arity is denoted as 7. Floating-point205 // arguments passed in XMM0-XMM7 are not counted toward arity because206 // floating-point values are not relevant to enforcing kCFI at this time.207 const unsigned ArityToRegMap[8] = {X86::EAX, X86::ECX, X86::EDX, X86::EBX,208 X86::ESP, X86::EBP, X86::ESI, X86::EDI};209 int Arity;210 if (MF.getInfo<X86MachineFunctionInfo>()->getArgumentStackSize() > 0) {211 Arity = 7;212 } else {213 Arity = 0;214 for (const auto &LI : MF.getRegInfo().liveins()) {215 auto Reg = LI.first;216 if (X86::GR8RegClass.contains(Reg) || X86::GR16RegClass.contains(Reg) ||217 X86::GR32RegClass.contains(Reg) ||218 X86::GR64RegClass.contains(Reg)) {219 ++Arity;220 }221 }222 }223 DestReg = ArityToRegMap[Arity];224 }225 226 EmitAndCountInstruction(MCInstBuilder(X86::MOV32ri)227 .addReg(DestReg)228 .addImm(MaskKCFIType(Type->getZExtValue())));229 230 if (MAI->hasDotTypeDotSizeDirective()) {231 MCSymbol *EndSym = OutContext.createTempSymbol("cfi_func_end");232 OutStreamer->emitLabel(EndSym);233 234 const MCExpr *SizeExp = MCBinaryExpr::createSub(235 MCSymbolRefExpr::create(EndSym, OutContext),236 MCSymbolRefExpr::create(FnSym, OutContext), OutContext);237 OutStreamer->emitELFSize(FnSym, SizeExp);238 }239}240 241/// PrintSymbolOperand - Print a raw symbol reference operand. This handles242/// jump tables, constant pools, global address and external symbols, all of243/// which print to a label with various suffixes for relocation types etc.244void X86AsmPrinter::PrintSymbolOperand(const MachineOperand &MO,245 raw_ostream &O) {246 switch (MO.getType()) {247 default: llvm_unreachable("unknown symbol type!");248 case MachineOperand::MO_ConstantPoolIndex:249 GetCPISymbol(MO.getIndex())->print(O, MAI);250 printOffset(MO.getOffset(), O);251 break;252 case MachineOperand::MO_GlobalAddress: {253 const GlobalValue *GV = MO.getGlobal();254 255 MCSymbol *GVSym;256 if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY ||257 MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE)258 GVSym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");259 else260 GVSym = getSymbolPreferLocal(*GV);261 262 // Handle dllimport linkage.263 if (MO.getTargetFlags() == X86II::MO_DLLIMPORT)264 GVSym = OutContext.getOrCreateSymbol(Twine("__imp_") + GVSym->getName());265 else if (MO.getTargetFlags() == X86II::MO_COFFSTUB)266 GVSym =267 OutContext.getOrCreateSymbol(Twine(".refptr.") + GVSym->getName());268 269 if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY ||270 MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) {271 MCSymbol *Sym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");272 MachineModuleInfoImpl::StubValueTy &StubSym =273 MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(Sym);274 if (!StubSym.getPointer())275 StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV),276 !GV->hasInternalLinkage());277 }278 279 // If the name begins with a dollar-sign, enclose it in parens. We do this280 // to avoid having it look like an integer immediate to the assembler.281 if (GVSym->getName()[0] != '$')282 GVSym->print(O, MAI);283 else {284 O << '(';285 GVSym->print(O, MAI);286 O << ')';287 }288 printOffset(MO.getOffset(), O);289 break;290 }291 }292 293 switch (MO.getTargetFlags()) {294 default:295 llvm_unreachable("Unknown target flag on GV operand");296 case X86II::MO_NO_FLAG: // No flag.297 break;298 case X86II::MO_DARWIN_NONLAZY:299 case X86II::MO_DLLIMPORT:300 case X86II::MO_COFFSTUB:301 // These affect the name of the symbol, not any suffix.302 break;303 case X86II::MO_GOT_ABSOLUTE_ADDRESS:304 O << " + [.-";305 MF->getPICBaseSymbol()->print(O, MAI);306 O << ']';307 break;308 case X86II::MO_PIC_BASE_OFFSET:309 case X86II::MO_DARWIN_NONLAZY_PIC_BASE:310 O << '-';311 MF->getPICBaseSymbol()->print(O, MAI);312 break;313 case X86II::MO_TLSGD: O << "@TLSGD"; break;314 case X86II::MO_TLSLD: O << "@TLSLD"; break;315 case X86II::MO_TLSLDM: O << "@TLSLDM"; break;316 case X86II::MO_GOTTPOFF: O << "@GOTTPOFF"; break;317 case X86II::MO_INDNTPOFF: O << "@INDNTPOFF"; break;318 case X86II::MO_TPOFF: O << "@TPOFF"; break;319 case X86II::MO_DTPOFF: O << "@DTPOFF"; break;320 case X86II::MO_NTPOFF: O << "@NTPOFF"; break;321 case X86II::MO_GOTNTPOFF: O << "@GOTNTPOFF"; break;322 case X86II::MO_GOTPCREL: O << "@GOTPCREL"; break;323 case X86II::MO_GOTPCREL_NORELAX: O << "@GOTPCREL_NORELAX"; break;324 case X86II::MO_GOT: O << "@GOT"; break;325 case X86II::MO_GOTOFF: O << "@GOTOFF"; break;326 case X86II::MO_PLT: O << "@PLT"; break;327 case X86II::MO_TLVP: O << "@TLVP"; break;328 case X86II::MO_TLVP_PIC_BASE:329 O << "@TLVP" << '-';330 MF->getPICBaseSymbol()->print(O, MAI);331 break;332 case X86II::MO_SECREL: O << "@SECREL32"; break;333 }334}335 336void X86AsmPrinter::PrintOperand(const MachineInstr *MI, unsigned OpNo,337 raw_ostream &O) {338 const MachineOperand &MO = MI->getOperand(OpNo);339 const bool IsATT = MI->getInlineAsmDialect() == InlineAsm::AD_ATT;340 switch (MO.getType()) {341 default: llvm_unreachable("unknown operand type!");342 case MachineOperand::MO_Register: {343 if (IsATT)344 O << '%';345 O << X86ATTInstPrinter::getRegisterName(MO.getReg());346 return;347 }348 349 case MachineOperand::MO_Immediate:350 if (IsATT)351 O << '$';352 O << MO.getImm();353 return;354 355 case MachineOperand::MO_ConstantPoolIndex:356 case MachineOperand::MO_GlobalAddress: {357 switch (MI->getInlineAsmDialect()) {358 case InlineAsm::AD_ATT:359 O << '$';360 break;361 case InlineAsm::AD_Intel:362 O << "offset ";363 break;364 }365 PrintSymbolOperand(MO, O);366 break;367 }368 case MachineOperand::MO_BlockAddress: {369 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());370 Sym->print(O, MAI);371 break;372 }373 }374}375 376/// PrintModifiedOperand - Print subregisters based on supplied modifier,377/// deferring to PrintOperand() if no modifier was supplied or if operand is not378/// a register.379void X86AsmPrinter::PrintModifiedOperand(const MachineInstr *MI, unsigned OpNo,380 raw_ostream &O, StringRef Modifier) {381 const MachineOperand &MO = MI->getOperand(OpNo);382 if (Modifier.empty() || !MO.isReg())383 return PrintOperand(MI, OpNo, O);384 if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)385 O << '%';386 Register Reg = MO.getReg();387 if (Modifier.consume_front("subreg")) {388 unsigned Size = (Modifier == "64") ? 64389 : (Modifier == "32") ? 32390 : (Modifier == "16") ? 16391 : 8;392 Reg = getX86SubSuperRegister(Reg, Size);393 }394 O << X86ATTInstPrinter::getRegisterName(Reg);395}396 397/// PrintPCRelImm - This is used to print an immediate value that ends up398/// being encoded as a pc-relative value. These print slightly differently, for399/// example, a $ is not emitted.400void X86AsmPrinter::PrintPCRelImm(const MachineInstr *MI, unsigned OpNo,401 raw_ostream &O) {402 const MachineOperand &MO = MI->getOperand(OpNo);403 switch (MO.getType()) {404 default: llvm_unreachable("Unknown pcrel immediate operand");405 case MachineOperand::MO_Register:406 // pc-relativeness was handled when computing the value in the reg.407 PrintOperand(MI, OpNo, O);408 return;409 case MachineOperand::MO_Immediate:410 O << MO.getImm();411 return;412 case MachineOperand::MO_GlobalAddress:413 PrintSymbolOperand(MO, O);414 return;415 }416}417 418void X86AsmPrinter::PrintLeaMemReference(const MachineInstr *MI, unsigned OpNo,419 raw_ostream &O, StringRef Modifier) {420 const MachineOperand &BaseReg = MI->getOperand(OpNo + X86::AddrBaseReg);421 const MachineOperand &IndexReg = MI->getOperand(OpNo + X86::AddrIndexReg);422 const MachineOperand &DispSpec = MI->getOperand(OpNo + X86::AddrDisp);423 424 // If we really don't want to print out (rip), don't.425 bool HasBaseReg = BaseReg.getReg() != 0;426 if (HasBaseReg && Modifier == "no-rip" && BaseReg.getReg() == X86::RIP)427 HasBaseReg = false;428 429 // HasParenPart - True if we will print out the () part of the mem ref.430 bool HasParenPart = IndexReg.getReg() || HasBaseReg;431 432 switch (DispSpec.getType()) {433 default:434 llvm_unreachable("unknown operand type!");435 case MachineOperand::MO_Immediate: {436 int DispVal = DispSpec.getImm();437 if (DispVal || !HasParenPart)438 O << DispVal;439 break;440 }441 case MachineOperand::MO_GlobalAddress:442 case MachineOperand::MO_ConstantPoolIndex:443 PrintSymbolOperand(DispSpec, O);444 break;445 }446 447 if (Modifier == "H")448 O << "+8";449 450 if (HasParenPart) {451 assert(IndexReg.getReg() != X86::ESP &&452 "X86 doesn't allow scaling by ESP");453 454 O << '(';455 if (HasBaseReg)456 PrintModifiedOperand(MI, OpNo + X86::AddrBaseReg, O, Modifier);457 458 if (IndexReg.getReg()) {459 O << ',';460 PrintModifiedOperand(MI, OpNo + X86::AddrIndexReg, O, Modifier);461 unsigned ScaleVal = MI->getOperand(OpNo + X86::AddrScaleAmt).getImm();462 if (ScaleVal != 1)463 O << ',' << ScaleVal;464 }465 O << ')';466 }467}468 469static bool isSimpleReturn(const MachineInstr &MI) {470 // We exclude all tail calls here which set both isReturn and isCall.471 return MI.getDesc().isReturn() && !MI.getDesc().isCall();472}473 474static bool isIndirectBranchOrTailCall(const MachineInstr &MI) {475 unsigned Opc = MI.getOpcode();476 return MI.getDesc().isIndirectBranch() /*Make below code in a good shape*/ ||477 Opc == X86::TAILJMPr || Opc == X86::TAILJMPm ||478 Opc == X86::TAILJMPr64 || Opc == X86::TAILJMPm64 ||479 Opc == X86::TCRETURNri || Opc == X86::TCRETURN_WIN64ri ||480 Opc == X86::TCRETURN_HIPE32ri || Opc == X86::TCRETURNmi ||481 Opc == X86::TCRETURN_WINmi64 || Opc == X86::TCRETURNri64 ||482 Opc == X86::TCRETURNmi64 || Opc == X86::TCRETURNri64_ImpCall ||483 Opc == X86::TAILJMPr64_REX || Opc == X86::TAILJMPm64_REX;484}485 486void X86AsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) {487 if (Subtarget->hardenSlsRet() || Subtarget->hardenSlsIJmp()) {488 auto I = MBB.getLastNonDebugInstr();489 if (I != MBB.end()) {490 if ((Subtarget->hardenSlsRet() && isSimpleReturn(*I)) ||491 (Subtarget->hardenSlsIJmp() && isIndirectBranchOrTailCall(*I))) {492 MCInst TmpInst;493 TmpInst.setOpcode(X86::INT3);494 EmitToStreamer(*OutStreamer, TmpInst);495 }496 }497 }498 AsmPrinter::emitBasicBlockEnd(MBB);499 SMShadowTracker.emitShadowPadding(*OutStreamer, getSubtargetInfo());500}501 502void X86AsmPrinter::PrintMemReference(const MachineInstr *MI, unsigned OpNo,503 raw_ostream &O, StringRef Modifier) {504 assert(isMem(*MI, OpNo) && "Invalid memory reference!");505 const MachineOperand &Segment = MI->getOperand(OpNo + X86::AddrSegmentReg);506 if (Segment.getReg()) {507 PrintModifiedOperand(MI, OpNo + X86::AddrSegmentReg, O, Modifier);508 O << ':';509 }510 PrintLeaMemReference(MI, OpNo, O, Modifier);511}512 513void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,514 unsigned OpNo, raw_ostream &O,515 StringRef Modifier) {516 const MachineOperand &BaseReg = MI->getOperand(OpNo + X86::AddrBaseReg);517 unsigned ScaleVal = MI->getOperand(OpNo + X86::AddrScaleAmt).getImm();518 const MachineOperand &IndexReg = MI->getOperand(OpNo + X86::AddrIndexReg);519 const MachineOperand &DispSpec = MI->getOperand(OpNo + X86::AddrDisp);520 const MachineOperand &SegReg = MI->getOperand(OpNo + X86::AddrSegmentReg);521 522 // If we really don't want to print out (rip), don't.523 bool HasBaseReg = BaseReg.getReg() != 0;524 if (HasBaseReg && Modifier == "no-rip" && BaseReg.getReg() == X86::RIP)525 HasBaseReg = false;526 527 // If we really just want to print out displacement.528 if ((DispSpec.isGlobal() || DispSpec.isSymbol()) && Modifier == "disp-only") {529 HasBaseReg = false;530 }531 532 // If this has a segment register, print it.533 if (SegReg.getReg()) {534 PrintOperand(MI, OpNo + X86::AddrSegmentReg, O);535 O << ':';536 }537 538 O << '[';539 540 bool NeedPlus = false;541 if (HasBaseReg) {542 PrintOperand(MI, OpNo + X86::AddrBaseReg, O);543 NeedPlus = true;544 }545 546 if (IndexReg.getReg()) {547 if (NeedPlus) O << " + ";548 if (ScaleVal != 1)549 O << ScaleVal << '*';550 PrintOperand(MI, OpNo + X86::AddrIndexReg, O);551 NeedPlus = true;552 }553 554 if (!DispSpec.isImm()) {555 if (NeedPlus) O << " + ";556 // Do not add `offset` operator. Matches the behaviour of557 // X86IntelInstPrinter::printMemReference.558 PrintSymbolOperand(DispSpec, O);559 } else {560 int64_t DispVal = DispSpec.getImm();561 if (DispVal || (!IndexReg.getReg() && !HasBaseReg)) {562 if (NeedPlus) {563 if (DispVal > 0)564 O << " + ";565 else {566 O << " - ";567 DispVal = -DispVal;568 }569 }570 O << DispVal;571 }572 }573 O << ']';574}575 576const MCSubtargetInfo *X86AsmPrinter::getIFuncMCSubtargetInfo() const {577 assert(Subtarget);578 return Subtarget;579}580 581void X86AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,582 MCSymbol *LazyPointer) {583 // _ifunc:584 // jmpq *lazy_pointer(%rip)585 586 OutStreamer->emitInstruction(587 MCInstBuilder(X86::JMP32m)588 .addReg(X86::RIP)589 .addImm(1)590 .addReg(0)591 .addOperand(MCOperand::createExpr(592 MCSymbolRefExpr::create(LazyPointer, OutContext)))593 .addReg(0),594 *Subtarget);595}596 597void X86AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,598 const GlobalIFunc &GI,599 MCSymbol *LazyPointer) {600 // _ifunc.stub_helper:601 // push %rax602 // push %rdi603 // push %rsi604 // push %rdx605 // push %rcx606 // push %r8607 // push %r9608 // callq foo609 // movq %rax,lazy_pointer(%rip)610 // pop %r9611 // pop %r8612 // pop %rcx613 // pop %rdx614 // pop %rsi615 // pop %rdi616 // pop %rax617 // jmpq *lazy_pointer(%rip)618 619 for (int Reg :620 {X86::RAX, X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9})621 OutStreamer->emitInstruction(MCInstBuilder(X86::PUSH64r).addReg(Reg),622 *Subtarget);623 624 OutStreamer->emitInstruction(625 MCInstBuilder(X86::CALL64pcrel32)626 .addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),627 *Subtarget);628 629 OutStreamer->emitInstruction(630 MCInstBuilder(X86::MOV64mr)631 .addReg(X86::RIP)632 .addImm(1)633 .addReg(0)634 .addOperand(MCOperand::createExpr(635 MCSymbolRefExpr::create(LazyPointer, OutContext)))636 .addReg(0)637 .addReg(X86::RAX),638 *Subtarget);639 640 for (int Reg :641 {X86::R9, X86::R8, X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RAX})642 OutStreamer->emitInstruction(MCInstBuilder(X86::POP64r).addReg(Reg),643 *Subtarget);644 645 OutStreamer->emitInstruction(646 MCInstBuilder(X86::JMP32m)647 .addReg(X86::RIP)648 .addImm(1)649 .addReg(0)650 .addOperand(MCOperand::createExpr(651 MCSymbolRefExpr::create(LazyPointer, OutContext)))652 .addReg(0),653 *Subtarget);654}655 656static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,657 char Mode, raw_ostream &O) {658 Register Reg = MO.getReg();659 bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;660 661 if (!X86::GR8RegClass.contains(Reg) &&662 !X86::GR16RegClass.contains(Reg) &&663 !X86::GR32RegClass.contains(Reg) &&664 !X86::GR64RegClass.contains(Reg))665 return true;666 667 switch (Mode) {668 default: return true; // Unknown mode.669 case 'b': // Print QImode register670 Reg = getX86SubSuperRegister(Reg, 8);671 break;672 case 'h': // Print QImode high register673 Reg = getX86SubSuperRegister(Reg, 8, true);674 if (!Reg.isValid())675 return true;676 break;677 case 'w': // Print HImode register678 Reg = getX86SubSuperRegister(Reg, 16);679 break;680 case 'k': // Print SImode register681 Reg = getX86SubSuperRegister(Reg, 32);682 break;683 case 'V':684 EmitPercent = false;685 [[fallthrough]];686 case 'q':687 // Print 64-bit register names if 64-bit integer registers are available.688 // Otherwise, print 32-bit register names.689 Reg = getX86SubSuperRegister(Reg, P.getSubtarget().is64Bit() ? 64 : 32);690 break;691 }692 693 if (EmitPercent)694 O << '%';695 696 O << X86ATTInstPrinter::getRegisterName(Reg);697 return false;698}699 700static bool printAsmVRegister(const MachineOperand &MO, char Mode,701 raw_ostream &O) {702 Register Reg = MO.getReg();703 bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;704 705 unsigned Index;706 if (X86::VR128XRegClass.contains(Reg))707 Index = Reg - X86::XMM0;708 else if (X86::VR256XRegClass.contains(Reg))709 Index = Reg - X86::YMM0;710 else if (X86::VR512RegClass.contains(Reg))711 Index = Reg - X86::ZMM0;712 else713 return true;714 715 switch (Mode) {716 default: // Unknown mode.717 return true;718 case 'x': // Print V4SFmode register719 Reg = X86::XMM0 + Index;720 break;721 case 't': // Print V8SFmode register722 Reg = X86::YMM0 + Index;723 break;724 case 'g': // Print V16SFmode register725 Reg = X86::ZMM0 + Index;726 break;727 }728 729 if (EmitPercent)730 O << '%';731 732 O << X86ATTInstPrinter::getRegisterName(Reg);733 return false;734}735 736/// PrintAsmOperand - Print out an operand for an inline asm expression.737///738bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,739 const char *ExtraCode, raw_ostream &O) {740 // Does this asm operand have a single letter operand modifier?741 if (ExtraCode && ExtraCode[0]) {742 if (ExtraCode[1] != 0) return true; // Unknown modifier.743 744 const MachineOperand &MO = MI->getOperand(OpNo);745 746 switch (ExtraCode[0]) {747 default:748 // See if this is a generic print operand749 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);750 case 'a': // This is an address. Currently only 'i' and 'r' are expected.751 switch (MO.getType()) {752 default:753 return true;754 case MachineOperand::MO_Immediate:755 O << MO.getImm();756 return false;757 case MachineOperand::MO_ConstantPoolIndex:758 case MachineOperand::MO_JumpTableIndex:759 case MachineOperand::MO_ExternalSymbol:760 llvm_unreachable("unexpected operand type!");761 case MachineOperand::MO_GlobalAddress:762 PrintSymbolOperand(MO, O);763 if (Subtarget->is64Bit())764 O << "(%rip)";765 return false;766 case MachineOperand::MO_Register:767 O << '(';768 PrintOperand(MI, OpNo, O);769 O << ')';770 return false;771 }772 773 case 'c': // Don't print "$" before a global var name or constant.774 switch (MO.getType()) {775 default:776 PrintOperand(MI, OpNo, O);777 break;778 case MachineOperand::MO_Immediate:779 O << MO.getImm();780 break;781 case MachineOperand::MO_ConstantPoolIndex:782 case MachineOperand::MO_JumpTableIndex:783 case MachineOperand::MO_ExternalSymbol:784 llvm_unreachable("unexpected operand type!");785 case MachineOperand::MO_GlobalAddress:786 PrintSymbolOperand(MO, O);787 break;788 }789 return false;790 791 case 'A': // Print '*' before a register (it must be a register)792 if (MO.isReg()) {793 O << '*';794 PrintOperand(MI, OpNo, O);795 return false;796 }797 return true;798 799 case 'b': // Print QImode register800 case 'h': // Print QImode high register801 case 'w': // Print HImode register802 case 'k': // Print SImode register803 case 'q': // Print DImode register804 case 'V': // Print native register without '%'805 if (MO.isReg())806 return printAsmMRegister(*this, MO, ExtraCode[0], O);807 PrintOperand(MI, OpNo, O);808 return false;809 810 case 'x': // Print V4SFmode register811 case 't': // Print V8SFmode register812 case 'g': // Print V16SFmode register813 if (MO.isReg())814 return printAsmVRegister(MO, ExtraCode[0], O);815 PrintOperand(MI, OpNo, O);816 return false;817 818 case 'p': {819 const MachineOperand &MO = MI->getOperand(OpNo);820 if (MO.getType() != MachineOperand::MO_GlobalAddress)821 return true;822 PrintSymbolOperand(MO, O);823 return false;824 }825 826 case 'P': // This is the operand of a call, treat specially.827 PrintPCRelImm(MI, OpNo, O);828 return false;829 830 case 'n': // Negate the immediate or print a '-' before the operand.831 // Note: this is a temporary solution. It should be handled target832 // independently as part of the 'MC' work.833 if (MO.isImm()) {834 O << -MO.getImm();835 return false;836 }837 O << '-';838 }839 }840 841 PrintOperand(MI, OpNo, O);842 return false;843}844 845bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,846 const char *ExtraCode,847 raw_ostream &O) {848 if (ExtraCode && ExtraCode[0]) {849 if (ExtraCode[1] != 0) return true; // Unknown modifier.850 851 switch (ExtraCode[0]) {852 default: return true; // Unknown modifier.853 case 'b': // Print QImode register854 case 'h': // Print QImode high register855 case 'w': // Print HImode register856 case 'k': // Print SImode register857 case 'q': // Print SImode register858 // These only apply to registers, ignore on mem.859 break;860 case 'H':861 if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {862 return true; // Unsupported modifier in Intel inline assembly.863 } else {864 PrintMemReference(MI, OpNo, O, "H");865 }866 return false;867 // Print memory only with displacement. The Modifer 'P' is used in inline868 // asm to present a call symbol or a global symbol which can not use base869 // reg or index reg.870 case 'P':871 if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {872 PrintIntelMemReference(MI, OpNo, O, "disp-only");873 } else {874 PrintMemReference(MI, OpNo, O, "disp-only");875 }876 return false;877 }878 }879 if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {880 PrintIntelMemReference(MI, OpNo, O);881 } else {882 PrintMemReference(MI, OpNo, O);883 }884 return false;885}886 887void X86AsmPrinter::emitStartOfAsmFile(Module &M) {888 const Triple &TT = TM.getTargetTriple();889 890 if (TT.isOSBinFormatELF()) {891 // Assemble feature flags that may require creation of a note section.892 unsigned FeatureFlagsAnd = 0;893 if (M.getModuleFlag("cf-protection-branch"))894 FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_IBT;895 if (M.getModuleFlag("cf-protection-return"))896 FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_SHSTK;897 898 if (FeatureFlagsAnd) {899 // Emit a .note.gnu.property section with the flags.900 assert((TT.isX86_32() || TT.isX86_64()) &&901 "CFProtection used on invalid architecture!");902 MCSection *Cur = OutStreamer->getCurrentSectionOnly();903 MCSection *Nt = MMI->getContext().getELFSection(904 ".note.gnu.property", ELF::SHT_NOTE, ELF::SHF_ALLOC);905 OutStreamer->switchSection(Nt);906 907 // Emitting note header.908 const int WordSize = TT.isX86_64() && !TT.isX32() ? 8 : 4;909 emitAlignment(WordSize == 4 ? Align(4) : Align(8));910 OutStreamer->emitIntValue(4, 4 /*size*/); // data size for "GNU\0"911 OutStreamer->emitIntValue(8 + WordSize, 4 /*size*/); // Elf_Prop size912 OutStreamer->emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4 /*size*/);913 OutStreamer->emitBytes(StringRef("GNU", 4)); // note name914 915 // Emitting an Elf_Prop for the CET properties.916 OutStreamer->emitInt32(ELF::GNU_PROPERTY_X86_FEATURE_1_AND);917 OutStreamer->emitInt32(4); // data size918 OutStreamer->emitInt32(FeatureFlagsAnd); // data919 emitAlignment(WordSize == 4 ? Align(4) : Align(8)); // padding920 921 OutStreamer->switchSection(Cur);922 }923 }924 925 if (TT.isOSBinFormatMachO())926 OutStreamer->switchSection(getObjFileLowering().getTextSection());927 928 if (TT.isOSBinFormatCOFF()) {929 emitCOFFFeatureSymbol(M);930 emitCOFFReplaceableFunctionData(M);931 932 if (M.getModuleFlag("import-call-optimization"))933 EnableImportCallOptimization = true;934 }935 OutStreamer->emitSyntaxDirective();936 937 // If this is not inline asm and we're in 16-bit938 // mode prefix assembly with .code16.939 bool is16 = TT.getEnvironment() == Triple::CODE16;940 if (M.getModuleInlineAsm().empty() && is16) {941 auto *XTS =942 static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());943 XTS->emitCode16();944 }945}946 947static void948emitNonLazySymbolPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel,949 MachineModuleInfoImpl::StubValueTy &MCSym) {950 // L_foo$stub:951 OutStreamer.emitLabel(StubLabel);952 // .indirect_symbol _foo953 OutStreamer.emitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol);954 955 if (MCSym.getInt())956 // External to current translation unit.957 OutStreamer.emitIntValue(0, 4/*size*/);958 else959 // Internal to current translation unit.960 //961 // When we place the LSDA into the TEXT section, the type info962 // pointers need to be indirect and pc-rel. We accomplish this by963 // using NLPs; however, sometimes the types are local to the file.964 // We need to fill in the value for the NLP in those cases.965 OutStreamer.emitValue(966 MCSymbolRefExpr::create(MCSym.getPointer(), OutStreamer.getContext()),967 4 /*size*/);968}969 970static void emitNonLazyStubs(MachineModuleInfo *MMI, MCStreamer &OutStreamer) {971 972 MachineModuleInfoMachO &MMIMacho =973 MMI->getObjFileInfo<MachineModuleInfoMachO>();974 975 // Output stubs for dynamically-linked functions.976 MachineModuleInfoMachO::SymbolListTy Stubs;977 978 // Output stubs for external and common global variables.979 Stubs = MMIMacho.GetGVStubList();980 if (!Stubs.empty()) {981 OutStreamer.switchSection(MMI->getContext().getMachOSection(982 "__IMPORT", "__pointers", MachO::S_NON_LAZY_SYMBOL_POINTERS,983 SectionKind::getMetadata()));984 985 for (auto &Stub : Stubs)986 emitNonLazySymbolPointer(OutStreamer, Stub.first, Stub.second);987 988 Stubs.clear();989 OutStreamer.addBlankLine();990 }991}992 993/// True if this module is being built for windows/msvc, and uses floating994/// point. This is used to emit an undefined reference to _fltused. This is995/// needed in Windows kernel or driver contexts to find and prevent code from996/// modifying non-GPR registers.997///998/// TODO: It would be better if this was computed from MIR by looking for999/// selected floating-point instructions.1000static bool usesMSVCFloatingPoint(const Triple &TT, const Module &M) {1001 // Only needed for MSVC1002 if (!TT.isWindowsMSVCEnvironment())1003 return false;1004 1005 for (const Function &F : M) {1006 for (const Instruction &I : instructions(F)) {1007 if (I.getType()->isFloatingPointTy())1008 return true;1009 1010 for (const auto &Op : I.operands()) {1011 if (Op->getType()->isFloatingPointTy())1012 return true;1013 }1014 }1015 }1016 1017 return false;1018}1019 1020void X86AsmPrinter::emitEndOfAsmFile(Module &M) {1021 const Triple &TT = TM.getTargetTriple();1022 1023 if (TT.isOSBinFormatMachO()) {1024 // Mach-O uses non-lazy symbol stubs to encode per-TU information into1025 // global table for symbol lookup.1026 emitNonLazyStubs(MMI, *OutStreamer);1027 1028 // Emit fault map information.1029 FM.serializeToFaultMapSection();1030 1031 // This flag tells the linker that no global symbols contain code that fall1032 // through to other global symbols (e.g. an implementation of multiple entry1033 // points). If this doesn't occur, the linker can safely perform dead code1034 // stripping. Since LLVM never generates code that does this, it is always1035 // safe to set.1036 OutStreamer->emitSubsectionsViaSymbols();1037 } else if (TT.isOSBinFormatCOFF()) {1038 // If import call optimization is enabled, emit the appropriate section.1039 // We do this whether or not we recorded any items.1040 if (EnableImportCallOptimization) {1041 OutStreamer->switchSection(getObjFileLowering().getImportCallSection());1042 1043 // Section always starts with some magic.1044 constexpr char ImpCallMagic[12] = "RetpolineV1";1045 OutStreamer->emitBytes(StringRef{ImpCallMagic, sizeof(ImpCallMagic)});1046 1047 // Layout of this section is:1048 // Per section that contains an item to record:1049 // uint32_t SectionSize: Size in bytes for information in this section.1050 // uint32_t Section Number1051 // Per call to imported function in section:1052 // uint32_t Kind: the kind of item.1053 // uint32_t InstOffset: the offset of the instr in its parent section.1054 for (auto &[Section, CallsToImportedFuncs] :1055 SectionToImportedFunctionCalls) {1056 unsigned SectionSize =1057 sizeof(uint32_t) * (2 + 2 * CallsToImportedFuncs.size());1058 OutStreamer->emitInt32(SectionSize);1059 OutStreamer->emitCOFFSecNumber(Section->getBeginSymbol());1060 for (auto &[CallsiteSymbol, Kind] : CallsToImportedFuncs) {1061 OutStreamer->emitInt32(Kind);1062 OutStreamer->emitCOFFSecOffset(CallsiteSymbol);1063 }1064 }1065 }1066 1067 if (usesMSVCFloatingPoint(TT, M)) {1068 // In Windows' libcmt.lib, there is a file which is linked in only if the1069 // symbol _fltused is referenced. Linking this in causes some1070 // side-effects:1071 //1072 // 1. For x86-32, it will set the x87 rounding mode to 53-bit instead of1073 // 64-bit mantissas at program start.1074 //1075 // 2. It links in support routines for floating-point in scanf and printf.1076 //1077 // MSVC emits an undefined reference to _fltused when there are any1078 // floating point operations in the program (including calls). A program1079 // that only has: `scanf("%f", &global_float);` may fail to trigger this,1080 // but oh well...that's a documented issue.1081 StringRef SymbolName =1082 (TT.getArch() == Triple::x86) ? "__fltused" : "_fltused";1083 MCSymbol *S = MMI->getContext().getOrCreateSymbol(SymbolName);1084 OutStreamer->emitSymbolAttribute(S, MCSA_Global);1085 return;1086 }1087 } else if (TT.isOSBinFormatELF()) {1088 FM.serializeToFaultMapSection();1089 }1090 1091 // Emit __morestack address if needed for indirect calls.1092 if (TT.isX86_64() && TM.getCodeModel() == CodeModel::Large) {1093 if (MCSymbol *AddrSymbol = OutContext.lookupSymbol("__morestack_addr")) {1094 Align Alignment(1);1095 MCSection *ReadOnlySection = getObjFileLowering().getSectionForConstant(1096 getDataLayout(), SectionKind::getReadOnly(),1097 /*C=*/nullptr, Alignment);1098 OutStreamer->switchSection(ReadOnlySection);1099 OutStreamer->emitLabel(AddrSymbol);1100 1101 unsigned PtrSize = MAI->getCodePointerSize();1102 OutStreamer->emitSymbolValue(GetExternalSymbolSymbol("__morestack"),1103 PtrSize);1104 }1105 }1106}1107 1108char X86AsmPrinter::ID = 0;1109 1110INITIALIZE_PASS(X86AsmPrinter, "x86-asm-printer", "X86 Assembly Printer", false,1111 false)1112 1113//===----------------------------------------------------------------------===//1114// Target Registry Stuff1115//===----------------------------------------------------------------------===//1116 1117// Force static initialization.1118extern "C" LLVM_C_ABI void LLVMInitializeX86AsmPrinter() {1119 RegisterAsmPrinter<X86AsmPrinter> X(getTheX86_32Target());1120 RegisterAsmPrinter<X86AsmPrinter> Y(getTheX86_64Target());1121}1122