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-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a printer that converts from our internal representation
10// 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(p: TM.getTarget().createMCCodeEmitter(
76 II: *Subtarget->getInstrInfo(), Ctx&: MF.getContext()));
77
78 const Module *M = MF.getFunction().getParent();
79 EmitFPOData = Subtarget->isTargetWin32() && M->getCodeViewFlag();
80
81 IndCSPrefix = M->getModuleFlag(Key: "indirect_branch_cs_prefix");
82
83 SetupMachineFunction(MF);
84
85 if (Subtarget->isTargetCOFF()) {
86 bool Local = MF.getFunction().hasLocalLinkage();
87 OutStreamer->beginCOFFSymbolDef(Symbol: CurrentFnSym);
88 OutStreamer->emitCOFFSymbolStorageClass(
89 StorageClass: Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL);
90 OutStreamer->emitCOFFSymbolType(Type: COFF::IMAGE_SYM_DTYPE_FUNCTION
91 << 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 ProcSym: CurrentFnSym,
115 ParamsSize: 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 also
135 // 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 into
145 // account if set.
146 int64_t PrefixBytes = 0;
147 (void)MF.getFunction()
148 .getFnAttribute(Kind: "patchable-function-prefix")
149 .getValueAsString()
150 .getAsInteger(Radix: 10, Result&: PrefixBytes);
151
152 // Also take the type identifier into account if we're emitting
153 // one. Otherwise, just pad with nops. The X86::MOV32ri instruction emitted
154 // in X86AsmPrinter::emitKCFITypeId is 5 bytes long.
155 if (HasType)
156 PrefixBytes += 5;
157
158 emitNops(N: offsetToAlignment(Value: PrefixBytes, Alignment: MF.getAlignment()));
159}
160
161/// emitKCFITypeId - Emit the KCFI type information in architecture specific
162/// format.
163void X86AsmPrinter::emitKCFITypeId(const MachineFunction &MF) {
164 const Function &F = MF.getFunction();
165 if (!F.getParent()->getModuleFlag(Key: "kcfi"))
166 return;
167
168 ConstantInt *Type = nullptr;
169 if (const MDNode *MD = F.getMetadata(KindID: LLVMContext::MD_kcfi_type))
170 Type = mdconst::extract<ConstantInt>(MD: MD->getOperand(I: 0));
171
172 // If we don't have a type to emit, just emit padding if needed to maintain
173 // 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 instruction
180 // warnings from binary validation tools, and use the same linkage as the
181 // parent function. Note that using local linkage would result in duplicate
182 // symbols for weak parent functions.
183 MCSymbol *FnSym = OutContext.getOrCreateSymbol(Name: "__cfi_" + MF.getName());
184 emitLinkage(GV: &MF.getFunction(), GVSym: FnSym);
185 if (MAI->hasDotTypeDotSizeDirective())
186 OutStreamer->emitSymbolAttribute(Symbol: FnSym, Attribute: MCSA_ELF_TypeFunction);
187 OutStreamer->emitLabel(Symbol: FnSym);
188
189 // Embed the type hash in the X86::MOV32ri instruction to avoid special
190 // casing object file parsers.
191 EmitKCFITypePadding(MF);
192 unsigned DestReg = X86::EAX;
193
194 if (F.getParent()->getModuleFlag(Key: "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 ABI
200 // level by counting the number of parameters that are passed
201 // as registers, such as pointers and 64-bit (or smaller) integers. The
202 // 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 on
204 // the stack, in which case the arity is denoted as 7. Floating-point
205 // arguments passed in XMM0-XMM7 are not counted toward arity because
206 // 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(Inst&: MCInstBuilder(X86::MOV32ri)
227 .addReg(Reg: DestReg)
228 .addImm(Val: MaskKCFIType(Value: Type->getZExtValue())));
229
230 if (MAI->hasDotTypeDotSizeDirective()) {
231 MCSymbol *EndSym = OutContext.createTempSymbol(Name: "cfi_func_end");
232 OutStreamer->emitLabel(Symbol: EndSym);
233
234 const MCExpr *SizeExp = MCBinaryExpr::createSub(
235 LHS: MCSymbolRefExpr::create(Symbol: EndSym, Ctx&: OutContext),
236 RHS: MCSymbolRefExpr::create(Symbol: FnSym, Ctx&: OutContext), Ctx&: OutContext);
237 OutStreamer->emitELFSize(Symbol: FnSym, Value: SizeExp);
238 }
239}
240
241/// PrintSymbolOperand - Print a raw symbol reference operand. This handles
242/// jump tables, constant pools, global address and external symbols, all of
243/// 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(CPID: MO.getIndex())->print(OS&: O, MAI);
250 printOffset(Offset: MO.getOffset(), OS&: 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, Suffix: "$non_lazy_ptr");
259 else
260 GVSym = getSymbolPreferLocal(GV: *GV);
261
262 // Handle dllimport linkage.
263 if (MO.getTargetFlags() == X86II::MO_DLLIMPORT)
264 GVSym = OutContext.getOrCreateSymbol(Name: Twine("__imp_") + GVSym->getName());
265 else if (MO.getTargetFlags() == X86II::MO_COFFSTUB)
266 GVSym =
267 OutContext.getOrCreateSymbol(Name: 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, Suffix: "$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 this
280 // to avoid having it look like an integer immediate to the assembler.
281 if (GVSym->getName()[0] != '$')
282 GVSym->print(OS&: O, MAI);
283 else {
284 O << '(';
285 GVSym->print(OS&: O, MAI);
286 O << ')';
287 }
288 printOffset(Offset: MO.getOffset(), OS&: 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(OS&: 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(OS&: 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(OS&: 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(i: 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(Reg: 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(BA: MO.getBlockAddress());
370 Sym->print(OS&: 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 not
378/// a register.
379void X86AsmPrinter::PrintModifiedOperand(const MachineInstr *MI, unsigned OpNo,
380 raw_ostream &O, StringRef Modifier) {
381 const MachineOperand &MO = MI->getOperand(i: 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(Prefix: "subreg")) {
388 unsigned Size = (Modifier == "64") ? 64
389 : (Modifier == "32") ? 32
390 : (Modifier == "16") ? 16
391 : 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 up
398/// being encoded as a pc-relative value. These print slightly differently, for
399/// example, a $ is not emitted.
400void X86AsmPrinter::PrintPCRelImm(const MachineInstr *MI, unsigned OpNo,
401 raw_ostream &O) {
402 const MachineOperand &MO = MI->getOperand(i: 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(i: OpNo + X86::AddrBaseReg);
421 const MachineOperand &IndexReg = MI->getOperand(i: OpNo + X86::AddrIndexReg);
422 const MachineOperand &DispSpec = MI->getOperand(i: 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(MO: 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: OpNo + X86::AddrBaseReg, O, Modifier);
457
458 if (IndexReg.getReg()) {
459 O << ',';
460 PrintModifiedOperand(MI, OpNo: OpNo + X86::AddrIndexReg, O, Modifier);
461 unsigned ScaleVal = MI->getOperand(i: 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(MI: *I)) ||
491 (Subtarget->hardenSlsIJmp() && isIndirectBranchOrTailCall(MI: *I))) {
492 MCInst TmpInst;
493 TmpInst.setOpcode(X86::INT3);
494 EmitToStreamer(S&: *OutStreamer, Inst: TmpInst);
495 }
496 }
497 }
498 if (SplitChainedAtEndOfBlock) {
499 OutStreamer->emitWinCFISplitChained();
500 // Splitting into a new unwind info implicitly starts a prolog. We have no
501 // instructions to add to the prolog, so immediately end it.
502 OutStreamer->emitWinCFIEndProlog();
503 SplitChainedAtEndOfBlock = false;
504 }
505 AsmPrinter::emitBasicBlockEnd(MBB);
506 SMShadowTracker.emitShadowPadding(OutStreamer&: *OutStreamer, STI: getSubtargetInfo());
507}
508
509void X86AsmPrinter::PrintMemReference(const MachineInstr *MI, unsigned OpNo,
510 raw_ostream &O, StringRef Modifier) {
511 assert(isMem(*MI, OpNo) && "Invalid memory reference!");
512 const MachineOperand &Segment = MI->getOperand(i: OpNo + X86::AddrSegmentReg);
513 if (Segment.getReg()) {
514 PrintModifiedOperand(MI, OpNo: OpNo + X86::AddrSegmentReg, O, Modifier);
515 O << ':';
516 }
517 PrintLeaMemReference(MI, OpNo, O, Modifier);
518}
519
520void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI,
521 unsigned OpNo, raw_ostream &O,
522 StringRef Modifier) {
523 const MachineOperand &BaseReg = MI->getOperand(i: OpNo + X86::AddrBaseReg);
524 unsigned ScaleVal = MI->getOperand(i: OpNo + X86::AddrScaleAmt).getImm();
525 const MachineOperand &IndexReg = MI->getOperand(i: OpNo + X86::AddrIndexReg);
526 const MachineOperand &DispSpec = MI->getOperand(i: OpNo + X86::AddrDisp);
527 const MachineOperand &SegReg = MI->getOperand(i: OpNo + X86::AddrSegmentReg);
528
529 // If we really don't want to print out (rip), don't.
530 bool HasBaseReg = BaseReg.getReg() != 0;
531 if (HasBaseReg && Modifier == "no-rip" && BaseReg.getReg() == X86::RIP)
532 HasBaseReg = false;
533
534 // If we really just want to print out displacement.
535 if ((DispSpec.isGlobal() || DispSpec.isSymbol()) && Modifier == "disp-only") {
536 HasBaseReg = false;
537 }
538
539 // If this has a segment register, print it.
540 if (SegReg.getReg()) {
541 PrintOperand(MI, OpNo: OpNo + X86::AddrSegmentReg, O);
542 O << ':';
543 }
544
545 O << '[';
546
547 bool NeedPlus = false;
548 if (HasBaseReg) {
549 PrintOperand(MI, OpNo: OpNo + X86::AddrBaseReg, O);
550 NeedPlus = true;
551 }
552
553 if (IndexReg.getReg()) {
554 if (NeedPlus) O << " + ";
555 if (ScaleVal != 1)
556 O << ScaleVal << '*';
557 PrintOperand(MI, OpNo: OpNo + X86::AddrIndexReg, O);
558 NeedPlus = true;
559 }
560
561 if (!DispSpec.isImm()) {
562 if (NeedPlus) O << " + ";
563 // Do not add `offset` operator. Matches the behaviour of
564 // X86IntelInstPrinter::printMemReference.
565 PrintSymbolOperand(MO: DispSpec, O);
566 } else {
567 int64_t DispVal = DispSpec.getImm();
568 if (DispVal || (!IndexReg.getReg() && !HasBaseReg)) {
569 if (NeedPlus) {
570 if (DispVal > 0)
571 O << " + ";
572 else {
573 O << " - ";
574 DispVal = -DispVal;
575 }
576 }
577 O << DispVal;
578 }
579 }
580 O << ']';
581}
582
583const MCSubtargetInfo *X86AsmPrinter::getIFuncMCSubtargetInfo() const {
584 assert(Subtarget);
585 return Subtarget;
586}
587
588void X86AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI,
589 MCSymbol *LazyPointer) {
590 // _ifunc:
591 // jmpq *lazy_pointer(%rip)
592
593 OutStreamer->emitInstruction(
594 Inst: MCInstBuilder(X86::JMP32m)
595 .addReg(Reg: X86::RIP)
596 .addImm(Val: 1)
597 .addReg(Reg: 0)
598 .addOperand(Op: MCOperand::createExpr(
599 Val: MCSymbolRefExpr::create(Symbol: LazyPointer, Ctx&: OutContext)))
600 .addReg(Reg: 0),
601 STI: *Subtarget);
602}
603
604void X86AsmPrinter::emitMachOIFuncStubHelperBody(Module &M,
605 const GlobalIFunc &GI,
606 MCSymbol *LazyPointer) {
607 // _ifunc.stub_helper:
608 // push %rax
609 // push %rdi
610 // push %rsi
611 // push %rdx
612 // push %rcx
613 // push %r8
614 // push %r9
615 // callq foo
616 // movq %rax,lazy_pointer(%rip)
617 // pop %r9
618 // pop %r8
619 // pop %rcx
620 // pop %rdx
621 // pop %rsi
622 // pop %rdi
623 // pop %rax
624 // jmpq *lazy_pointer(%rip)
625
626 for (int Reg :
627 {X86::RAX, X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9})
628 OutStreamer->emitInstruction(Inst: MCInstBuilder(X86::PUSH64r).addReg(Reg),
629 STI: *Subtarget);
630
631 OutStreamer->emitInstruction(
632 Inst: MCInstBuilder(X86::CALL64pcrel32)
633 .addOperand(Op: MCOperand::createExpr(Val: lowerConstant(CV: GI.getResolver()))),
634 STI: *Subtarget);
635
636 OutStreamer->emitInstruction(
637 Inst: MCInstBuilder(X86::MOV64mr)
638 .addReg(Reg: X86::RIP)
639 .addImm(Val: 1)
640 .addReg(Reg: 0)
641 .addOperand(Op: MCOperand::createExpr(
642 Val: MCSymbolRefExpr::create(Symbol: LazyPointer, Ctx&: OutContext)))
643 .addReg(Reg: 0)
644 .addReg(Reg: X86::RAX),
645 STI: *Subtarget);
646
647 for (int Reg :
648 {X86::R9, X86::R8, X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RAX})
649 OutStreamer->emitInstruction(Inst: MCInstBuilder(X86::POP64r).addReg(Reg),
650 STI: *Subtarget);
651
652 OutStreamer->emitInstruction(
653 Inst: MCInstBuilder(X86::JMP32m)
654 .addReg(Reg: X86::RIP)
655 .addImm(Val: 1)
656 .addReg(Reg: 0)
657 .addOperand(Op: MCOperand::createExpr(
658 Val: MCSymbolRefExpr::create(Symbol: LazyPointer, Ctx&: OutContext)))
659 .addReg(Reg: 0),
660 STI: *Subtarget);
661}
662
663static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO,
664 char Mode, raw_ostream &O) {
665 Register Reg = MO.getReg();
666 bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;
667
668 if (!X86::GR8RegClass.contains(Reg) &&
669 !X86::GR16RegClass.contains(Reg) &&
670 !X86::GR32RegClass.contains(Reg) &&
671 !X86::GR64RegClass.contains(Reg))
672 return true;
673
674 switch (Mode) {
675 default: return true; // Unknown mode.
676 case 'b': // Print QImode register
677 Reg = getX86SubSuperRegister(Reg, Size: 8);
678 break;
679 case 'h': // Print QImode high register
680 Reg = getX86SubSuperRegister(Reg, Size: 8, High: true);
681 if (!Reg.isValid())
682 return true;
683 break;
684 case 'w': // Print HImode register
685 Reg = getX86SubSuperRegister(Reg, Size: 16);
686 break;
687 case 'k': // Print SImode register
688 Reg = getX86SubSuperRegister(Reg, Size: 32);
689 break;
690 case 'V':
691 EmitPercent = false;
692 [[fallthrough]];
693 case 'q':
694 // Print 64-bit register names if 64-bit integer registers are available.
695 // Otherwise, print 32-bit register names.
696 Reg = getX86SubSuperRegister(Reg, Size: P.getSubtarget().is64Bit() ? 64 : 32);
697 break;
698 }
699
700 if (EmitPercent)
701 O << '%';
702
703 O << X86ATTInstPrinter::getRegisterName(Reg);
704 return false;
705}
706
707static bool printAsmVRegister(const MachineOperand &MO, char Mode,
708 raw_ostream &O) {
709 Register Reg = MO.getReg();
710 bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT;
711
712 unsigned Index;
713 if (X86::VR128XRegClass.contains(Reg))
714 Index = Reg - X86::XMM0;
715 else if (X86::VR256XRegClass.contains(Reg))
716 Index = Reg - X86::YMM0;
717 else if (X86::VR512RegClass.contains(Reg))
718 Index = Reg - X86::ZMM0;
719 else
720 return true;
721
722 switch (Mode) {
723 default: // Unknown mode.
724 return true;
725 case 'x': // Print V4SFmode register
726 Reg = X86::XMM0 + Index;
727 break;
728 case 't': // Print V8SFmode register
729 Reg = X86::YMM0 + Index;
730 break;
731 case 'g': // Print V16SFmode register
732 Reg = X86::ZMM0 + Index;
733 break;
734 }
735
736 if (EmitPercent)
737 O << '%';
738
739 O << X86ATTInstPrinter::getRegisterName(Reg);
740 return false;
741}
742
743/// PrintAsmOperand - Print out an operand for an inline asm expression.
744///
745bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
746 const char *ExtraCode, raw_ostream &O) {
747 // Does this asm operand have a single letter operand modifier?
748 if (ExtraCode && ExtraCode[0]) {
749 if (ExtraCode[1] != 0) return true; // Unknown modifier.
750
751 const MachineOperand &MO = MI->getOperand(i: OpNo);
752
753 switch (ExtraCode[0]) {
754 default:
755 // See if this is a generic print operand
756 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O);
757 case 'a': // This is an address. Currently only 'i' and 'r' are expected.
758 switch (MO.getType()) {
759 default:
760 return true;
761 case MachineOperand::MO_Immediate:
762 O << MO.getImm();
763 return false;
764 case MachineOperand::MO_ConstantPoolIndex:
765 case MachineOperand::MO_JumpTableIndex:
766 case MachineOperand::MO_ExternalSymbol:
767 llvm_unreachable("unexpected operand type!");
768 case MachineOperand::MO_GlobalAddress:
769 PrintSymbolOperand(MO, O);
770 if (Subtarget->is64Bit())
771 O << "(%rip)";
772 return false;
773 case MachineOperand::MO_Register:
774 O << '(';
775 PrintOperand(MI, OpNo, O);
776 O << ')';
777 return false;
778 }
779
780 case 'c': // Don't print "$" before a global var name or constant.
781 switch (MO.getType()) {
782 default:
783 PrintOperand(MI, OpNo, O);
784 break;
785 case MachineOperand::MO_Immediate:
786 O << MO.getImm();
787 break;
788 case MachineOperand::MO_ConstantPoolIndex:
789 case MachineOperand::MO_JumpTableIndex:
790 case MachineOperand::MO_ExternalSymbol:
791 llvm_unreachable("unexpected operand type!");
792 case MachineOperand::MO_GlobalAddress:
793 PrintSymbolOperand(MO, O);
794 break;
795 }
796 return false;
797
798 case 'A': // Print '*' before a register (it must be a register)
799 if (MO.isReg()) {
800 O << '*';
801 PrintOperand(MI, OpNo, O);
802 return false;
803 }
804 return true;
805
806 case 'b': // Print QImode register
807 case 'h': // Print QImode high register
808 case 'w': // Print HImode register
809 case 'k': // Print SImode register
810 case 'q': // Print DImode register
811 case 'V': // Print native register without '%'
812 if (MO.isReg())
813 return printAsmMRegister(P: *this, MO, Mode: ExtraCode[0], O);
814 PrintOperand(MI, OpNo, O);
815 return false;
816
817 case 'x': // Print V4SFmode register
818 case 't': // Print V8SFmode register
819 case 'g': // Print V16SFmode register
820 if (MO.isReg())
821 return printAsmVRegister(MO, Mode: ExtraCode[0], O);
822 PrintOperand(MI, OpNo, O);
823 return false;
824
825 case 'p': {
826 const MachineOperand &MO = MI->getOperand(i: OpNo);
827 if (MO.getType() != MachineOperand::MO_GlobalAddress)
828 return true;
829 PrintSymbolOperand(MO, O);
830 return false;
831 }
832
833 case 'P': // This is the operand of a call, treat specially.
834 PrintPCRelImm(MI, OpNo, O);
835 return false;
836
837 case 'n': // Negate the immediate or print a '-' before the operand.
838 // Note: this is a temporary solution. It should be handled target
839 // independently as part of the 'MC' work.
840 if (MO.isImm()) {
841 O << -MO.getImm();
842 return false;
843 }
844 O << '-';
845 }
846 }
847
848 PrintOperand(MI, OpNo, O);
849 return false;
850}
851
852bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
853 const char *ExtraCode,
854 raw_ostream &O) {
855 if (ExtraCode && ExtraCode[0]) {
856 if (ExtraCode[1] != 0) return true; // Unknown modifier.
857
858 switch (ExtraCode[0]) {
859 default: return true; // Unknown modifier.
860 case 'b': // Print QImode register
861 case 'h': // Print QImode high register
862 case 'w': // Print HImode register
863 case 'k': // Print SImode register
864 case 'q': // Print SImode register
865 // These only apply to registers, ignore on mem.
866 break;
867 case 'H':
868 if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
869 return true; // Unsupported modifier in Intel inline assembly.
870 } else {
871 PrintMemReference(MI, OpNo, O, Modifier: "H");
872 }
873 return false;
874 // Print memory only with displacement. The Modifer 'P' is used in inline
875 // asm to present a call symbol or a global symbol which can not use base
876 // reg or index reg.
877 case 'P':
878 if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
879 PrintIntelMemReference(MI, OpNo, O, Modifier: "disp-only");
880 } else {
881 PrintMemReference(MI, OpNo, O, Modifier: "disp-only");
882 }
883 return false;
884 }
885 }
886 if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) {
887 PrintIntelMemReference(MI, OpNo, O);
888 } else {
889 PrintMemReference(MI, OpNo, O);
890 }
891 return false;
892}
893
894void X86AsmPrinter::emitStartOfAsmFile(Module &M) {
895 const Triple &TT = TM.getTargetTriple();
896
897 if (TT.isOSBinFormatELF()) {
898 // Assemble feature flags that may require creation of a note section.
899 unsigned FeatureFlagsAnd = 0;
900 if (M.getModuleFlag(Key: "cf-protection-branch"))
901 FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_IBT;
902 if (M.getModuleFlag(Key: "cf-protection-return"))
903 FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_SHSTK;
904
905 if (FeatureFlagsAnd) {
906 // Emit a .note.gnu.property section with the flags.
907 assert((TT.isX86_32() || TT.isX86_64()) &&
908 "CFProtection used on invalid architecture!");
909 MCSection *Cur = OutStreamer->getCurrentSectionOnly();
910 MCSection *Nt = MMI->getContext().getELFSection(
911 Section: ".note.gnu.property", Type: ELF::SHT_NOTE, Flags: ELF::SHF_ALLOC);
912 OutStreamer->switchSection(Section: Nt);
913
914 // Emitting note header.
915 const int WordSize = TT.isX86_64() && !TT.isX32() ? 8 : 4;
916 emitAlignment(Alignment: WordSize == 4 ? Align(4) : Align(8));
917 OutStreamer->emitIntValue(Value: 4, Size: 4 /*size*/); // data size for "GNU\0"
918 OutStreamer->emitIntValue(Value: 8 + WordSize, Size: 4 /*size*/); // Elf_Prop size
919 OutStreamer->emitIntValue(Value: ELF::NT_GNU_PROPERTY_TYPE_0, Size: 4 /*size*/);
920 OutStreamer->emitBytes(Data: StringRef("GNU", 4)); // note name
921
922 // Emitting an Elf_Prop for the CET properties.
923 OutStreamer->emitInt32(Value: ELF::GNU_PROPERTY_X86_FEATURE_1_AND);
924 OutStreamer->emitInt32(Value: 4); // data size
925 OutStreamer->emitInt32(Value: FeatureFlagsAnd); // data
926 emitAlignment(Alignment: WordSize == 4 ? Align(4) : Align(8)); // padding
927
928 OutStreamer->switchSection(Section: Cur);
929 }
930 }
931
932 if (TT.isOSBinFormatMachO())
933 OutStreamer->switchSection(Section: getObjFileLowering().getTextSection());
934
935 if (TT.isOSBinFormatCOFF()) {
936 emitCOFFFeatureSymbol(M);
937 emitCOFFReplaceableFunctionData(M);
938
939 if (M.getModuleFlag(Key: "import-call-optimization"))
940 EnableImportCallOptimization = true;
941 }
942
943 // TODO: Support prefixed registers for the Intel syntax.
944 const bool IntelSyntax = MAI->getAssemblerDialect() == InlineAsm::AD_Intel;
945 OutStreamer->emitSyntaxDirective(Syntax: IntelSyntax ? "intel" : "att",
946 Options: IntelSyntax ? "noprefix" : "");
947
948 // If this is not inline asm and we're in 16-bit
949 // mode prefix assembly with .code16.
950 bool is16 = TT.getEnvironment() == Triple::CODE16;
951 if (M.getModuleInlineAsm().empty() && is16) {
952 auto *XTS =
953 static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer());
954 XTS->emitCode16();
955 }
956}
957
958static void
959emitNonLazySymbolPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel,
960 MachineModuleInfoImpl::StubValueTy &MCSym) {
961 // L_foo$stub:
962 OutStreamer.emitLabel(Symbol: StubLabel);
963 // .indirect_symbol _foo
964 OutStreamer.emitSymbolAttribute(Symbol: MCSym.getPointer(), Attribute: MCSA_IndirectSymbol);
965
966 if (MCSym.getInt())
967 // External to current translation unit.
968 OutStreamer.emitIntValue(Value: 0, Size: 4/*size*/);
969 else
970 // Internal to current translation unit.
971 //
972 // When we place the LSDA into the TEXT section, the type info
973 // pointers need to be indirect and pc-rel. We accomplish this by
974 // using NLPs; however, sometimes the types are local to the file.
975 // We need to fill in the value for the NLP in those cases.
976 OutStreamer.emitValue(
977 Value: MCSymbolRefExpr::create(Symbol: MCSym.getPointer(), Ctx&: OutStreamer.getContext()),
978 Size: 4 /*size*/);
979}
980
981static void emitNonLazyStubs(MachineModuleInfo *MMI, MCStreamer &OutStreamer) {
982
983 MachineModuleInfoMachO &MMIMacho =
984 MMI->getObjFileInfo<MachineModuleInfoMachO>();
985
986 // Output stubs for dynamically-linked functions.
987 MachineModuleInfoMachO::SymbolListTy Stubs;
988
989 // Output stubs for external and common global variables.
990 Stubs = MMIMacho.GetGVStubList();
991 if (!Stubs.empty()) {
992 OutStreamer.switchSection(Section: MMI->getContext().getMachOSection(
993 Segment: "__IMPORT", Section: "__pointers", TypeAndAttributes: MachO::S_NON_LAZY_SYMBOL_POINTERS,
994 K: SectionKind::getMetadata()));
995
996 for (auto &Stub : Stubs)
997 emitNonLazySymbolPointer(OutStreamer, StubLabel: Stub.first, MCSym&: Stub.second);
998
999 Stubs.clear();
1000 OutStreamer.addBlankLine();
1001 }
1002}
1003
1004/// True if this module is being built for windows/msvc, and uses floating
1005/// point. This is used to emit an undefined reference to _fltused. This is
1006/// needed in Windows kernel or driver contexts to find and prevent code from
1007/// modifying non-GPR registers.
1008///
1009/// TODO: It would be better if this was computed from MIR by looking for
1010/// selected floating-point instructions.
1011static bool usesMSVCFloatingPoint(const Triple &TT, const Module &M) {
1012 // Only needed for MSVC
1013 if (!TT.isWindowsMSVCEnvironment())
1014 return false;
1015
1016 for (const Function &F : M) {
1017 for (const Instruction &I : instructions(F)) {
1018 if (I.getType()->isFloatingPointTy())
1019 return true;
1020
1021 for (const auto &Op : I.operands()) {
1022 if (Op->getType()->isFloatingPointTy())
1023 return true;
1024 }
1025 }
1026 }
1027
1028 return false;
1029}
1030
1031void X86AsmPrinter::emitEndOfAsmFile(Module &M) {
1032 const Triple &TT = TM.getTargetTriple();
1033
1034 if (TT.isOSBinFormatMachO()) {
1035 // Mach-O uses non-lazy symbol stubs to encode per-TU information into
1036 // global table for symbol lookup.
1037 emitNonLazyStubs(MMI, OutStreamer&: *OutStreamer);
1038
1039 // Emit fault map information.
1040 FM.serializeToFaultMapSection();
1041
1042 // This flag tells the linker that no global symbols contain code that fall
1043 // through to other global symbols (e.g. an implementation of multiple entry
1044 // points). If this doesn't occur, the linker can safely perform dead code
1045 // stripping. Since LLVM never generates code that does this, it is always
1046 // safe to set.
1047 OutStreamer->emitSubsectionsViaSymbols();
1048 } else if (TT.isOSBinFormatCOFF()) {
1049 // If import call optimization is enabled, emit the appropriate section.
1050 // We do this whether or not we recorded any items.
1051 if (EnableImportCallOptimization) {
1052 OutStreamer->switchSection(Section: getObjFileLowering().getImportCallSection());
1053
1054 // Section always starts with some magic.
1055 constexpr char ImpCallMagic[12] = "RetpolineV1";
1056 OutStreamer->emitBytes(Data: StringRef{ImpCallMagic, sizeof(ImpCallMagic)});
1057
1058 // Layout of this section is:
1059 // Per section that contains an item to record:
1060 // uint32_t SectionSize: Size in bytes for information in this section.
1061 // uint32_t Section Number
1062 // Per call to imported function in section:
1063 // uint32_t Kind: the kind of item.
1064 // uint32_t InstOffset: the offset of the instr in its parent section.
1065 for (auto &[Section, CallsToImportedFuncs] :
1066 SectionToImportedFunctionCalls) {
1067 unsigned SectionSize =
1068 sizeof(uint32_t) * (2 + 2 * CallsToImportedFuncs.size());
1069 OutStreamer->emitInt32(Value: SectionSize);
1070 OutStreamer->emitCOFFSecNumber(Symbol: Section->getBeginSymbol());
1071 for (auto &[CallsiteSymbol, Kind] : CallsToImportedFuncs) {
1072 OutStreamer->emitInt32(Value: Kind);
1073 OutStreamer->emitCOFFSecOffset(Symbol: CallsiteSymbol);
1074 }
1075 }
1076 }
1077
1078 if (usesMSVCFloatingPoint(TT, M)) {
1079 // In Windows' libcmt.lib, there is a file which is linked in only if the
1080 // symbol _fltused is referenced. Linking this in causes some
1081 // side-effects:
1082 //
1083 // 1. For x86-32, it will set the x87 rounding mode to 53-bit instead of
1084 // 64-bit mantissas at program start.
1085 //
1086 // 2. It links in support routines for floating-point in scanf and printf.
1087 //
1088 // MSVC emits an undefined reference to _fltused when there are any
1089 // floating point operations in the program (including calls). A program
1090 // that only has: `scanf("%f", &global_float);` may fail to trigger this,
1091 // but oh well...that's a documented issue.
1092 StringRef SymbolName =
1093 (TT.getArch() == Triple::x86) ? "__fltused" : "_fltused";
1094 MCSymbol *S = MMI->getContext().getOrCreateSymbol(Name: SymbolName);
1095 OutStreamer->emitSymbolAttribute(Symbol: S, Attribute: MCSA_Global);
1096 return;
1097 }
1098 } else if (TT.isOSBinFormatELF()) {
1099 FM.serializeToFaultMapSection();
1100 }
1101
1102 // Emit __morestack address if needed for indirect calls.
1103 if (TT.isX86_64() && TM.getCodeModel() == CodeModel::Large) {
1104 if (MCSymbol *AddrSymbol = OutContext.lookupSymbol(Name: "__morestack_addr")) {
1105 Align Alignment(1);
1106 MCSection *ReadOnlySection = getObjFileLowering().getSectionForConstant(
1107 DL: getDataLayout(), Kind: SectionKind::getReadOnly(),
1108 /*C=*/nullptr, Alignment);
1109 OutStreamer->switchSection(Section: ReadOnlySection);
1110 OutStreamer->emitLabel(Symbol: AddrSymbol);
1111
1112 unsigned PtrSize = MAI->getCodePointerSize();
1113 OutStreamer->emitSymbolValue(Sym: GetExternalSymbolSymbol(Sym: "__morestack"),
1114 Size: PtrSize);
1115 }
1116 }
1117}
1118
1119char X86AsmPrinter::ID = 0;
1120
1121INITIALIZE_PASS(X86AsmPrinter, "x86-asm-printer", "X86 Assembly Printer", false,
1122 false)
1123
1124//===----------------------------------------------------------------------===//
1125// Target Registry Stuff
1126//===----------------------------------------------------------------------===//
1127
1128// Force static initialization.
1129extern "C" LLVM_C_ABI void LLVMInitializeX86AsmPrinter() {
1130 RegisterAsmPrinter<X86AsmPrinter> X(getTheX86_32Target());
1131 RegisterAsmPrinter<X86AsmPrinter> Y(getTheX86_64Target());
1132}
1133