Path: blob/main/contrib/llvm-project/llvm/lib/Target/X86/X86AsmPrinter.cpp
35266 views
//===-- X86AsmPrinter.cpp - Convert X86 LLVM code to AT&T assembly --------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains a printer that converts from our internal representation9// of machine-dependent LLVM code to X86 machine code.10//11//===----------------------------------------------------------------------===//1213#include "X86AsmPrinter.h"14#include "MCTargetDesc/X86ATTInstPrinter.h"15#include "MCTargetDesc/X86BaseInfo.h"16#include "MCTargetDesc/X86MCTargetDesc.h"17#include "MCTargetDesc/X86TargetStreamer.h"18#include "TargetInfo/X86TargetInfo.h"19#include "X86InstrInfo.h"20#include "X86MachineFunctionInfo.h"21#include "X86Subtarget.h"22#include "llvm/BinaryFormat/COFF.h"23#include "llvm/BinaryFormat/ELF.h"24#include "llvm/CodeGen/MachineConstantPool.h"25#include "llvm/CodeGen/MachineModuleInfoImpls.h"26#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"27#include "llvm/CodeGenTypes/MachineValueType.h"28#include "llvm/IR/DerivedTypes.h"29#include "llvm/IR/InlineAsm.h"30#include "llvm/IR/Mangler.h"31#include "llvm/IR/Module.h"32#include "llvm/IR/Type.h"33#include "llvm/MC/MCAsmInfo.h"34#include "llvm/MC/MCCodeEmitter.h"35#include "llvm/MC/MCContext.h"36#include "llvm/MC/MCExpr.h"37#include "llvm/MC/MCInst.h"38#include "llvm/MC/MCInstBuilder.h"39#include "llvm/MC/MCSectionCOFF.h"40#include "llvm/MC/MCSectionELF.h"41#include "llvm/MC/MCSectionMachO.h"42#include "llvm/MC/MCStreamer.h"43#include "llvm/MC/MCSymbol.h"44#include "llvm/MC/TargetRegistry.h"45#include "llvm/Support/Debug.h"46#include "llvm/Support/ErrorHandling.h"47#include "llvm/Target/TargetMachine.h"4849using namespace llvm;5051X86AsmPrinter::X86AsmPrinter(TargetMachine &TM,52std::unique_ptr<MCStreamer> Streamer)53: AsmPrinter(TM, std::move(Streamer)), FM(*this) {}5455//===----------------------------------------------------------------------===//56// Primitive Helper Functions.57//===----------------------------------------------------------------------===//5859/// runOnMachineFunction - Emit the function body.60///61bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) {62Subtarget = &MF.getSubtarget<X86Subtarget>();6364SMShadowTracker.startFunction(MF);65CodeEmitter.reset(TM.getTarget().createMCCodeEmitter(66*Subtarget->getInstrInfo(), MF.getContext()));6768const Module *M = MF.getFunction().getParent();69EmitFPOData = Subtarget->isTargetWin32() && M->getCodeViewFlag();7071IndCSPrefix = M->getModuleFlag("indirect_branch_cs_prefix");7273SetupMachineFunction(MF);7475if (Subtarget->isTargetCOFF()) {76bool Local = MF.getFunction().hasLocalLinkage();77OutStreamer->beginCOFFSymbolDef(CurrentFnSym);78OutStreamer->emitCOFFSymbolStorageClass(79Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL);80OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_FUNCTION81<< COFF::SCT_COMPLEX_TYPE_SHIFT);82OutStreamer->endCOFFSymbolDef();83}8485// Emit the rest of the function body.86emitFunctionBody();8788// Emit the XRay table for this function.89emitXRayTable();9091EmitFPOData = false;9293IndCSPrefix = false;9495// We didn't modify anything.96return false;97}9899void X86AsmPrinter::emitFunctionBodyStart() {100if (EmitFPOData) {101auto *XTS =102static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());103XTS->emitFPOProc(104CurrentFnSym,105MF->getInfo<X86MachineFunctionInfo>()->getArgumentStackSize());106}107}108109void X86AsmPrinter::emitFunctionBodyEnd() {110if (EmitFPOData) {111auto *XTS =112static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());113XTS->emitFPOEndProc();114}115}116117uint32_t X86AsmPrinter::MaskKCFIType(uint32_t Value) {118// If the type hash matches an invalid pattern, mask the value.119const uint32_t InvalidValues[] = {1200xFA1E0FF3, /* ENDBR64 */1210xFB1E0FF3, /* ENDBR32 */122};123for (uint32_t N : InvalidValues) {124// LowerKCFI_CHECK emits -Value for indirect call checks, so we must also125// mask that. Note that -(Value + 1) == ~Value.126if (N == Value || -N == Value)127return Value + 1;128}129return Value;130}131132void X86AsmPrinter::EmitKCFITypePadding(const MachineFunction &MF,133bool HasType) {134// Keep the function entry aligned, taking patchable-function-prefix into135// account if set.136int64_t PrefixBytes = 0;137(void)MF.getFunction()138.getFnAttribute("patchable-function-prefix")139.getValueAsString()140.getAsInteger(10, PrefixBytes);141142// Also take the type identifier into account if we're emitting143// one. Otherwise, just pad with nops. The X86::MOV32ri instruction emitted144// in X86AsmPrinter::emitKCFITypeId is 5 bytes long.145if (HasType)146PrefixBytes += 5;147148emitNops(offsetToAlignment(PrefixBytes, MF.getAlignment()));149}150151/// emitKCFITypeId - Emit the KCFI type information in architecture specific152/// format.153void X86AsmPrinter::emitKCFITypeId(const MachineFunction &MF) {154const Function &F = MF.getFunction();155if (!F.getParent()->getModuleFlag("kcfi"))156return;157158ConstantInt *Type = nullptr;159if (const MDNode *MD = F.getMetadata(LLVMContext::MD_kcfi_type))160Type = mdconst::extract<ConstantInt>(MD->getOperand(0));161162// If we don't have a type to emit, just emit padding if needed to maintain163// the same alignment for all functions.164if (!Type) {165EmitKCFITypePadding(MF, /*HasType=*/false);166return;167}168169// Emit a function symbol for the type data to avoid unreachable instruction170// warnings from binary validation tools, and use the same linkage as the171// parent function. Note that using local linkage would result in duplicate172// symbols for weak parent functions.173MCSymbol *FnSym = OutContext.getOrCreateSymbol("__cfi_" + MF.getName());174emitLinkage(&MF.getFunction(), FnSym);175if (MAI->hasDotTypeDotSizeDirective())176OutStreamer->emitSymbolAttribute(FnSym, MCSA_ELF_TypeFunction);177OutStreamer->emitLabel(FnSym);178179// Embed the type hash in the X86::MOV32ri instruction to avoid special180// casing object file parsers.181EmitKCFITypePadding(MF);182EmitAndCountInstruction(MCInstBuilder(X86::MOV32ri)183.addReg(X86::EAX)184.addImm(MaskKCFIType(Type->getZExtValue())));185186if (MAI->hasDotTypeDotSizeDirective()) {187MCSymbol *EndSym = OutContext.createTempSymbol("cfi_func_end");188OutStreamer->emitLabel(EndSym);189190const MCExpr *SizeExp = MCBinaryExpr::createSub(191MCSymbolRefExpr::create(EndSym, OutContext),192MCSymbolRefExpr::create(FnSym, OutContext), OutContext);193OutStreamer->emitELFSize(FnSym, SizeExp);194}195}196197/// PrintSymbolOperand - Print a raw symbol reference operand. This handles198/// jump tables, constant pools, global address and external symbols, all of199/// which print to a label with various suffixes for relocation types etc.200void X86AsmPrinter::PrintSymbolOperand(const MachineOperand &MO,201raw_ostream &O) {202switch (MO.getType()) {203default: llvm_unreachable("unknown symbol type!");204case MachineOperand::MO_ConstantPoolIndex:205GetCPISymbol(MO.getIndex())->print(O, MAI);206printOffset(MO.getOffset(), O);207break;208case MachineOperand::MO_GlobalAddress: {209const GlobalValue *GV = MO.getGlobal();210211MCSymbol *GVSym;212if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY ||213MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE)214GVSym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");215else216GVSym = getSymbolPreferLocal(*GV);217218// Handle dllimport linkage.219if (MO.getTargetFlags() == X86II::MO_DLLIMPORT)220GVSym = OutContext.getOrCreateSymbol(Twine("__imp_") + GVSym->getName());221else if (MO.getTargetFlags() == X86II::MO_COFFSTUB)222GVSym =223OutContext.getOrCreateSymbol(Twine(".refptr.") + GVSym->getName());224225if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY ||226MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) {227MCSymbol *Sym = getSymbolWithGlobalValueBase(GV, "$non_lazy_ptr");228MachineModuleInfoImpl::StubValueTy &StubSym =229MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(Sym);230if (!StubSym.getPointer())231StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV),232!GV->hasInternalLinkage());233}234235// If the name begins with a dollar-sign, enclose it in parens. We do this236// to avoid having it look like an integer immediate to the assembler.237if (GVSym->getName()[0] != '$')238GVSym->print(O, MAI);239else {240O << '(';241GVSym->print(O, MAI);242O << ')';243}244printOffset(MO.getOffset(), O);245break;246}247}248249switch (MO.getTargetFlags()) {250default:251llvm_unreachable("Unknown target flag on GV operand");252case X86II::MO_NO_FLAG: // No flag.253break;254case X86II::MO_DARWIN_NONLAZY:255case X86II::MO_DLLIMPORT:256case X86II::MO_COFFSTUB:257// These affect the name of the symbol, not any suffix.258break;259case X86II::MO_GOT_ABSOLUTE_ADDRESS:260O << " + [.-";261MF->getPICBaseSymbol()->print(O, MAI);262O << ']';263break;264case X86II::MO_PIC_BASE_OFFSET:265case X86II::MO_DARWIN_NONLAZY_PIC_BASE:266O << '-';267MF->getPICBaseSymbol()->print(O, MAI);268break;269case X86II::MO_TLSGD: O << "@TLSGD"; break;270case X86II::MO_TLSLD: O << "@TLSLD"; break;271case X86II::MO_TLSLDM: O << "@TLSLDM"; break;272case X86II::MO_GOTTPOFF: O << "@GOTTPOFF"; break;273case X86II::MO_INDNTPOFF: O << "@INDNTPOFF"; break;274case X86II::MO_TPOFF: O << "@TPOFF"; break;275case X86II::MO_DTPOFF: O << "@DTPOFF"; break;276case X86II::MO_NTPOFF: O << "@NTPOFF"; break;277case X86II::MO_GOTNTPOFF: O << "@GOTNTPOFF"; break;278case X86II::MO_GOTPCREL: O << "@GOTPCREL"; break;279case X86II::MO_GOTPCREL_NORELAX: O << "@GOTPCREL_NORELAX"; break;280case X86II::MO_GOT: O << "@GOT"; break;281case X86II::MO_GOTOFF: O << "@GOTOFF"; break;282case X86II::MO_PLT: O << "@PLT"; break;283case X86II::MO_TLVP: O << "@TLVP"; break;284case X86II::MO_TLVP_PIC_BASE:285O << "@TLVP" << '-';286MF->getPICBaseSymbol()->print(O, MAI);287break;288case X86II::MO_SECREL: O << "@SECREL32"; break;289}290}291292void X86AsmPrinter::PrintOperand(const MachineInstr *MI, unsigned OpNo,293raw_ostream &O) {294const MachineOperand &MO = MI->getOperand(OpNo);295const bool IsATT = MI->getInlineAsmDialect() == InlineAsm::AD_ATT;296switch (MO.getType()) {297default: llvm_unreachable("unknown operand type!");298case MachineOperand::MO_Register: {299if (IsATT)300O << '%';301O << X86ATTInstPrinter::getRegisterName(MO.getReg());302return;303}304305case MachineOperand::MO_Immediate:306if (IsATT)307O << '$';308O << MO.getImm();309return;310311case MachineOperand::MO_ConstantPoolIndex:312case MachineOperand::MO_GlobalAddress: {313switch (MI->getInlineAsmDialect()) {314case InlineAsm::AD_ATT:315O << '$';316break;317case InlineAsm::AD_Intel:318O << "offset ";319break;320}321PrintSymbolOperand(MO, O);322break;323}324case MachineOperand::MO_BlockAddress: {325MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());326Sym->print(O, MAI);327break;328}329}330}331332/// PrintModifiedOperand - Print subregisters based on supplied modifier,333/// deferring to PrintOperand() if no modifier was supplied or if operand is not334/// a register.335void X86AsmPrinter::PrintModifiedOperand(const MachineInstr *MI, unsigned OpNo,336raw_ostream &O, const char *Modifier) {337const MachineOperand &MO = MI->getOperand(OpNo);338if (!Modifier || !MO.isReg())339return PrintOperand(MI, OpNo, O);340if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT)341O << '%';342Register Reg = MO.getReg();343if (strncmp(Modifier, "subreg", strlen("subreg")) == 0) {344unsigned Size = (strcmp(Modifier+6,"64") == 0) ? 64 :345(strcmp(Modifier+6,"32") == 0) ? 32 :346(strcmp(Modifier+6,"16") == 0) ? 16 : 8;347Reg = getX86SubSuperRegister(Reg, Size);348}349O << X86ATTInstPrinter::getRegisterName(Reg);350}351352/// PrintPCRelImm - This is used to print an immediate value that ends up353/// being encoded as a pc-relative value. These print slightly differently, for354/// example, a $ is not emitted.355void X86AsmPrinter::PrintPCRelImm(const MachineInstr *MI, unsigned OpNo,356raw_ostream &O) {357const MachineOperand &MO = MI->getOperand(OpNo);358switch (MO.getType()) {359default: llvm_unreachable("Unknown pcrel immediate operand");360case MachineOperand::MO_Register:361// pc-relativeness was handled when computing the value in the reg.362PrintOperand(MI, OpNo, O);363return;364case MachineOperand::MO_Immediate:365O << MO.getImm();366return;367case MachineOperand::MO_GlobalAddress:368PrintSymbolOperand(MO, O);369return;370}371}372373void X86AsmPrinter::PrintLeaMemReference(const MachineInstr *MI, unsigned OpNo,374raw_ostream &O, const char *Modifier) {375const MachineOperand &BaseReg = MI->getOperand(OpNo + X86::AddrBaseReg);376const MachineOperand &IndexReg = MI->getOperand(OpNo + X86::AddrIndexReg);377const MachineOperand &DispSpec = MI->getOperand(OpNo + X86::AddrDisp);378379// If we really don't want to print out (rip), don't.380bool HasBaseReg = BaseReg.getReg() != 0;381if (HasBaseReg && Modifier && !strcmp(Modifier, "no-rip") &&382BaseReg.getReg() == X86::RIP)383HasBaseReg = false;384385// HasParenPart - True if we will print out the () part of the mem ref.386bool HasParenPart = IndexReg.getReg() || HasBaseReg;387388switch (DispSpec.getType()) {389default:390llvm_unreachable("unknown operand type!");391case MachineOperand::MO_Immediate: {392int DispVal = DispSpec.getImm();393if (DispVal || !HasParenPart)394O << DispVal;395break;396}397case MachineOperand::MO_GlobalAddress:398case MachineOperand::MO_ConstantPoolIndex:399PrintSymbolOperand(DispSpec, O);400break;401}402403if (Modifier && strcmp(Modifier, "H") == 0)404O << "+8";405406if (HasParenPart) {407assert(IndexReg.getReg() != X86::ESP &&408"X86 doesn't allow scaling by ESP");409410O << '(';411if (HasBaseReg)412PrintModifiedOperand(MI, OpNo + X86::AddrBaseReg, O, Modifier);413414if (IndexReg.getReg()) {415O << ',';416PrintModifiedOperand(MI, OpNo + X86::AddrIndexReg, O, Modifier);417unsigned ScaleVal = MI->getOperand(OpNo + X86::AddrScaleAmt).getImm();418if (ScaleVal != 1)419O << ',' << ScaleVal;420}421O << ')';422}423}424425static bool isSimpleReturn(const MachineInstr &MI) {426// We exclude all tail calls here which set both isReturn and isCall.427return MI.getDesc().isReturn() && !MI.getDesc().isCall();428}429430static bool isIndirectBranchOrTailCall(const MachineInstr &MI) {431unsigned Opc = MI.getOpcode();432return MI.getDesc().isIndirectBranch() /*Make below code in a good shape*/ ||433Opc == X86::TAILJMPr || Opc == X86::TAILJMPm ||434Opc == X86::TAILJMPr64 || Opc == X86::TAILJMPm64 ||435Opc == X86::TCRETURNri || Opc == X86::TCRETURNmi ||436Opc == X86::TCRETURNri64 || Opc == X86::TCRETURNmi64 ||437Opc == X86::TAILJMPr64_REX || Opc == X86::TAILJMPm64_REX;438}439440void X86AsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) {441if (Subtarget->hardenSlsRet() || Subtarget->hardenSlsIJmp()) {442auto I = MBB.getLastNonDebugInstr();443if (I != MBB.end()) {444if ((Subtarget->hardenSlsRet() && isSimpleReturn(*I)) ||445(Subtarget->hardenSlsIJmp() && isIndirectBranchOrTailCall(*I))) {446MCInst TmpInst;447TmpInst.setOpcode(X86::INT3);448EmitToStreamer(*OutStreamer, TmpInst);449}450}451}452AsmPrinter::emitBasicBlockEnd(MBB);453SMShadowTracker.emitShadowPadding(*OutStreamer, getSubtargetInfo());454}455456void X86AsmPrinter::PrintMemReference(const MachineInstr *MI, unsigned OpNo,457raw_ostream &O, const char *Modifier) {458assert(isMem(*MI, OpNo) && "Invalid memory reference!");459const MachineOperand &Segment = MI->getOperand(OpNo + X86::AddrSegmentReg);460if (Segment.getReg()) {461PrintModifiedOperand(MI, OpNo + X86::AddrSegmentReg, O, Modifier);462O << ':';463}464PrintLeaMemReference(MI, OpNo, O, Modifier);465}466467468void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,469unsigned OpNo, raw_ostream &O,470const char *Modifier) {471const MachineOperand &BaseReg = MI->getOperand(OpNo + X86::AddrBaseReg);472unsigned ScaleVal = MI->getOperand(OpNo + X86::AddrScaleAmt).getImm();473const MachineOperand &IndexReg = MI->getOperand(OpNo + X86::AddrIndexReg);474const MachineOperand &DispSpec = MI->getOperand(OpNo + X86::AddrDisp);475const MachineOperand &SegReg = MI->getOperand(OpNo + X86::AddrSegmentReg);476477// If we really don't want to print out (rip), don't.478bool HasBaseReg = BaseReg.getReg() != 0;479if (HasBaseReg && Modifier && !strcmp(Modifier, "no-rip") &&480BaseReg.getReg() == X86::RIP)481HasBaseReg = false;482483// If we really just want to print out displacement.484if (Modifier && (DispSpec.isGlobal() || DispSpec.isSymbol()) &&485!strcmp(Modifier, "disp-only")) {486HasBaseReg = false;487}488489// If this has a segment register, print it.490if (SegReg.getReg()) {491PrintOperand(MI, OpNo + X86::AddrSegmentReg, O);492O << ':';493}494495O << '[';496497bool NeedPlus = false;498if (HasBaseReg) {499PrintOperand(MI, OpNo + X86::AddrBaseReg, O);500NeedPlus = true;501}502503if (IndexReg.getReg()) {504if (NeedPlus) O << " + ";505if (ScaleVal != 1)506O << ScaleVal << '*';507PrintOperand(MI, OpNo + X86::AddrIndexReg, O);508NeedPlus = true;509}510511if (!DispSpec.isImm()) {512if (NeedPlus) O << " + ";513// Do not add `offset` operator. Matches the behaviour of514// X86IntelInstPrinter::printMemReference.515PrintSymbolOperand(DispSpec, O);516} else {517int64_t DispVal = DispSpec.getImm();518if (DispVal || (!IndexReg.getReg() && !HasBaseReg)) {519if (NeedPlus) {520if (DispVal > 0)521O << " + ";522else {523O << " - ";524DispVal = -DispVal;525}526}527O << DispVal;528}529}530O << ']';531}532533const MCSubtargetInfo *X86AsmPrinter::getIFuncMCSubtargetInfo() const {534assert(Subtarget);535return Subtarget;536}537538void X86AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,539MCSymbol *LazyPointer) {540// _ifunc:541// jmpq *lazy_pointer(%rip)542543OutStreamer->emitInstruction(544MCInstBuilder(X86::JMP32m)545.addReg(X86::RIP)546.addImm(1)547.addReg(0)548.addOperand(MCOperand::createExpr(549MCSymbolRefExpr::create(LazyPointer, OutContext)))550.addReg(0),551*Subtarget);552}553554void X86AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,555const GlobalIFunc &GI,556MCSymbol *LazyPointer) {557// _ifunc.stub_helper:558// push %rax559// push %rdi560// push %rsi561// push %rdx562// push %rcx563// push %r8564// push %r9565// callq foo566// movq %rax,lazy_pointer(%rip)567// pop %r9568// pop %r8569// pop %rcx570// pop %rdx571// pop %rsi572// pop %rdi573// pop %rax574// jmpq *lazy_pointer(%rip)575576for (int Reg :577{X86::RAX, X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9})578OutStreamer->emitInstruction(MCInstBuilder(X86::PUSH64r).addReg(Reg),579*Subtarget);580581OutStreamer->emitInstruction(582MCInstBuilder(X86::CALL64pcrel32)583.addOperand(MCOperand::createExpr(lowerConstant(GI.getResolver()))),584*Subtarget);585586OutStreamer->emitInstruction(587MCInstBuilder(X86::MOV64mr)588.addReg(X86::RIP)589.addImm(1)590.addReg(0)591.addOperand(MCOperand::createExpr(592MCSymbolRefExpr::create(LazyPointer, OutContext)))593.addReg(0)594.addReg(X86::RAX),595*Subtarget);596597for (int Reg :598{X86::R9, X86::R8, X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RAX})599OutStreamer->emitInstruction(MCInstBuilder(X86::POP64r).addReg(Reg),600*Subtarget);601602OutStreamer->emitInstruction(603MCInstBuilder(X86::JMP32m)604.addReg(X86::RIP)605.addImm(1)606.addReg(0)607.addOperand(MCOperand::createExpr(608MCSymbolRefExpr::create(LazyPointer, OutContext)))609.addReg(0),610*Subtarget);611}612613static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,614char Mode, raw_ostream &O) {615Register Reg = MO.getReg();616bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;617618if (!X86::GR8RegClass.contains(Reg) &&619!X86::GR16RegClass.contains(Reg) &&620!X86::GR32RegClass.contains(Reg) &&621!X86::GR64RegClass.contains(Reg))622return true;623624switch (Mode) {625default: return true; // Unknown mode.626case 'b': // Print QImode register627Reg = getX86SubSuperRegister(Reg, 8);628break;629case 'h': // Print QImode high register630Reg = getX86SubSuperRegister(Reg, 8, true);631if (!Reg.isValid())632return true;633break;634case 'w': // Print HImode register635Reg = getX86SubSuperRegister(Reg, 16);636break;637case 'k': // Print SImode register638Reg = getX86SubSuperRegister(Reg, 32);639break;640case 'V':641EmitPercent = false;642[[fallthrough]];643case 'q':644// Print 64-bit register names if 64-bit integer registers are available.645// Otherwise, print 32-bit register names.646Reg = getX86SubSuperRegister(Reg, P.getSubtarget().is64Bit() ? 64 : 32);647break;648}649650if (EmitPercent)651O << '%';652653O << X86ATTInstPrinter::getRegisterName(Reg);654return false;655}656657static bool printAsmVRegister(const MachineOperand &MO, char Mode,658raw_ostream &O) {659Register Reg = MO.getReg();660bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;661662unsigned Index;663if (X86::VR128XRegClass.contains(Reg))664Index = Reg - X86::XMM0;665else if (X86::VR256XRegClass.contains(Reg))666Index = Reg - X86::YMM0;667else if (X86::VR512RegClass.contains(Reg))668Index = Reg - X86::ZMM0;669else670return true;671672switch (Mode) {673default: // Unknown mode.674return true;675case 'x': // Print V4SFmode register676Reg = X86::XMM0 + Index;677break;678case 't': // Print V8SFmode register679Reg = X86::YMM0 + Index;680break;681case 'g': // Print V16SFmode register682Reg = X86::ZMM0 + Index;683break;684}685686if (EmitPercent)687O << '%';688689O << X86ATTInstPrinter::getRegisterName(Reg);690return false;691}692693/// PrintAsmOperand - Print out an operand for an inline asm expression.694///695bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,696const char *ExtraCode, raw_ostream &O) {697// Does this asm operand have a single letter operand modifier?698if (ExtraCode && ExtraCode[0]) {699if (ExtraCode[1] != 0) return true; // Unknown modifier.700701const MachineOperand &MO = MI->getOperand(OpNo);702703switch (ExtraCode[0]) {704default:705// See if this is a generic print operand706return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);707case 'a': // This is an address. Currently only 'i' and 'r' are expected.708switch (MO.getType()) {709default:710return true;711case MachineOperand::MO_Immediate:712O << MO.getImm();713return false;714case MachineOperand::MO_ConstantPoolIndex:715case MachineOperand::MO_JumpTableIndex:716case MachineOperand::MO_ExternalSymbol:717llvm_unreachable("unexpected operand type!");718case MachineOperand::MO_GlobalAddress:719PrintSymbolOperand(MO, O);720if (Subtarget->isPICStyleRIPRel())721O << "(%rip)";722return false;723case MachineOperand::MO_Register:724O << '(';725PrintOperand(MI, OpNo, O);726O << ')';727return false;728}729730case 'c': // Don't print "$" before a global var name or constant.731switch (MO.getType()) {732default:733PrintOperand(MI, OpNo, O);734break;735case MachineOperand::MO_Immediate:736O << MO.getImm();737break;738case MachineOperand::MO_ConstantPoolIndex:739case MachineOperand::MO_JumpTableIndex:740case MachineOperand::MO_ExternalSymbol:741llvm_unreachable("unexpected operand type!");742case MachineOperand::MO_GlobalAddress:743PrintSymbolOperand(MO, O);744break;745}746return false;747748case 'A': // Print '*' before a register (it must be a register)749if (MO.isReg()) {750O << '*';751PrintOperand(MI, OpNo, O);752return false;753}754return true;755756case 'b': // Print QImode register757case 'h': // Print QImode high register758case 'w': // Print HImode register759case 'k': // Print SImode register760case 'q': // Print DImode register761case 'V': // Print native register without '%'762if (MO.isReg())763return printAsmMRegister(*this, MO, ExtraCode[0], O);764PrintOperand(MI, OpNo, O);765return false;766767case 'x': // Print V4SFmode register768case 't': // Print V8SFmode register769case 'g': // Print V16SFmode register770if (MO.isReg())771return printAsmVRegister(MO, ExtraCode[0], O);772PrintOperand(MI, OpNo, O);773return false;774775case 'p': {776const MachineOperand &MO = MI->getOperand(OpNo);777if (MO.getType() != MachineOperand::MO_GlobalAddress)778return true;779PrintSymbolOperand(MO, O);780return false;781}782783case 'P': // This is the operand of a call, treat specially.784PrintPCRelImm(MI, OpNo, O);785return false;786787case 'n': // Negate the immediate or print a '-' before the operand.788// Note: this is a temporary solution. It should be handled target789// independently as part of the 'MC' work.790if (MO.isImm()) {791O << -MO.getImm();792return false;793}794O << '-';795}796}797798PrintOperand(MI, OpNo, O);799return false;800}801802bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,803const char *ExtraCode,804raw_ostream &O) {805if (ExtraCode && ExtraCode[0]) {806if (ExtraCode[1] != 0) return true; // Unknown modifier.807808switch (ExtraCode[0]) {809default: return true; // Unknown modifier.810case 'b': // Print QImode register811case 'h': // Print QImode high register812case 'w': // Print HImode register813case 'k': // Print SImode register814case 'q': // Print SImode register815// These only apply to registers, ignore on mem.816break;817case 'H':818if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {819return true; // Unsupported modifier in Intel inline assembly.820} else {821PrintMemReference(MI, OpNo, O, "H");822}823return false;824// Print memory only with displacement. The Modifer 'P' is used in inline825// asm to present a call symbol or a global symbol which can not use base826// reg or index reg.827case 'P':828if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {829PrintIntelMemReference(MI, OpNo, O, "disp-only");830} else {831PrintMemReference(MI, OpNo, O, "disp-only");832}833return false;834}835}836if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {837PrintIntelMemReference(MI, OpNo, O, nullptr);838} else {839PrintMemReference(MI, OpNo, O, nullptr);840}841return false;842}843844void X86AsmPrinter::emitStartOfAsmFile(Module &M) {845const Triple &TT = TM.getTargetTriple();846847if (TT.isOSBinFormatELF()) {848// Assemble feature flags that may require creation of a note section.849unsigned FeatureFlagsAnd = 0;850if (M.getModuleFlag("cf-protection-branch"))851FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_IBT;852if (M.getModuleFlag("cf-protection-return"))853FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_SHSTK;854855if (FeatureFlagsAnd) {856// Emit a .note.gnu.property section with the flags.857assert((TT.isArch32Bit() || TT.isArch64Bit()) &&858"CFProtection used on invalid architecture!");859MCSection *Cur = OutStreamer->getCurrentSectionOnly();860MCSection *Nt = MMI->getContext().getELFSection(861".note.gnu.property", ELF::SHT_NOTE, ELF::SHF_ALLOC);862OutStreamer->switchSection(Nt);863864// Emitting note header.865const int WordSize = TT.isArch64Bit() && !TT.isX32() ? 8 : 4;866emitAlignment(WordSize == 4 ? Align(4) : Align(8));867OutStreamer->emitIntValue(4, 4 /*size*/); // data size for "GNU\0"868OutStreamer->emitIntValue(8 + WordSize, 4 /*size*/); // Elf_Prop size869OutStreamer->emitIntValue(ELF::NT_GNU_PROPERTY_TYPE_0, 4 /*size*/);870OutStreamer->emitBytes(StringRef("GNU", 4)); // note name871872// Emitting an Elf_Prop for the CET properties.873OutStreamer->emitInt32(ELF::GNU_PROPERTY_X86_FEATURE_1_AND);874OutStreamer->emitInt32(4); // data size875OutStreamer->emitInt32(FeatureFlagsAnd); // data876emitAlignment(WordSize == 4 ? Align(4) : Align(8)); // padding877878OutStreamer->switchSection(Cur);879}880}881882if (TT.isOSBinFormatMachO())883OutStreamer->switchSection(getObjFileLowering().getTextSection());884885if (TT.isOSBinFormatCOFF()) {886// Emit an absolute @feat.00 symbol.887MCSymbol *S = MMI->getContext().getOrCreateSymbol(StringRef("@feat.00"));888OutStreamer->beginCOFFSymbolDef(S);889OutStreamer->emitCOFFSymbolStorageClass(COFF::IMAGE_SYM_CLASS_STATIC);890OutStreamer->emitCOFFSymbolType(COFF::IMAGE_SYM_DTYPE_NULL);891OutStreamer->endCOFFSymbolDef();892int64_t Feat00Value = 0;893894if (TT.getArch() == Triple::x86) {895// According to the PE-COFF spec, the LSB of this value marks the object896// for "registered SEH". This means that all SEH handler entry points897// must be registered in .sxdata. Use of any unregistered handlers will898// cause the process to terminate immediately. LLVM does not know how to899// register any SEH handlers, so its object files should be safe.900Feat00Value |= COFF::Feat00Flags::SafeSEH;901}902903if (M.getModuleFlag("cfguard")) {904// Object is CFG-aware.905Feat00Value |= COFF::Feat00Flags::GuardCF;906}907908if (M.getModuleFlag("ehcontguard")) {909// Object also has EHCont.910Feat00Value |= COFF::Feat00Flags::GuardEHCont;911}912913if (M.getModuleFlag("ms-kernel")) {914// Object is compiled with /kernel.915Feat00Value |= COFF::Feat00Flags::Kernel;916}917918OutStreamer->emitSymbolAttribute(S, MCSA_Global);919OutStreamer->emitAssignment(920S, MCConstantExpr::create(Feat00Value, MMI->getContext()));921}922OutStreamer->emitSyntaxDirective();923924// If this is not inline asm and we're in 16-bit925// mode prefix assembly with .code16.926bool is16 = TT.getEnvironment() == Triple::CODE16;927if (M.getModuleInlineAsm().empty() && is16)928OutStreamer->emitAssemblerFlag(MCAF_Code16);929}930931static void932emitNonLazySymbolPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel,933MachineModuleInfoImpl::StubValueTy &MCSym) {934// L_foo$stub:935OutStreamer.emitLabel(StubLabel);936// .indirect_symbol _foo937OutStreamer.emitSymbolAttribute(MCSym.getPointer(), MCSA_IndirectSymbol);938939if (MCSym.getInt())940// External to current translation unit.941OutStreamer.emitIntValue(0, 4/*size*/);942else943// Internal to current translation unit.944//945// When we place the LSDA into the TEXT section, the type info946// pointers need to be indirect and pc-rel. We accomplish this by947// using NLPs; however, sometimes the types are local to the file.948// We need to fill in the value for the NLP in those cases.949OutStreamer.emitValue(950MCSymbolRefExpr::create(MCSym.getPointer(), OutStreamer.getContext()),9514 /*size*/);952}953954static void emitNonLazyStubs(MachineModuleInfo *MMI, MCStreamer &OutStreamer) {955956MachineModuleInfoMachO &MMIMacho =957MMI->getObjFileInfo<MachineModuleInfoMachO>();958959// Output stubs for dynamically-linked functions.960MachineModuleInfoMachO::SymbolListTy Stubs;961962// Output stubs for external and common global variables.963Stubs = MMIMacho.GetGVStubList();964if (!Stubs.empty()) {965OutStreamer.switchSection(MMI->getContext().getMachOSection(966"__IMPORT", "__pointers", MachO::S_NON_LAZY_SYMBOL_POINTERS,967SectionKind::getMetadata()));968969for (auto &Stub : Stubs)970emitNonLazySymbolPointer(OutStreamer, Stub.first, Stub.second);971972Stubs.clear();973OutStreamer.addBlankLine();974}975}976977void X86AsmPrinter::emitEndOfAsmFile(Module &M) {978const Triple &TT = TM.getTargetTriple();979980if (TT.isOSBinFormatMachO()) {981// Mach-O uses non-lazy symbol stubs to encode per-TU information into982// global table for symbol lookup.983emitNonLazyStubs(MMI, *OutStreamer);984985// Emit fault map information.986FM.serializeToFaultMapSection();987988// This flag tells the linker that no global symbols contain code that fall989// through to other global symbols (e.g. an implementation of multiple entry990// points). If this doesn't occur, the linker can safely perform dead code991// stripping. Since LLVM never generates code that does this, it is always992// safe to set.993OutStreamer->emitAssemblerFlag(MCAF_SubsectionsViaSymbols);994} else if (TT.isOSBinFormatCOFF()) {995if (MMI->usesMSVCFloatingPoint()) {996// In Windows' libcmt.lib, there is a file which is linked in only if the997// symbol _fltused is referenced. Linking this in causes some998// side-effects:999//1000// 1. For x86-32, it will set the x87 rounding mode to 53-bit instead of1001// 64-bit mantissas at program start.1002//1003// 2. It links in support routines for floating-point in scanf and printf.1004//1005// MSVC emits an undefined reference to _fltused when there are any1006// floating point operations in the program (including calls). A program1007// that only has: `scanf("%f", &global_float);` may fail to trigger this,1008// but oh well...that's a documented issue.1009StringRef SymbolName =1010(TT.getArch() == Triple::x86) ? "__fltused" : "_fltused";1011MCSymbol *S = MMI->getContext().getOrCreateSymbol(SymbolName);1012OutStreamer->emitSymbolAttribute(S, MCSA_Global);1013return;1014}1015} else if (TT.isOSBinFormatELF()) {1016FM.serializeToFaultMapSection();1017}10181019// Emit __morestack address if needed for indirect calls.1020if (TT.getArch() == Triple::x86_64 && TM.getCodeModel() == CodeModel::Large) {1021if (MCSymbol *AddrSymbol = OutContext.lookupSymbol("__morestack_addr")) {1022Align Alignment(1);1023MCSection *ReadOnlySection = getObjFileLowering().getSectionForConstant(1024getDataLayout(), SectionKind::getReadOnly(),1025/*C=*/nullptr, Alignment);1026OutStreamer->switchSection(ReadOnlySection);1027OutStreamer->emitLabel(AddrSymbol);10281029unsigned PtrSize = MAI->getCodePointerSize();1030OutStreamer->emitSymbolValue(GetExternalSymbolSymbol("__morestack"),1031PtrSize);1032}1033}1034}10351036//===----------------------------------------------------------------------===//1037// Target Registry Stuff1038//===----------------------------------------------------------------------===//10391040// Force static initialization.1041extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeX86AsmPrinter() {1042RegisterAsmPrinter<X86AsmPrinter> X(getTheX86_32Target());1043RegisterAsmPrinter<X86AsmPrinter> Y(getTheX86_64Target());1044}104510461047