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