1//===- llvm/MC/MCWinCOFFStreamer.cpp --------------------------------------===//
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 an implementation of a Windows COFF object file streamer.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/MC/MCWinCOFFStreamer.h"
14#include "llvm/ADT/SmallString.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/Twine.h"
17#include "llvm/BinaryFormat/COFF.h"
18#include "llvm/MC/MCAsmBackend.h"
19#include "llvm/MC/MCAssembler.h"
20#include "llvm/MC/MCCodeEmitter.h"
21#include "llvm/MC/MCCodeView.h"
22#include "llvm/MC/MCContext.h"
23#include "llvm/MC/MCExpr.h"
24#include "llvm/MC/MCFixup.h"
25#include "llvm/MC/MCObjectFileInfo.h"
26#include "llvm/MC/MCObjectStreamer.h"
27#include "llvm/MC/MCObjectWriter.h"
28#include "llvm/MC/MCSectionCOFF.h"
29#include "llvm/MC/MCSymbolCOFF.h"
30#include "llvm/MC/MCTargetOptions.h"
31#include "llvm/MC/MCValue.h"
32#include "llvm/MC/MCWinCOFFObjectWriter.h"
33#include "llvm/Support/ErrorHandling.h"
34#include "llvm/Support/MathExtras.h"
35#include "llvm/Support/SMLoc.h"
36#include "llvm/Support/raw_ostream.h"
37#include "llvm/TargetParser/Triple.h"
38#include <algorithm>
39#include <cstdint>
40
41using namespace llvm;
42
43#define DEBUG_TYPE "WinCOFFStreamer"
44
45/// MCExpr that represents the physical number for the sections that contains
46/// a symbol.
47class MCCOFFSectionNumberTargetExpr final : public MCTargetExpr {
48 const MCSymbol &SectionSymbol;
49 const WinCOFFObjectWriter &Writer;
50
51 MCCOFFSectionNumberTargetExpr(const MCSymbol &SectionSymbol_,
52 const WinCOFFObjectWriter &Writer_)
53 : SectionSymbol(SectionSymbol_), Writer(Writer_) {}
54
55public:
56 static MCCOFFSectionNumberTargetExpr *
57 create(const MCSymbol &SectionSymbol, const WinCOFFObjectWriter &Writer,
58 MCContext &Ctx) {
59 return new (Ctx) MCCOFFSectionNumberTargetExpr(SectionSymbol, Writer);
60 }
61
62 void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override {
63 OS << ":secnum:";
64 SectionSymbol.print(OS, MAI);
65 }
66
67 bool evaluateAsRelocatableImpl(MCValue &Res,
68 const MCAssembler *Asm) const override {
69 auto sectionNumber = Writer.getSectionNumber(Section: SectionSymbol.getSection());
70 assert(sectionNumber != 0 &&
71 "Containing section was not assigned a number");
72 Res = MCValue::get(Val: sectionNumber);
73 return true;
74 }
75
76 void visitUsedExpr(MCStreamer &Streamer) const override {
77 // Contains no sub-expressions.
78 }
79
80 MCFragment *findAssociatedFragment() const override {
81 return SectionSymbol.getFragment();
82 }
83};
84
85/// MCExpr that represents the offset to a symbol from the beginning of its
86/// section.
87class MCCOFFSectionOffsetTargetExpr final : public MCTargetExpr {
88 const MCSymbol &Symbol;
89
90 MCCOFFSectionOffsetTargetExpr(const MCSymbol &Symbol_) : Symbol(Symbol_) {}
91
92public:
93 static MCCOFFSectionOffsetTargetExpr *create(const MCSymbol &Symbol,
94 MCContext &Ctx) {
95 return new (Ctx) MCCOFFSectionOffsetTargetExpr(Symbol);
96 }
97
98 void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override {
99 OS << ":secoffset:";
100 Symbol.print(OS, MAI);
101 }
102
103 bool evaluateAsRelocatableImpl(MCValue &Res,
104 const MCAssembler *Asm) const override {
105 uint64_t CallsiteOffset = 0;
106 if (!Asm->getSymbolOffset(S: Symbol, Val&: CallsiteOffset)) {
107 return true;
108 }
109 Res = MCValue::get(Val: CallsiteOffset);
110 return true;
111 }
112
113 void visitUsedExpr(MCStreamer &Streamer) const override {
114 // Contains no sub-expressions.
115 }
116
117 MCFragment *findAssociatedFragment() const override {
118 return Symbol.getFragment();
119 }
120};
121
122MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context,
123 std::unique_ptr<MCAsmBackend> MAB,
124 std::unique_ptr<MCCodeEmitter> CE,
125 std::unique_ptr<MCObjectWriter> OW)
126 : MCObjectStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)),
127 CurSymbol(nullptr) {
128 if (Context.getTargetOptions().MCIncrementalLinkerCompatible)
129 getWriter().setIncrementalLinkerCompatible(true);
130}
131
132WinCOFFObjectWriter &MCWinCOFFStreamer::getWriter() {
133 return static_cast<WinCOFFObjectWriter &>(getAssembler().getWriter());
134}
135
136void MCWinCOFFStreamer::initSections(const MCSubtargetInfo &STI) {
137 // FIXME: this is identical to the ELF one.
138 // This emulates the same behavior of GNU as. This makes it easier
139 // to compare the output as the major sections are in the same order.
140 switchSection(Section: getContext().getObjectFileInfo()->getTextSection());
141 emitCodeAlignment(ByteAlignment: Align(4), STI);
142
143 switchSection(Section: getContext().getObjectFileInfo()->getDataSection());
144 emitCodeAlignment(ByteAlignment: Align(4), STI);
145
146 switchSection(Section: getContext().getObjectFileInfo()->getBSSSection());
147 emitCodeAlignment(ByteAlignment: Align(4), STI);
148
149 switchSection(Section: getContext().getObjectFileInfo()->getTextSection());
150}
151
152void MCWinCOFFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
153 MCObjectStreamer::changeSection(Section, Subsection);
154 // Ensure that the first and the second symbols relative to the section are
155 // the section symbol and the COMDAT symbol.
156 getAssembler().registerSymbol(Symbol: *Section->getBeginSymbol());
157 if (auto *Sym =
158 static_cast<const MCSectionCOFF *>(Section)->getCOMDATSymbol())
159 getAssembler().registerSymbol(Symbol: *Sym);
160}
161
162void MCWinCOFFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
163 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
164 MCObjectStreamer::emitLabel(Symbol, Loc);
165}
166
167bool MCWinCOFFStreamer::emitSymbolAttribute(MCSymbol *S,
168 MCSymbolAttr Attribute) {
169 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
170 getAssembler().registerSymbol(Symbol: *Symbol);
171
172 switch (Attribute) {
173 default: return false;
174 case MCSA_WeakReference:
175 case MCSA_Weak:
176 Symbol->setWeakExternalCharacteristics(COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS);
177 Symbol->setExternal(true);
178 break;
179 case MCSA_WeakAntiDep:
180 Symbol->setWeakExternalCharacteristics(COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY);
181 Symbol->setExternal(true);
182 Symbol->setIsWeakExternal(true);
183 break;
184 case MCSA_Global:
185 Symbol->setExternal(true);
186 break;
187 case MCSA_AltEntry:
188 llvm_unreachable("COFF doesn't support the .alt_entry attribute");
189 }
190
191 return true;
192}
193
194void MCWinCOFFStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
195 llvm_unreachable("not implemented");
196}
197
198void MCWinCOFFStreamer::beginCOFFSymbolDef(MCSymbol const *S) {
199 if (CurSymbol)
200 Error(Msg: "starting a new symbol definition without completing the "
201 "previous one");
202 CurSymbol = static_cast<MCSymbolCOFF *>(const_cast<MCSymbol *>(S));
203}
204
205void MCWinCOFFStreamer::emitCOFFSymbolStorageClass(int StorageClass) {
206 if (!CurSymbol) {
207 Error(Msg: "storage class specified outside of symbol definition");
208 return;
209 }
210
211 if (StorageClass & ~COFF::SSC_Invalid) {
212 Error(Msg: "storage class value '" + Twine(StorageClass) +
213 "' out of range");
214 return;
215 }
216
217 getAssembler().registerSymbol(Symbol: *CurSymbol);
218 static_cast<MCSymbolCOFF *>(CurSymbol)->setClass((uint16_t)StorageClass);
219}
220
221void MCWinCOFFStreamer::emitCOFFSymbolType(int Type) {
222 if (!CurSymbol) {
223 Error(Msg: "symbol type specified outside of a symbol definition");
224 return;
225 }
226
227 if (Type & ~0xffff) {
228 Error(Msg: "type value '" + Twine(Type) + "' out of range");
229 return;
230 }
231
232 getAssembler().registerSymbol(Symbol: *CurSymbol);
233 static_cast<const MCSymbolCOFF *>(CurSymbol)->setType((uint16_t)Type);
234}
235
236void MCWinCOFFStreamer::endCOFFSymbolDef() {
237 if (!CurSymbol)
238 Error(Msg: "ending symbol definition without starting one");
239 CurSymbol = nullptr;
240}
241
242void MCWinCOFFStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {
243 // SafeSEH is a feature specific to 32-bit x86. It does not exist (and is
244 // unnecessary) on all platforms which use table-based exception dispatch.
245 if (getContext().getTargetTriple().getArch() != Triple::x86)
246 return;
247
248 auto *CSymbol = static_cast<const MCSymbolCOFF *>(Symbol);
249 if (CSymbol->isSafeSEH())
250 return;
251
252 MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection();
253 pushSection();
254 switchSection(Section: SXData);
255 SXData->ensureMinAlignment(MinAlignment: Align(4));
256
257 newSpecialFragment<MCSymbolIdFragment>(args&: Symbol);
258 getAssembler().registerSymbol(Symbol: *Symbol);
259 CSymbol->setIsSafeSEH();
260
261 // The Microsoft linker requires that the symbol type of a handler be
262 // function. Go ahead and oblige it here.
263 CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION
264 << COFF::SCT_COMPLEX_TYPE_SHIFT);
265 popSection();
266}
267
268void MCWinCOFFStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
269 MCSection *Sec = getCurrentSectionOnly();
270 Sec->ensureMinAlignment(MinAlignment: Align(4));
271
272 newSpecialFragment<MCSymbolIdFragment>(args&: Symbol);
273 getAssembler().registerSymbol(Symbol: *Symbol);
274}
275
276void MCWinCOFFStreamer::emitCOFFSectionIndex(const MCSymbol *Symbol) {
277 visitUsedSymbol(Sym: *Symbol);
278 const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, Ctx&: getContext());
279 ensureHeadroom(Headroom: 2);
280 addFixup(Value: SRE, Kind: FK_SecRel_2);
281 appendContents(Num: 2, Elt: 0);
282}
283
284void MCWinCOFFStreamer::emitCOFFSecRel32(const MCSymbol *Symbol,
285 uint64_t Offset) {
286 visitUsedSymbol(Sym: *Symbol);
287 // Create Symbol A for the relocation relative reference.
288 const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, Ctx&: getContext());
289 // Add the constant offset, if given.
290 if (Offset)
291 MCE = MCBinaryExpr::createAdd(
292 LHS: MCE, RHS: MCConstantExpr::create(Value: Offset, Ctx&: getContext()), Ctx&: getContext());
293 ensureHeadroom(Headroom: 4);
294 addFixup(Value: MCE, Kind: FK_SecRel_4);
295 // Emit 4 bytes (zeros) to the object file.
296 appendContents(Num: 4, Elt: 0);
297}
298
299void MCWinCOFFStreamer::emitCOFFImgRel32(const MCSymbol *Symbol,
300 int64_t Offset) {
301 visitUsedSymbol(Sym: *Symbol);
302 // Create Symbol A for the relocation relative reference.
303 const MCExpr *MCE = MCSymbolRefExpr::create(
304 Symbol, specifier: MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx&: getContext());
305 // Add the constant offset, if given.
306 if (Offset)
307 MCE = MCBinaryExpr::createAdd(
308 LHS: MCE, RHS: MCConstantExpr::create(Value: Offset, Ctx&: getContext()), Ctx&: getContext());
309 ensureHeadroom(Headroom: 4);
310 addFixup(Value: MCE, Kind: FK_Data_4);
311 // Emit 4 bytes (zeros) to the object file.
312 appendContents(Num: 4, Elt: 0);
313}
314
315void MCWinCOFFStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {
316 visitUsedSymbol(Sym: *Symbol);
317 // Create Symbol for section number.
318 const MCExpr *MCE = MCCOFFSectionNumberTargetExpr::create(
319 SectionSymbol: *Symbol, Writer: this->getWriter(), Ctx&: getContext());
320 ensureHeadroom(Headroom: 4);
321 addFixup(Value: MCE, Kind: FK_Data_4);
322 // Emit 4 bytes (zeros) to the object file.
323 appendContents(Num: 4, Elt: 0);
324}
325
326void MCWinCOFFStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
327 visitUsedSymbol(Sym: *Symbol);
328 // Create Symbol for section offset.
329 const MCExpr *MCE =
330 MCCOFFSectionOffsetTargetExpr::create(Symbol: *Symbol, Ctx&: getContext());
331 ensureHeadroom(Headroom: 4);
332 addFixup(Value: MCE, Kind: FK_Data_4);
333 // Emit 4 bytes (zeros) to the object file.
334 appendContents(Num: 4, Elt: 0);
335}
336
337void MCWinCOFFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
338 Align ByteAlignment) {
339 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
340
341 const Triple &T = getContext().getTargetTriple();
342 if (T.isWindowsMSVCEnvironment()) {
343 if (ByteAlignment > 32)
344 report_fatal_error(reason: "alignment is limited to 32-bytes");
345
346 // Round size up to alignment so that we will honor the alignment request.
347 Size = std::max(a: Size, b: ByteAlignment.value());
348 }
349
350 getAssembler().registerSymbol(Symbol: *Symbol);
351 Symbol->setExternal(true);
352 Symbol->setCommon(Size, Alignment: ByteAlignment);
353
354 if (!T.isWindowsMSVCEnvironment() && ByteAlignment > 1) {
355 SmallString<128> Directive;
356 raw_svector_ostream OS(Directive);
357 const MCObjectFileInfo *MFI = getContext().getObjectFileInfo();
358
359 OS << " -aligncomm:\"" << Symbol->getName() << "\","
360 << Log2_32_Ceil(Value: ByteAlignment.value());
361
362 pushSection();
363 switchSection(Section: MFI->getDrectveSection());
364 emitBytes(Data: Directive);
365 popSection();
366 }
367}
368
369void MCWinCOFFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
370 Align ByteAlignment) {
371 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
372
373 MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
374 pushSection();
375 switchSection(Section);
376 emitValueToAlignment(Alignment: ByteAlignment, Fill: 0, FillLen: 1, MaxBytesToEmit: 0);
377 emitLabel(S: Symbol);
378 Symbol->setExternal(false);
379 emitZeros(NumBytes: Size);
380 popSection();
381}
382
383// Hack: Used by llvm-ml to implement the alias directive.
384void MCWinCOFFStreamer::emitWeakReference(MCSymbol *AliasS,
385 const MCSymbol *Symbol) {
386 auto *Alias = static_cast<MCSymbolCOFF *>(AliasS);
387 emitSymbolAttribute(S: Alias, Attribute: MCSA_Weak);
388 Alias->setIsWeakExternal(true);
389
390 getAssembler().registerSymbol(Symbol: *Symbol);
391 Alias->setVariableValue(MCSymbolRefExpr::create(Symbol, Ctx&: getContext()));
392}
393
394// TODO: Implement this if you want to emit .comment section in COFF obj files.
395void MCWinCOFFStreamer::emitIdent(StringRef IdentString) {
396 llvm_unreachable("not implemented");
397}
398
399void MCWinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) {
400 llvm_unreachable("not implemented");
401}
402
403void MCWinCOFFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
404 const MCSymbolRefExpr *To,
405 uint64_t Count) {
406 // Ignore temporary symbols for now.
407 if (!From->getSymbol().isTemporary() && !To->getSymbol().isTemporary())
408 getWriter().getCGProfile().push_back(Elt: {.From: From, .To: To, .Count: Count});
409}
410
411void MCWinCOFFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) {
412 const MCSymbol *S = &SRE->getSymbol();
413 if (getAssembler().registerSymbol(Symbol: *S))
414 static_cast<const MCSymbolCOFF *>(S)->setExternal(true);
415}
416
417void MCWinCOFFStreamer::finishImpl() {
418 getContext().getCVContext().finish();
419 MCAssembler &Asm = getAssembler();
420 if (Asm.getWriter().getEmitAddrsigSection()) {
421 // Register the section.
422 switchSection(Section: Asm.getContext().getCOFFSection(Section: ".llvm_addrsig",
423 Characteristics: COFF::IMAGE_SCN_LNK_REMOVE));
424 }
425 if (!Asm.getWriter().getCGProfile().empty()) {
426 for (auto &E : Asm.getWriter().getCGProfile()) {
427 finalizeCGProfileEntry(SRE&: E.From);
428 finalizeCGProfileEntry(SRE&: E.To);
429 }
430 switchSection(Section: Asm.getContext().getCOFFSection(Section: ".llvm.call-graph-profile",
431 Characteristics: COFF::IMAGE_SCN_LNK_REMOVE));
432 }
433
434 MCObjectStreamer::finishImpl();
435}
436
437void MCWinCOFFStreamer::Error(const Twine &Msg) const {
438 getContext().reportError(L: SMLoc(), Msg);
439}
440