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 "X86InstrInfo.h" |
21 | #include "X86MachineFunctionInfo.h" |
22 | #include "X86Subtarget.h" |
23 | #include "llvm/BinaryFormat/COFF.h" |
24 | #include "llvm/BinaryFormat/ELF.h" |
25 | #include "llvm/CodeGen/MachineConstantPool.h" |
26 | #include "llvm/CodeGen/MachineModuleInfoImpls.h" |
27 | #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" |
28 | #include "llvm/CodeGenTypes/MachineValueType.h" |
29 | #include "llvm/IR/DerivedTypes.h" |
30 | #include "llvm/IR/InlineAsm.h" |
31 | #include "llvm/IR/Mangler.h" |
32 | #include "llvm/IR/Module.h" |
33 | #include "llvm/IR/Type.h" |
34 | #include "llvm/MC/MCAsmInfo.h" |
35 | #include "llvm/MC/MCCodeEmitter.h" |
36 | #include "llvm/MC/MCContext.h" |
37 | #include "llvm/MC/MCExpr.h" |
38 | #include "llvm/MC/MCInst.h" |
39 | #include "llvm/MC/MCInstBuilder.h" |
40 | #include "llvm/MC/MCSectionCOFF.h" |
41 | #include "llvm/MC/MCSectionELF.h" |
42 | #include "llvm/MC/MCSectionMachO.h" |
43 | #include "llvm/MC/MCStreamer.h" |
44 | #include "llvm/MC/MCSymbol.h" |
45 | #include "llvm/MC/TargetRegistry.h" |
46 | #include "llvm/Support/Debug.h" |
47 | #include "llvm/Support/ErrorHandling.h" |
48 | #include "llvm/Target/TargetMachine.h" |
49 | |
50 | using namespace llvm; |
51 | |
52 | X86AsmPrinter::X86AsmPrinter(TargetMachine &TM, |
53 | std::unique_ptr<MCStreamer> Streamer) |
54 | : AsmPrinter(TM, std::move(Streamer)), FM(*this) {} |
55 | |
56 | //===----------------------------------------------------------------------===// |
57 | // Primitive Helper Functions. |
58 | //===----------------------------------------------------------------------===// |
59 | |
60 | /// runOnMachineFunction - Emit the function body. |
61 | /// |
62 | bool X86AsmPrinter::runOnMachineFunction(MachineFunction &MF) { |
63 | Subtarget = &MF.getSubtarget<X86Subtarget>(); |
64 | |
65 | SMShadowTracker.startFunction(MF); |
66 | CodeEmitter.reset(p: TM.getTarget().createMCCodeEmitter( |
67 | II: *Subtarget->getInstrInfo(), Ctx&: MF.getContext())); |
68 | |
69 | const Module *M = MF.getFunction().getParent(); |
70 | EmitFPOData = Subtarget->isTargetWin32() && M->getCodeViewFlag(); |
71 | |
72 | IndCSPrefix = M->getModuleFlag(Key: "indirect_branch_cs_prefix" ); |
73 | |
74 | SetupMachineFunction(MF); |
75 | |
76 | if (Subtarget->isTargetCOFF()) { |
77 | bool Local = MF.getFunction().hasLocalLinkage(); |
78 | OutStreamer->beginCOFFSymbolDef(Symbol: CurrentFnSym); |
79 | OutStreamer->emitCOFFSymbolStorageClass( |
80 | StorageClass: Local ? COFF::IMAGE_SYM_CLASS_STATIC : COFF::IMAGE_SYM_CLASS_EXTERNAL); |
81 | OutStreamer->emitCOFFSymbolType(Type: COFF::IMAGE_SYM_DTYPE_FUNCTION |
82 | << COFF::SCT_COMPLEX_TYPE_SHIFT); |
83 | OutStreamer->endCOFFSymbolDef(); |
84 | } |
85 | |
86 | // Emit the rest of the function body. |
87 | emitFunctionBody(); |
88 | |
89 | // Emit the XRay table for this function. |
90 | emitXRayTable(); |
91 | |
92 | EmitFPOData = false; |
93 | |
94 | IndCSPrefix = false; |
95 | |
96 | // We didn't modify anything. |
97 | return false; |
98 | } |
99 | |
100 | void X86AsmPrinter::emitFunctionBodyStart() { |
101 | if (EmitFPOData) { |
102 | auto *XTS = |
103 | static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer()); |
104 | XTS->emitFPOProc( |
105 | ProcSym: CurrentFnSym, |
106 | ParamsSize: MF->getInfo<X86MachineFunctionInfo>()->getArgumentStackSize()); |
107 | } |
108 | } |
109 | |
110 | void X86AsmPrinter::emitFunctionBodyEnd() { |
111 | if (EmitFPOData) { |
112 | auto *XTS = |
113 | static_cast<X86TargetStreamer *>(OutStreamer->getTargetStreamer()); |
114 | XTS->emitFPOEndProc(); |
115 | } |
116 | } |
117 | |
118 | uint32_t X86AsmPrinter::MaskKCFIType(uint32_t Value) { |
119 | // If the type hash matches an invalid pattern, mask the value. |
120 | const uint32_t InvalidValues[] = { |
121 | 0xFA1E0FF3, /* ENDBR64 */ |
122 | 0xFB1E0FF3, /* ENDBR32 */ |
123 | }; |
124 | for (uint32_t N : InvalidValues) { |
125 | // LowerKCFI_CHECK emits -Value for indirect call checks, so we must also |
126 | // mask that. Note that -(Value + 1) == ~Value. |
127 | if (N == Value || -N == Value) |
128 | return Value + 1; |
129 | } |
130 | return Value; |
131 | } |
132 | |
133 | void X86AsmPrinter::EmitKCFITypePadding(const MachineFunction &MF, |
134 | bool HasType) { |
135 | // Keep the function entry aligned, taking patchable-function-prefix into |
136 | // account if set. |
137 | int64_t PrefixBytes = 0; |
138 | (void)MF.getFunction() |
139 | .getFnAttribute(Kind: "patchable-function-prefix" ) |
140 | .getValueAsString() |
141 | .getAsInteger(Radix: 10, Result&: PrefixBytes); |
142 | |
143 | // Also take the type identifier into account if we're emitting |
144 | // one. Otherwise, just pad with nops. The X86::MOV32ri instruction emitted |
145 | // in X86AsmPrinter::emitKCFITypeId is 5 bytes long. |
146 | if (HasType) |
147 | PrefixBytes += 5; |
148 | |
149 | emitNops(N: offsetToAlignment(Value: PrefixBytes, Alignment: MF.getAlignment())); |
150 | } |
151 | |
152 | /// emitKCFITypeId - Emit the KCFI type information in architecture specific |
153 | /// format. |
154 | void X86AsmPrinter::emitKCFITypeId(const MachineFunction &MF) { |
155 | const Function &F = MF.getFunction(); |
156 | if (!F.getParent()->getModuleFlag(Key: "kcfi" )) |
157 | return; |
158 | |
159 | ConstantInt *Type = nullptr; |
160 | if (const MDNode *MD = F.getMetadata(KindID: LLVMContext::MD_kcfi_type)) |
161 | Type = mdconst::extract<ConstantInt>(MD: MD->getOperand(I: 0)); |
162 | |
163 | // If we don't have a type to emit, just emit padding if needed to maintain |
164 | // the same alignment for all functions. |
165 | if (!Type) { |
166 | EmitKCFITypePadding(MF, /*HasType=*/false); |
167 | return; |
168 | } |
169 | |
170 | // Emit a function symbol for the type data to avoid unreachable instruction |
171 | // warnings from binary validation tools, and use the same linkage as the |
172 | // parent function. Note that using local linkage would result in duplicate |
173 | // symbols for weak parent functions. |
174 | MCSymbol *FnSym = OutContext.getOrCreateSymbol(Name: "__cfi_" + MF.getName()); |
175 | emitLinkage(GV: &MF.getFunction(), GVSym: FnSym); |
176 | if (MAI->hasDotTypeDotSizeDirective()) |
177 | OutStreamer->emitSymbolAttribute(Symbol: FnSym, Attribute: MCSA_ELF_TypeFunction); |
178 | OutStreamer->emitLabel(Symbol: FnSym); |
179 | |
180 | // Embed the type hash in the X86::MOV32ri instruction to avoid special |
181 | // casing object file parsers. |
182 | EmitKCFITypePadding(MF); |
183 | EmitAndCountInstruction(Inst&: MCInstBuilder(X86::MOV32ri) |
184 | .addReg(Reg: X86::EAX) |
185 | .addImm(Val: MaskKCFIType(Value: Type->getZExtValue()))); |
186 | |
187 | if (MAI->hasDotTypeDotSizeDirective()) { |
188 | MCSymbol *EndSym = OutContext.createTempSymbol(Name: "cfi_func_end" ); |
189 | OutStreamer->emitLabel(Symbol: EndSym); |
190 | |
191 | const MCExpr *SizeExp = MCBinaryExpr::createSub( |
192 | LHS: MCSymbolRefExpr::create(Symbol: EndSym, Ctx&: OutContext), |
193 | RHS: MCSymbolRefExpr::create(Symbol: FnSym, Ctx&: OutContext), Ctx&: OutContext); |
194 | OutStreamer->emitELFSize(Symbol: FnSym, Value: SizeExp); |
195 | } |
196 | } |
197 | |
198 | /// PrintSymbolOperand - Print a raw symbol reference operand. This handles |
199 | /// jump tables, constant pools, global address and external symbols, all of |
200 | /// which print to a label with various suffixes for relocation types etc. |
201 | void X86AsmPrinter::PrintSymbolOperand(const MachineOperand &MO, |
202 | raw_ostream &O) { |
203 | switch (MO.getType()) { |
204 | default: llvm_unreachable("unknown symbol type!" ); |
205 | case MachineOperand::MO_ConstantPoolIndex: |
206 | GetCPISymbol(CPID: MO.getIndex())->print(OS&: O, MAI); |
207 | printOffset(Offset: MO.getOffset(), OS&: O); |
208 | break; |
209 | case MachineOperand::MO_GlobalAddress: { |
210 | const GlobalValue *GV = MO.getGlobal(); |
211 | |
212 | MCSymbol *GVSym; |
213 | if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || |
214 | MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) |
215 | GVSym = getSymbolWithGlobalValueBase(GV, Suffix: "$non_lazy_ptr" ); |
216 | else |
217 | GVSym = getSymbolPreferLocal(GV: *GV); |
218 | |
219 | // Handle dllimport linkage. |
220 | if (MO.getTargetFlags() == X86II::MO_DLLIMPORT) |
221 | GVSym = OutContext.getOrCreateSymbol(Name: Twine("__imp_" ) + GVSym->getName()); |
222 | else if (MO.getTargetFlags() == X86II::MO_COFFSTUB) |
223 | GVSym = |
224 | OutContext.getOrCreateSymbol(Name: Twine(".refptr." ) + GVSym->getName()); |
225 | |
226 | if (MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY || |
227 | MO.getTargetFlags() == X86II::MO_DARWIN_NONLAZY_PIC_BASE) { |
228 | MCSymbol *Sym = getSymbolWithGlobalValueBase(GV, Suffix: "$non_lazy_ptr" ); |
229 | MachineModuleInfoImpl::StubValueTy &StubSym = |
230 | MMI->getObjFileInfo<MachineModuleInfoMachO>().getGVStubEntry(Sym); |
231 | if (!StubSym.getPointer()) |
232 | StubSym = MachineModuleInfoImpl::StubValueTy(getSymbol(GV), |
233 | !GV->hasInternalLinkage()); |
234 | } |
235 | |
236 | // If the name begins with a dollar-sign, enclose it in parens. We do this |
237 | // to avoid having it look like an integer immediate to the assembler. |
238 | if (GVSym->getName()[0] != '$') |
239 | GVSym->print(OS&: O, MAI); |
240 | else { |
241 | O << '('; |
242 | GVSym->print(OS&: O, MAI); |
243 | O << ')'; |
244 | } |
245 | printOffset(Offset: MO.getOffset(), OS&: O); |
246 | break; |
247 | } |
248 | } |
249 | |
250 | switch (MO.getTargetFlags()) { |
251 | default: |
252 | llvm_unreachable("Unknown target flag on GV operand" ); |
253 | case X86II::MO_NO_FLAG: // No flag. |
254 | break; |
255 | case X86II::MO_DARWIN_NONLAZY: |
256 | case X86II::MO_DLLIMPORT: |
257 | case X86II::MO_COFFSTUB: |
258 | // These affect the name of the symbol, not any suffix. |
259 | break; |
260 | case X86II::MO_GOT_ABSOLUTE_ADDRESS: |
261 | O << " + [.-" ; |
262 | MF->getPICBaseSymbol()->print(OS&: O, MAI); |
263 | O << ']'; |
264 | break; |
265 | case X86II::MO_PIC_BASE_OFFSET: |
266 | case X86II::MO_DARWIN_NONLAZY_PIC_BASE: |
267 | O << '-'; |
268 | MF->getPICBaseSymbol()->print(OS&: O, MAI); |
269 | break; |
270 | case X86II::MO_TLSGD: O << "@TLSGD" ; break; |
271 | case X86II::MO_TLSLD: O << "@TLSLD" ; break; |
272 | case X86II::MO_TLSLDM: O << "@TLSLDM" ; break; |
273 | case X86II::MO_GOTTPOFF: O << "@GOTTPOFF" ; break; |
274 | case X86II::MO_INDNTPOFF: O << "@INDNTPOFF" ; break; |
275 | case X86II::MO_TPOFF: O << "@TPOFF" ; break; |
276 | case X86II::MO_DTPOFF: O << "@DTPOFF" ; break; |
277 | case X86II::MO_NTPOFF: O << "@NTPOFF" ; break; |
278 | case X86II::MO_GOTNTPOFF: O << "@GOTNTPOFF" ; break; |
279 | case X86II::MO_GOTPCREL: O << "@GOTPCREL" ; break; |
280 | case X86II::MO_GOTPCREL_NORELAX: O << "@GOTPCREL_NORELAX" ; break; |
281 | case X86II::MO_GOT: O << "@GOT" ; break; |
282 | case X86II::MO_GOTOFF: O << "@GOTOFF" ; break; |
283 | case X86II::MO_PLT: O << "@PLT" ; break; |
284 | case X86II::MO_TLVP: O << "@TLVP" ; break; |
285 | case X86II::MO_TLVP_PIC_BASE: |
286 | O << "@TLVP" << '-'; |
287 | MF->getPICBaseSymbol()->print(OS&: O, MAI); |
288 | break; |
289 | case X86II::MO_SECREL: O << "@SECREL32" ; break; |
290 | } |
291 | } |
292 | |
293 | void X86AsmPrinter::PrintOperand(const MachineInstr *MI, unsigned OpNo, |
294 | raw_ostream &O) { |
295 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
296 | const bool IsATT = MI->getInlineAsmDialect() == InlineAsm::AD_ATT; |
297 | switch (MO.getType()) { |
298 | default: llvm_unreachable("unknown operand type!" ); |
299 | case MachineOperand::MO_Register: { |
300 | if (IsATT) |
301 | O << '%'; |
302 | O << X86ATTInstPrinter::getRegisterName(Reg: MO.getReg()); |
303 | return; |
304 | } |
305 | |
306 | case MachineOperand::MO_Immediate: |
307 | if (IsATT) |
308 | O << '$'; |
309 | O << MO.getImm(); |
310 | return; |
311 | |
312 | case MachineOperand::MO_ConstantPoolIndex: |
313 | case MachineOperand::MO_GlobalAddress: { |
314 | switch (MI->getInlineAsmDialect()) { |
315 | case InlineAsm::AD_ATT: |
316 | O << '$'; |
317 | break; |
318 | case InlineAsm::AD_Intel: |
319 | O << "offset " ; |
320 | break; |
321 | } |
322 | PrintSymbolOperand(MO, O); |
323 | break; |
324 | } |
325 | case MachineOperand::MO_BlockAddress: { |
326 | MCSymbol *Sym = GetBlockAddressSymbol(BA: MO.getBlockAddress()); |
327 | Sym->print(OS&: O, MAI); |
328 | break; |
329 | } |
330 | } |
331 | } |
332 | |
333 | /// PrintModifiedOperand - Print subregisters based on supplied modifier, |
334 | /// deferring to PrintOperand() if no modifier was supplied or if operand is not |
335 | /// a register. |
336 | void X86AsmPrinter::PrintModifiedOperand(const MachineInstr *MI, unsigned OpNo, |
337 | raw_ostream &O, const char *Modifier) { |
338 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
339 | if (!Modifier || !MO.isReg()) |
340 | return PrintOperand(MI, OpNo, O); |
341 | if (MI->getInlineAsmDialect() == InlineAsm::AD_ATT) |
342 | O << '%'; |
343 | Register Reg = MO.getReg(); |
344 | if (strncmp(s1: Modifier, s2: "subreg" , n: strlen(s: "subreg" )) == 0) { |
345 | unsigned Size = (strcmp(s1: Modifier+6,s2: "64" ) == 0) ? 64 : |
346 | (strcmp(s1: Modifier+6,s2: "32" ) == 0) ? 32 : |
347 | (strcmp(s1: Modifier+6,s2: "16" ) == 0) ? 16 : 8; |
348 | Reg = getX86SubSuperRegister(Reg, Size); |
349 | } |
350 | O << X86ATTInstPrinter::getRegisterName(Reg); |
351 | } |
352 | |
353 | /// PrintPCRelImm - This is used to print an immediate value that ends up |
354 | /// being encoded as a pc-relative value. These print slightly differently, for |
355 | /// example, a $ is not emitted. |
356 | void X86AsmPrinter::PrintPCRelImm(const MachineInstr *MI, unsigned OpNo, |
357 | raw_ostream &O) { |
358 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
359 | switch (MO.getType()) { |
360 | default: llvm_unreachable("Unknown pcrel immediate operand" ); |
361 | case MachineOperand::MO_Register: |
362 | // pc-relativeness was handled when computing the value in the reg. |
363 | PrintOperand(MI, OpNo, O); |
364 | return; |
365 | case MachineOperand::MO_Immediate: |
366 | O << MO.getImm(); |
367 | return; |
368 | case MachineOperand::MO_GlobalAddress: |
369 | PrintSymbolOperand(MO, O); |
370 | return; |
371 | } |
372 | } |
373 | |
374 | void X86AsmPrinter::PrintLeaMemReference(const MachineInstr *MI, unsigned OpNo, |
375 | raw_ostream &O, const char *Modifier) { |
376 | const MachineOperand &BaseReg = MI->getOperand(i: OpNo + X86::AddrBaseReg); |
377 | const MachineOperand &IndexReg = MI->getOperand(i: OpNo + X86::AddrIndexReg); |
378 | const MachineOperand &DispSpec = MI->getOperand(i: OpNo + X86::AddrDisp); |
379 | |
380 | // If we really don't want to print out (rip), don't. |
381 | bool HasBaseReg = BaseReg.getReg() != 0; |
382 | if (HasBaseReg && Modifier && !strcmp(s1: Modifier, s2: "no-rip" ) && |
383 | BaseReg.getReg() == X86::RIP) |
384 | HasBaseReg = false; |
385 | |
386 | // HasParenPart - True if we will print out the () part of the mem ref. |
387 | bool HasParenPart = IndexReg.getReg() || HasBaseReg; |
388 | |
389 | switch (DispSpec.getType()) { |
390 | default: |
391 | llvm_unreachable("unknown operand type!" ); |
392 | case MachineOperand::MO_Immediate: { |
393 | int DispVal = DispSpec.getImm(); |
394 | if (DispVal || !HasParenPart) |
395 | O << DispVal; |
396 | break; |
397 | } |
398 | case MachineOperand::MO_GlobalAddress: |
399 | case MachineOperand::MO_ConstantPoolIndex: |
400 | PrintSymbolOperand(MO: DispSpec, O); |
401 | break; |
402 | } |
403 | |
404 | if (Modifier && strcmp(s1: Modifier, s2: "H" ) == 0) |
405 | O << "+8" ; |
406 | |
407 | if (HasParenPart) { |
408 | assert(IndexReg.getReg() != X86::ESP && |
409 | "X86 doesn't allow scaling by ESP" ); |
410 | |
411 | O << '('; |
412 | if (HasBaseReg) |
413 | PrintModifiedOperand(MI, OpNo: OpNo + X86::AddrBaseReg, O, Modifier); |
414 | |
415 | if (IndexReg.getReg()) { |
416 | O << ','; |
417 | PrintModifiedOperand(MI, OpNo: OpNo + X86::AddrIndexReg, O, Modifier); |
418 | unsigned ScaleVal = MI->getOperand(i: OpNo + X86::AddrScaleAmt).getImm(); |
419 | if (ScaleVal != 1) |
420 | O << ',' << ScaleVal; |
421 | } |
422 | O << ')'; |
423 | } |
424 | } |
425 | |
426 | static bool isSimpleReturn(const MachineInstr &MI) { |
427 | // We exclude all tail calls here which set both isReturn and isCall. |
428 | return MI.getDesc().isReturn() && !MI.getDesc().isCall(); |
429 | } |
430 | |
431 | static bool isIndirectBranchOrTailCall(const MachineInstr &MI) { |
432 | unsigned Opc = MI.getOpcode(); |
433 | return MI.getDesc().isIndirectBranch() /*Make below code in a good shape*/ || |
434 | Opc == X86::TAILJMPr || Opc == X86::TAILJMPm || |
435 | Opc == X86::TAILJMPr64 || Opc == X86::TAILJMPm64 || |
436 | Opc == X86::TCRETURNri || Opc == X86::TCRETURNmi || |
437 | Opc == X86::TCRETURNri64 || Opc == X86::TCRETURNmi64 || |
438 | Opc == X86::TAILJMPr64_REX || Opc == X86::TAILJMPm64_REX; |
439 | } |
440 | |
441 | void X86AsmPrinter::emitBasicBlockEnd(const MachineBasicBlock &MBB) { |
442 | if (Subtarget->hardenSlsRet() || Subtarget->hardenSlsIJmp()) { |
443 | auto I = MBB.getLastNonDebugInstr(); |
444 | if (I != MBB.end()) { |
445 | if ((Subtarget->hardenSlsRet() && isSimpleReturn(MI: *I)) || |
446 | (Subtarget->hardenSlsIJmp() && isIndirectBranchOrTailCall(MI: *I))) { |
447 | MCInst TmpInst; |
448 | TmpInst.setOpcode(X86::INT3); |
449 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
450 | } |
451 | } |
452 | } |
453 | AsmPrinter::emitBasicBlockEnd(MBB); |
454 | SMShadowTracker.emitShadowPadding(OutStreamer&: *OutStreamer, STI: getSubtargetInfo()); |
455 | } |
456 | |
457 | void X86AsmPrinter::PrintMemReference(const MachineInstr *MI, unsigned OpNo, |
458 | raw_ostream &O, const char *Modifier) { |
459 | assert(isMem(*MI, OpNo) && "Invalid memory reference!" ); |
460 | const MachineOperand &Segment = MI->getOperand(i: OpNo + X86::AddrSegmentReg); |
461 | if (Segment.getReg()) { |
462 | PrintModifiedOperand(MI, OpNo: OpNo + X86::AddrSegmentReg, O, Modifier); |
463 | O << ':'; |
464 | } |
465 | PrintLeaMemReference(MI, OpNo, O, Modifier); |
466 | } |
467 | |
468 | |
469 | void X86AsmPrinter::PrintIntelMemReference(const MachineInstr *MI, |
470 | unsigned OpNo, raw_ostream &O, |
471 | const char *Modifier) { |
472 | const MachineOperand &BaseReg = MI->getOperand(i: OpNo + X86::AddrBaseReg); |
473 | unsigned ScaleVal = MI->getOperand(i: OpNo + X86::AddrScaleAmt).getImm(); |
474 | const MachineOperand &IndexReg = MI->getOperand(i: OpNo + X86::AddrIndexReg); |
475 | const MachineOperand &DispSpec = MI->getOperand(i: OpNo + X86::AddrDisp); |
476 | const MachineOperand &SegReg = MI->getOperand(i: OpNo + X86::AddrSegmentReg); |
477 | |
478 | // If we really don't want to print out (rip), don't. |
479 | bool HasBaseReg = BaseReg.getReg() != 0; |
480 | if (HasBaseReg && Modifier && !strcmp(s1: Modifier, s2: "no-rip" ) && |
481 | BaseReg.getReg() == X86::RIP) |
482 | HasBaseReg = false; |
483 | |
484 | // If we really just want to print out displacement. |
485 | if (Modifier && (DispSpec.isGlobal() || DispSpec.isSymbol()) && |
486 | !strcmp(s1: Modifier, s2: "disp-only" )) { |
487 | HasBaseReg = false; |
488 | } |
489 | |
490 | // If this has a segment register, print it. |
491 | if (SegReg.getReg()) { |
492 | PrintOperand(MI, OpNo: OpNo + X86::AddrSegmentReg, O); |
493 | O << ':'; |
494 | } |
495 | |
496 | O << '['; |
497 | |
498 | bool NeedPlus = false; |
499 | if (HasBaseReg) { |
500 | PrintOperand(MI, OpNo: OpNo + X86::AddrBaseReg, O); |
501 | NeedPlus = true; |
502 | } |
503 | |
504 | if (IndexReg.getReg()) { |
505 | if (NeedPlus) O << " + " ; |
506 | if (ScaleVal != 1) |
507 | O << ScaleVal << '*'; |
508 | PrintOperand(MI, OpNo: OpNo + X86::AddrIndexReg, O); |
509 | NeedPlus = true; |
510 | } |
511 | |
512 | if (!DispSpec.isImm()) { |
513 | if (NeedPlus) O << " + " ; |
514 | // Do not add `offset` operator. Matches the behaviour of |
515 | // X86IntelInstPrinter::printMemReference. |
516 | PrintSymbolOperand(MO: DispSpec, O); |
517 | } else { |
518 | int64_t DispVal = DispSpec.getImm(); |
519 | if (DispVal || (!IndexReg.getReg() && !HasBaseReg)) { |
520 | if (NeedPlus) { |
521 | if (DispVal > 0) |
522 | O << " + " ; |
523 | else { |
524 | O << " - " ; |
525 | DispVal = -DispVal; |
526 | } |
527 | } |
528 | O << DispVal; |
529 | } |
530 | } |
531 | O << ']'; |
532 | } |
533 | |
534 | const MCSubtargetInfo *X86AsmPrinter::getIFuncMCSubtargetInfo() const { |
535 | assert(Subtarget); |
536 | return Subtarget; |
537 | } |
538 | |
539 | void X86AsmPrinter::emitMachOIFuncStubBody(Module &M, const GlobalIFunc &GI, |
540 | MCSymbol *LazyPointer) { |
541 | // _ifunc: |
542 | // jmpq *lazy_pointer(%rip) |
543 | |
544 | OutStreamer->emitInstruction( |
545 | Inst: MCInstBuilder(X86::JMP32m) |
546 | .addReg(Reg: X86::RIP) |
547 | .addImm(Val: 1) |
548 | .addReg(Reg: 0) |
549 | .addOperand(Op: MCOperand::createExpr( |
550 | Val: MCSymbolRefExpr::create(Symbol: LazyPointer, Ctx&: OutContext))) |
551 | .addReg(Reg: 0), |
552 | STI: *Subtarget); |
553 | } |
554 | |
555 | void X86AsmPrinter::emitMachOIFuncStubHelperBody(Module &M, |
556 | const GlobalIFunc &GI, |
557 | MCSymbol *LazyPointer) { |
558 | // _ifunc.stub_helper: |
559 | // push %rax |
560 | // push %rdi |
561 | // push %rsi |
562 | // push %rdx |
563 | // push %rcx |
564 | // push %r8 |
565 | // push %r9 |
566 | // callq foo |
567 | // movq %rax,lazy_pointer(%rip) |
568 | // pop %r9 |
569 | // pop %r8 |
570 | // pop %rcx |
571 | // pop %rdx |
572 | // pop %rsi |
573 | // pop %rdi |
574 | // pop %rax |
575 | // jmpq *lazy_pointer(%rip) |
576 | |
577 | for (int Reg : |
578 | {X86::RAX, X86::RDI, X86::RSI, X86::RDX, X86::RCX, X86::R8, X86::R9}) |
579 | OutStreamer->emitInstruction(Inst: MCInstBuilder(X86::PUSH64r).addReg(Reg), |
580 | STI: *Subtarget); |
581 | |
582 | OutStreamer->emitInstruction( |
583 | Inst: MCInstBuilder(X86::CALL64pcrel32) |
584 | .addOperand(Op: MCOperand::createExpr(Val: lowerConstant(CV: GI.getResolver()))), |
585 | STI: *Subtarget); |
586 | |
587 | OutStreamer->emitInstruction( |
588 | Inst: MCInstBuilder(X86::MOV64mr) |
589 | .addReg(Reg: X86::RIP) |
590 | .addImm(Val: 1) |
591 | .addReg(Reg: 0) |
592 | .addOperand(Op: MCOperand::createExpr( |
593 | Val: MCSymbolRefExpr::create(Symbol: LazyPointer, Ctx&: OutContext))) |
594 | .addReg(Reg: 0) |
595 | .addReg(Reg: X86::RAX), |
596 | STI: *Subtarget); |
597 | |
598 | for (int Reg : |
599 | {X86::R9, X86::R8, X86::RCX, X86::RDX, X86::RSI, X86::RDI, X86::RAX}) |
600 | OutStreamer->emitInstruction(Inst: MCInstBuilder(X86::POP64r).addReg(Reg), |
601 | STI: *Subtarget); |
602 | |
603 | OutStreamer->emitInstruction( |
604 | Inst: MCInstBuilder(X86::JMP32m) |
605 | .addReg(Reg: X86::RIP) |
606 | .addImm(Val: 1) |
607 | .addReg(Reg: 0) |
608 | .addOperand(Op: MCOperand::createExpr( |
609 | Val: MCSymbolRefExpr::create(Symbol: LazyPointer, Ctx&: OutContext))) |
610 | .addReg(Reg: 0), |
611 | STI: *Subtarget); |
612 | } |
613 | |
614 | static bool printAsmMRegister(const X86AsmPrinter &P, const MachineOperand &MO, |
615 | char Mode, raw_ostream &O) { |
616 | Register Reg = MO.getReg(); |
617 | bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT; |
618 | |
619 | if (!X86::GR8RegClass.contains(Reg) && |
620 | !X86::GR16RegClass.contains(Reg) && |
621 | !X86::GR32RegClass.contains(Reg) && |
622 | !X86::GR64RegClass.contains(Reg)) |
623 | return true; |
624 | |
625 | switch (Mode) { |
626 | default: return true; // Unknown mode. |
627 | case 'b': // Print QImode register |
628 | Reg = getX86SubSuperRegister(Reg, Size: 8); |
629 | break; |
630 | case 'h': // Print QImode high register |
631 | Reg = getX86SubSuperRegister(Reg, Size: 8, High: true); |
632 | if (!Reg.isValid()) |
633 | return true; |
634 | break; |
635 | case 'w': // Print HImode register |
636 | Reg = getX86SubSuperRegister(Reg, Size: 16); |
637 | break; |
638 | case 'k': // Print SImode register |
639 | Reg = getX86SubSuperRegister(Reg, Size: 32); |
640 | break; |
641 | case 'V': |
642 | EmitPercent = false; |
643 | [[fallthrough]]; |
644 | case 'q': |
645 | // Print 64-bit register names if 64-bit integer registers are available. |
646 | // Otherwise, print 32-bit register names. |
647 | Reg = getX86SubSuperRegister(Reg, Size: P.getSubtarget().is64Bit() ? 64 : 32); |
648 | break; |
649 | } |
650 | |
651 | if (EmitPercent) |
652 | O << '%'; |
653 | |
654 | O << X86ATTInstPrinter::getRegisterName(Reg); |
655 | return false; |
656 | } |
657 | |
658 | static bool printAsmVRegister(const MachineOperand &MO, char Mode, |
659 | raw_ostream &O) { |
660 | Register Reg = MO.getReg(); |
661 | bool EmitPercent = MO.getParent()->getInlineAsmDialect() == InlineAsm::AD_ATT; |
662 | |
663 | unsigned Index; |
664 | if (X86::VR128XRegClass.contains(Reg)) |
665 | Index = Reg - X86::XMM0; |
666 | else if (X86::VR256XRegClass.contains(Reg)) |
667 | Index = Reg - X86::YMM0; |
668 | else if (X86::VR512RegClass.contains(Reg)) |
669 | Index = Reg - X86::ZMM0; |
670 | else |
671 | return true; |
672 | |
673 | switch (Mode) { |
674 | default: // Unknown mode. |
675 | return true; |
676 | case 'x': // Print V4SFmode register |
677 | Reg = X86::XMM0 + Index; |
678 | break; |
679 | case 't': // Print V8SFmode register |
680 | Reg = X86::YMM0 + Index; |
681 | break; |
682 | case 'g': // Print V16SFmode register |
683 | Reg = X86::ZMM0 + Index; |
684 | break; |
685 | } |
686 | |
687 | if (EmitPercent) |
688 | O << '%'; |
689 | |
690 | O << X86ATTInstPrinter::getRegisterName(Reg); |
691 | return false; |
692 | } |
693 | |
694 | /// PrintAsmOperand - Print out an operand for an inline asm expression. |
695 | /// |
696 | bool X86AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
697 | const char *, raw_ostream &O) { |
698 | // Does this asm operand have a single letter operand modifier? |
699 | if (ExtraCode && ExtraCode[0]) { |
700 | if (ExtraCode[1] != 0) return true; // Unknown modifier. |
701 | |
702 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
703 | |
704 | switch (ExtraCode[0]) { |
705 | default: |
706 | // See if this is a generic print operand |
707 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O); |
708 | case 'a': // This is an address. Currently only 'i' and 'r' are expected. |
709 | switch (MO.getType()) { |
710 | default: |
711 | return true; |
712 | case MachineOperand::MO_Immediate: |
713 | O << MO.getImm(); |
714 | return false; |
715 | case MachineOperand::MO_ConstantPoolIndex: |
716 | case MachineOperand::MO_JumpTableIndex: |
717 | case MachineOperand::MO_ExternalSymbol: |
718 | llvm_unreachable("unexpected operand type!" ); |
719 | case MachineOperand::MO_GlobalAddress: |
720 | PrintSymbolOperand(MO, O); |
721 | if (Subtarget->isPICStyleRIPRel()) |
722 | O << "(%rip)" ; |
723 | return false; |
724 | case MachineOperand::MO_Register: |
725 | O << '('; |
726 | PrintOperand(MI, OpNo, O); |
727 | O << ')'; |
728 | return false; |
729 | } |
730 | |
731 | case 'c': // Don't print "$" before a global var name or constant. |
732 | switch (MO.getType()) { |
733 | default: |
734 | PrintOperand(MI, OpNo, O); |
735 | break; |
736 | case MachineOperand::MO_Immediate: |
737 | O << MO.getImm(); |
738 | break; |
739 | case MachineOperand::MO_ConstantPoolIndex: |
740 | case MachineOperand::MO_JumpTableIndex: |
741 | case MachineOperand::MO_ExternalSymbol: |
742 | llvm_unreachable("unexpected operand type!" ); |
743 | case MachineOperand::MO_GlobalAddress: |
744 | PrintSymbolOperand(MO, O); |
745 | break; |
746 | } |
747 | return false; |
748 | |
749 | case 'A': // Print '*' before a register (it must be a register) |
750 | if (MO.isReg()) { |
751 | O << '*'; |
752 | PrintOperand(MI, OpNo, O); |
753 | return false; |
754 | } |
755 | return true; |
756 | |
757 | case 'b': // Print QImode register |
758 | case 'h': // Print QImode high register |
759 | case 'w': // Print HImode register |
760 | case 'k': // Print SImode register |
761 | case 'q': // Print DImode register |
762 | case 'V': // Print native register without '%' |
763 | if (MO.isReg()) |
764 | return printAsmMRegister(P: *this, MO, Mode: ExtraCode[0], O); |
765 | PrintOperand(MI, OpNo, O); |
766 | return false; |
767 | |
768 | case 'x': // Print V4SFmode register |
769 | case 't': // Print V8SFmode register |
770 | case 'g': // Print V16SFmode register |
771 | if (MO.isReg()) |
772 | return printAsmVRegister(MO, Mode: ExtraCode[0], O); |
773 | PrintOperand(MI, OpNo, O); |
774 | return false; |
775 | |
776 | case 'p': { |
777 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
778 | if (MO.getType() != MachineOperand::MO_GlobalAddress) |
779 | return true; |
780 | PrintSymbolOperand(MO, O); |
781 | return false; |
782 | } |
783 | |
784 | case 'P': // This is the operand of a call, treat specially. |
785 | PrintPCRelImm(MI, OpNo, O); |
786 | return false; |
787 | |
788 | case 'n': // Negate the immediate or print a '-' before the operand. |
789 | // Note: this is a temporary solution. It should be handled target |
790 | // independently as part of the 'MC' work. |
791 | if (MO.isImm()) { |
792 | O << -MO.getImm(); |
793 | return false; |
794 | } |
795 | O << '-'; |
796 | } |
797 | } |
798 | |
799 | PrintOperand(MI, OpNo, O); |
800 | return false; |
801 | } |
802 | |
803 | bool X86AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
804 | const char *, |
805 | raw_ostream &O) { |
806 | if (ExtraCode && ExtraCode[0]) { |
807 | if (ExtraCode[1] != 0) return true; // Unknown modifier. |
808 | |
809 | switch (ExtraCode[0]) { |
810 | default: return true; // Unknown modifier. |
811 | case 'b': // Print QImode register |
812 | case 'h': // Print QImode high register |
813 | case 'w': // Print HImode register |
814 | case 'k': // Print SImode register |
815 | case 'q': // Print SImode register |
816 | // These only apply to registers, ignore on mem. |
817 | break; |
818 | case 'H': |
819 | if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) { |
820 | return true; // Unsupported modifier in Intel inline assembly. |
821 | } else { |
822 | PrintMemReference(MI, OpNo, O, Modifier: "H" ); |
823 | } |
824 | return false; |
825 | // Print memory only with displacement. The Modifer 'P' is used in inline |
826 | // asm to present a call symbol or a global symbol which can not use base |
827 | // reg or index reg. |
828 | case 'P': |
829 | if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) { |
830 | PrintIntelMemReference(MI, OpNo, O, Modifier: "disp-only" ); |
831 | } else { |
832 | PrintMemReference(MI, OpNo, O, Modifier: "disp-only" ); |
833 | } |
834 | return false; |
835 | } |
836 | } |
837 | if (MI->getInlineAsmDialect() == InlineAsm::AD_Intel) { |
838 | PrintIntelMemReference(MI, OpNo, O, Modifier: nullptr); |
839 | } else { |
840 | PrintMemReference(MI, OpNo, O, Modifier: nullptr); |
841 | } |
842 | return false; |
843 | } |
844 | |
845 | void X86AsmPrinter::emitStartOfAsmFile(Module &M) { |
846 | const Triple &TT = TM.getTargetTriple(); |
847 | |
848 | if (TT.isOSBinFormatELF()) { |
849 | // Assemble feature flags that may require creation of a note section. |
850 | unsigned FeatureFlagsAnd = 0; |
851 | if (M.getModuleFlag(Key: "cf-protection-branch" )) |
852 | FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_IBT; |
853 | if (M.getModuleFlag(Key: "cf-protection-return" )) |
854 | FeatureFlagsAnd |= ELF::GNU_PROPERTY_X86_FEATURE_1_SHSTK; |
855 | |
856 | if (FeatureFlagsAnd) { |
857 | // Emit a .note.gnu.property section with the flags. |
858 | assert((TT.isArch32Bit() || TT.isArch64Bit()) && |
859 | "CFProtection used on invalid architecture!" ); |
860 | MCSection *Cur = OutStreamer->getCurrentSectionOnly(); |
861 | MCSection *Nt = MMI->getContext().getELFSection( |
862 | Section: ".note.gnu.property" , Type: ELF::SHT_NOTE, Flags: ELF::SHF_ALLOC); |
863 | OutStreamer->switchSection(Section: Nt); |
864 | |
865 | // Emitting note header. |
866 | const int WordSize = TT.isArch64Bit() && !TT.isX32() ? 8 : 4; |
867 | emitAlignment(Alignment: WordSize == 4 ? Align(4) : Align(8)); |
868 | OutStreamer->emitIntValue(Value: 4, Size: 4 /*size*/); // data size for "GNU\0" |
869 | OutStreamer->emitIntValue(Value: 8 + WordSize, Size: 4 /*size*/); // Elf_Prop size |
870 | OutStreamer->emitIntValue(Value: ELF::NT_GNU_PROPERTY_TYPE_0, Size: 4 /*size*/); |
871 | OutStreamer->emitBytes(Data: StringRef("GNU" , 4)); // note name |
872 | |
873 | // Emitting an Elf_Prop for the CET properties. |
874 | OutStreamer->emitInt32(Value: ELF::GNU_PROPERTY_X86_FEATURE_1_AND); |
875 | OutStreamer->emitInt32(Value: 4); // data size |
876 | OutStreamer->emitInt32(Value: FeatureFlagsAnd); // data |
877 | emitAlignment(Alignment: WordSize == 4 ? Align(4) : Align(8)); // padding |
878 | |
879 | OutStreamer->switchSection(Section: Cur); |
880 | } |
881 | } |
882 | |
883 | if (TT.isOSBinFormatMachO()) |
884 | OutStreamer->switchSection(Section: getObjFileLowering().getTextSection()); |
885 | |
886 | if (TT.isOSBinFormatCOFF()) { |
887 | // Emit an absolute @feat.00 symbol. |
888 | MCSymbol *S = MMI->getContext().getOrCreateSymbol(Name: StringRef("@feat.00" )); |
889 | OutStreamer->beginCOFFSymbolDef(Symbol: S); |
890 | OutStreamer->emitCOFFSymbolStorageClass(StorageClass: COFF::IMAGE_SYM_CLASS_STATIC); |
891 | OutStreamer->emitCOFFSymbolType(Type: COFF::IMAGE_SYM_DTYPE_NULL); |
892 | OutStreamer->endCOFFSymbolDef(); |
893 | int64_t Feat00Value = 0; |
894 | |
895 | if (TT.getArch() == Triple::x86) { |
896 | // According to the PE-COFF spec, the LSB of this value marks the object |
897 | // for "registered SEH". This means that all SEH handler entry points |
898 | // must be registered in .sxdata. Use of any unregistered handlers will |
899 | // cause the process to terminate immediately. LLVM does not know how to |
900 | // register any SEH handlers, so its object files should be safe. |
901 | Feat00Value |= COFF::Feat00Flags::SafeSEH; |
902 | } |
903 | |
904 | if (M.getModuleFlag(Key: "cfguard" )) { |
905 | // Object is CFG-aware. |
906 | Feat00Value |= COFF::Feat00Flags::GuardCF; |
907 | } |
908 | |
909 | if (M.getModuleFlag(Key: "ehcontguard" )) { |
910 | // Object also has EHCont. |
911 | Feat00Value |= COFF::Feat00Flags::GuardEHCont; |
912 | } |
913 | |
914 | if (M.getModuleFlag(Key: "ms-kernel" )) { |
915 | // Object is compiled with /kernel. |
916 | Feat00Value |= COFF::Feat00Flags::Kernel; |
917 | } |
918 | |
919 | OutStreamer->emitSymbolAttribute(Symbol: S, Attribute: MCSA_Global); |
920 | OutStreamer->emitAssignment( |
921 | Symbol: S, Value: MCConstantExpr::create(Value: Feat00Value, Ctx&: MMI->getContext())); |
922 | } |
923 | OutStreamer->emitSyntaxDirective(); |
924 | |
925 | // If this is not inline asm and we're in 16-bit |
926 | // mode prefix assembly with .code16. |
927 | bool is16 = TT.getEnvironment() == Triple::CODE16; |
928 | if (M.getModuleInlineAsm().empty() && is16) |
929 | OutStreamer->emitAssemblerFlag(Flag: MCAF_Code16); |
930 | } |
931 | |
932 | static void |
933 | emitNonLazySymbolPointer(MCStreamer &OutStreamer, MCSymbol *StubLabel, |
934 | MachineModuleInfoImpl::StubValueTy &MCSym) { |
935 | // L_foo$stub: |
936 | OutStreamer.emitLabel(Symbol: StubLabel); |
937 | // .indirect_symbol _foo |
938 | OutStreamer.emitSymbolAttribute(Symbol: MCSym.getPointer(), Attribute: MCSA_IndirectSymbol); |
939 | |
940 | if (MCSym.getInt()) |
941 | // External to current translation unit. |
942 | OutStreamer.emitIntValue(Value: 0, Size: 4/*size*/); |
943 | else |
944 | // Internal to current translation unit. |
945 | // |
946 | // When we place the LSDA into the TEXT section, the type info |
947 | // pointers need to be indirect and pc-rel. We accomplish this by |
948 | // using NLPs; however, sometimes the types are local to the file. |
949 | // We need to fill in the value for the NLP in those cases. |
950 | OutStreamer.emitValue( |
951 | Value: MCSymbolRefExpr::create(Symbol: MCSym.getPointer(), Ctx&: OutStreamer.getContext()), |
952 | Size: 4 /*size*/); |
953 | } |
954 | |
955 | static void emitNonLazyStubs(MachineModuleInfo *MMI, MCStreamer &OutStreamer) { |
956 | |
957 | MachineModuleInfoMachO &MMIMacho = |
958 | MMI->getObjFileInfo<MachineModuleInfoMachO>(); |
959 | |
960 | // Output stubs for dynamically-linked functions. |
961 | MachineModuleInfoMachO::SymbolListTy Stubs; |
962 | |
963 | // Output stubs for external and common global variables. |
964 | Stubs = MMIMacho.GetGVStubList(); |
965 | if (!Stubs.empty()) { |
966 | OutStreamer.switchSection(Section: MMI->getContext().getMachOSection( |
967 | Segment: "__IMPORT" , Section: "__pointers" , TypeAndAttributes: MachO::S_NON_LAZY_SYMBOL_POINTERS, |
968 | K: SectionKind::getMetadata())); |
969 | |
970 | for (auto &Stub : Stubs) |
971 | emitNonLazySymbolPointer(OutStreamer, StubLabel: Stub.first, MCSym&: Stub.second); |
972 | |
973 | Stubs.clear(); |
974 | OutStreamer.addBlankLine(); |
975 | } |
976 | } |
977 | |
978 | void X86AsmPrinter::emitEndOfAsmFile(Module &M) { |
979 | const Triple &TT = TM.getTargetTriple(); |
980 | |
981 | if (TT.isOSBinFormatMachO()) { |
982 | // Mach-O uses non-lazy symbol stubs to encode per-TU information into |
983 | // global table for symbol lookup. |
984 | emitNonLazyStubs(MMI, OutStreamer&: *OutStreamer); |
985 | |
986 | // Emit fault map information. |
987 | FM.serializeToFaultMapSection(); |
988 | |
989 | // This flag tells the linker that no global symbols contain code that fall |
990 | // through to other global symbols (e.g. an implementation of multiple entry |
991 | // points). If this doesn't occur, the linker can safely perform dead code |
992 | // stripping. Since LLVM never generates code that does this, it is always |
993 | // safe to set. |
994 | OutStreamer->emitAssemblerFlag(Flag: MCAF_SubsectionsViaSymbols); |
995 | } else if (TT.isOSBinFormatCOFF()) { |
996 | if (MMI->usesMSVCFloatingPoint()) { |
997 | // In Windows' libcmt.lib, there is a file which is linked in only if the |
998 | // symbol _fltused is referenced. Linking this in causes some |
999 | // side-effects: |
1000 | // |
1001 | // 1. For x86-32, it will set the x87 rounding mode to 53-bit instead of |
1002 | // 64-bit mantissas at program start. |
1003 | // |
1004 | // 2. It links in support routines for floating-point in scanf and printf. |
1005 | // |
1006 | // MSVC emits an undefined reference to _fltused when there are any |
1007 | // floating point operations in the program (including calls). A program |
1008 | // that only has: `scanf("%f", &global_float);` may fail to trigger this, |
1009 | // but oh well...that's a documented issue. |
1010 | StringRef SymbolName = |
1011 | (TT.getArch() == Triple::x86) ? "__fltused" : "_fltused" ; |
1012 | MCSymbol *S = MMI->getContext().getOrCreateSymbol(Name: SymbolName); |
1013 | OutStreamer->emitSymbolAttribute(Symbol: S, Attribute: MCSA_Global); |
1014 | return; |
1015 | } |
1016 | } else if (TT.isOSBinFormatELF()) { |
1017 | FM.serializeToFaultMapSection(); |
1018 | } |
1019 | |
1020 | // Emit __morestack address if needed for indirect calls. |
1021 | if (TT.getArch() == Triple::x86_64 && TM.getCodeModel() == CodeModel::Large) { |
1022 | if (MCSymbol *AddrSymbol = OutContext.lookupSymbol(Name: "__morestack_addr" )) { |
1023 | Align Alignment(1); |
1024 | MCSection *ReadOnlySection = getObjFileLowering().getSectionForConstant( |
1025 | DL: getDataLayout(), Kind: SectionKind::getReadOnly(), |
1026 | /*C=*/nullptr, Alignment); |
1027 | OutStreamer->switchSection(Section: ReadOnlySection); |
1028 | OutStreamer->emitLabel(Symbol: AddrSymbol); |
1029 | |
1030 | unsigned PtrSize = MAI->getCodePointerSize(); |
1031 | OutStreamer->emitSymbolValue(Sym: GetExternalSymbolSymbol(Sym: "__morestack" ), |
1032 | Size: PtrSize); |
1033 | } |
1034 | } |
1035 | } |
1036 | |
1037 | //===----------------------------------------------------------------------===// |
1038 | // Target Registry Stuff |
1039 | //===----------------------------------------------------------------------===// |
1040 | |
1041 | // Force static initialization. |
1042 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeX86AsmPrinter() { |
1043 | RegisterAsmPrinter<X86AsmPrinter> X(getTheX86_32Target()); |
1044 | RegisterAsmPrinter<X86AsmPrinter> Y(getTheX86_64Target()); |
1045 | } |
1046 | |