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 auto *TO = Context.getTargetOptions();
129 if (TO && TO->MCIncrementalLinkerCompatible)
130 getWriter().setIncrementalLinkerCompatible(true);
131}
132
133WinCOFFObjectWriter &MCWinCOFFStreamer::getWriter() {
134 return static_cast<WinCOFFObjectWriter &>(getAssembler().getWriter());
135}
136
137void MCWinCOFFStreamer::initSections(const MCSubtargetInfo &STI) {
138 // FIXME: this is identical to the ELF one.
139 // This emulates the same behavior of GNU as. This makes it easier
140 // to compare the output as the major sections are in the same order.
141 switchSection(Section: getContext().getObjectFileInfo()->getTextSection());
142 emitCodeAlignment(ByteAlignment: Align(4), STI: &STI);
143
144 switchSection(Section: getContext().getObjectFileInfo()->getDataSection());
145 emitCodeAlignment(ByteAlignment: Align(4), STI: &STI);
146
147 switchSection(Section: getContext().getObjectFileInfo()->getBSSSection());
148 emitCodeAlignment(ByteAlignment: Align(4), STI: &STI);
149
150 switchSection(Section: getContext().getObjectFileInfo()->getTextSection());
151}
152
153void MCWinCOFFStreamer::changeSection(MCSection *Section, uint32_t Subsection) {
154 MCObjectStreamer::changeSection(Section, Subsection);
155 // Ensure that the first and the second symbols relative to the section are
156 // the section symbol and the COMDAT symbol.
157 getAssembler().registerSymbol(Symbol: *Section->getBeginSymbol());
158 if (auto *Sym =
159 static_cast<const MCSectionCOFF *>(Section)->getCOMDATSymbol())
160 getAssembler().registerSymbol(Symbol: *Sym);
161}
162
163void MCWinCOFFStreamer::emitLabel(MCSymbol *S, SMLoc Loc) {
164 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
165 MCObjectStreamer::emitLabel(Symbol, Loc);
166}
167
168bool MCWinCOFFStreamer::emitSymbolAttribute(MCSymbol *S,
169 MCSymbolAttr Attribute) {
170 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
171 getAssembler().registerSymbol(Symbol: *Symbol);
172
173 switch (Attribute) {
174 default: return false;
175 case MCSA_WeakReference:
176 case MCSA_Weak:
177 Symbol->setWeakExternalCharacteristics(COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS);
178 Symbol->setExternal(true);
179 break;
180 case MCSA_WeakAntiDep:
181 Symbol->setWeakExternalCharacteristics(COFF::IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY);
182 Symbol->setExternal(true);
183 Symbol->setIsWeakExternal(true);
184 break;
185 case MCSA_Global:
186 Symbol->setExternal(true);
187 break;
188 case MCSA_AltEntry:
189 llvm_unreachable("COFF doesn't support the .alt_entry attribute");
190 }
191
192 return true;
193}
194
195void MCWinCOFFStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
196 llvm_unreachable("not implemented");
197}
198
199void MCWinCOFFStreamer::beginCOFFSymbolDef(MCSymbol const *S) {
200 if (CurSymbol)
201 Error(Msg: "starting a new symbol definition without completing the "
202 "previous one");
203 CurSymbol = static_cast<MCSymbolCOFF *>(const_cast<MCSymbol *>(S));
204}
205
206void MCWinCOFFStreamer::emitCOFFSymbolStorageClass(int StorageClass) {
207 if (!CurSymbol) {
208 Error(Msg: "storage class specified outside of symbol definition");
209 return;
210 }
211
212 if (StorageClass & ~COFF::SSC_Invalid) {
213 Error(Msg: "storage class value '" + Twine(StorageClass) +
214 "' out of range");
215 return;
216 }
217
218 getAssembler().registerSymbol(Symbol: *CurSymbol);
219 static_cast<MCSymbolCOFF *>(CurSymbol)->setClass((uint16_t)StorageClass);
220}
221
222void MCWinCOFFStreamer::emitCOFFSymbolType(int Type) {
223 if (!CurSymbol) {
224 Error(Msg: "symbol type specified outside of a symbol definition");
225 return;
226 }
227
228 if (Type & ~0xffff) {
229 Error(Msg: "type value '" + Twine(Type) + "' out of range");
230 return;
231 }
232
233 getAssembler().registerSymbol(Symbol: *CurSymbol);
234 static_cast<const MCSymbolCOFF *>(CurSymbol)->setType((uint16_t)Type);
235}
236
237void MCWinCOFFStreamer::endCOFFSymbolDef() {
238 if (!CurSymbol)
239 Error(Msg: "ending symbol definition without starting one");
240 CurSymbol = nullptr;
241}
242
243void MCWinCOFFStreamer::emitCOFFSafeSEH(MCSymbol const *Symbol) {
244 // SafeSEH is a feature specific to 32-bit x86. It does not exist (and is
245 // unnecessary) on all platforms which use table-based exception dispatch.
246 if (getContext().getTargetTriple().getArch() != Triple::x86)
247 return;
248
249 auto *CSymbol = static_cast<const MCSymbolCOFF *>(Symbol);
250 if (CSymbol->isSafeSEH())
251 return;
252
253 MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection();
254 pushSection();
255 switchSection(Section: SXData);
256 SXData->ensureMinAlignment(MinAlignment: Align(4));
257
258 newSpecialFragment<MCSymbolIdFragment>(args&: Symbol);
259 getAssembler().registerSymbol(Symbol: *Symbol);
260 CSymbol->setIsSafeSEH();
261
262 // The Microsoft linker requires that the symbol type of a handler be
263 // function. Go ahead and oblige it here.
264 CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION
265 << COFF::SCT_COMPLEX_TYPE_SHIFT);
266 popSection();
267}
268
269void MCWinCOFFStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {
270 MCSection *Sec = getCurrentSectionOnly();
271 Sec->ensureMinAlignment(MinAlignment: Align(4));
272
273 newSpecialFragment<MCSymbolIdFragment>(args&: Symbol);
274 getAssembler().registerSymbol(Symbol: *Symbol);
275}
276
277void MCWinCOFFStreamer::emitCOFFSectionIndex(const MCSymbol *Symbol) {
278 visitUsedSymbol(Sym: *Symbol);
279 const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, Ctx&: getContext());
280 ensureHeadroom(Headroom: 2);
281 addFixup(Value: SRE, Kind: FK_SecRel_2);
282 appendContents(Num: 2, Elt: 0);
283}
284
285void MCWinCOFFStreamer::emitCOFFSecRel32(const MCSymbol *Symbol,
286 uint64_t Offset) {
287 visitUsedSymbol(Sym: *Symbol);
288 // Create Symbol A for the relocation relative reference.
289 const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, Ctx&: getContext());
290 // Add the constant offset, if given.
291 if (Offset)
292 MCE = MCBinaryExpr::createAdd(
293 LHS: MCE, RHS: MCConstantExpr::create(Value: Offset, Ctx&: getContext()), Ctx&: getContext());
294 ensureHeadroom(Headroom: 4);
295 addFixup(Value: MCE, Kind: FK_SecRel_4);
296 // Emit 4 bytes (zeros) to the object file.
297 appendContents(Num: 4, Elt: 0);
298}
299
300void MCWinCOFFStreamer::emitCOFFImgRel32(const MCSymbol *Symbol,
301 int64_t Offset) {
302 visitUsedSymbol(Sym: *Symbol);
303 // Create Symbol A for the relocation relative reference.
304 const MCExpr *MCE = MCSymbolRefExpr::create(
305 Symbol, specifier: MCSymbolRefExpr::VK_COFF_IMGREL32, Ctx&: getContext());
306 // Add the constant offset, if given.
307 if (Offset)
308 MCE = MCBinaryExpr::createAdd(
309 LHS: MCE, RHS: MCConstantExpr::create(Value: Offset, Ctx&: getContext()), Ctx&: getContext());
310 ensureHeadroom(Headroom: 4);
311 addFixup(Value: MCE, Kind: FK_Data_4);
312 // Emit 4 bytes (zeros) to the object file.
313 appendContents(Num: 4, Elt: 0);
314}
315
316void MCWinCOFFStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {
317 visitUsedSymbol(Sym: *Symbol);
318 // Create Symbol for section number.
319 const MCExpr *MCE = MCCOFFSectionNumberTargetExpr::create(
320 SectionSymbol: *Symbol, Writer: this->getWriter(), Ctx&: getContext());
321 ensureHeadroom(Headroom: 4);
322 addFixup(Value: MCE, Kind: FK_Data_4);
323 // Emit 4 bytes (zeros) to the object file.
324 appendContents(Num: 4, Elt: 0);
325}
326
327void MCWinCOFFStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
328 visitUsedSymbol(Sym: *Symbol);
329 // Create Symbol for section offset.
330 const MCExpr *MCE =
331 MCCOFFSectionOffsetTargetExpr::create(Symbol: *Symbol, Ctx&: getContext());
332 ensureHeadroom(Headroom: 4);
333 addFixup(Value: MCE, Kind: FK_Data_4);
334 // Emit 4 bytes (zeros) to the object file.
335 appendContents(Num: 4, Elt: 0);
336}
337
338void MCWinCOFFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
339 Align ByteAlignment) {
340 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
341
342 const Triple &T = getContext().getTargetTriple();
343 if (T.isWindowsMSVCEnvironment()) {
344 if (ByteAlignment > 32)
345 report_fatal_error(reason: "alignment is limited to 32-bytes");
346
347 // Round size up to alignment so that we will honor the alignment request.
348 Size = std::max(a: Size, b: ByteAlignment.value());
349 }
350
351 getAssembler().registerSymbol(Symbol: *Symbol);
352 Symbol->setExternal(true);
353 Symbol->setCommon(Size, Alignment: ByteAlignment);
354
355 if (!T.isWindowsMSVCEnvironment() && ByteAlignment > 1) {
356 SmallString<128> Directive;
357 raw_svector_ostream OS(Directive);
358 const MCObjectFileInfo *MFI = getContext().getObjectFileInfo();
359
360 OS << " -aligncomm:\"" << Symbol->getName() << "\","
361 << Log2_32_Ceil(Value: ByteAlignment.value());
362
363 pushSection();
364 switchSection(Section: MFI->getDrectveSection());
365 emitBytes(Data: Directive);
366 popSection();
367 }
368}
369
370void MCWinCOFFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
371 Align ByteAlignment) {
372 auto *Symbol = static_cast<MCSymbolCOFF *>(S);
373
374 MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
375 pushSection();
376 switchSection(Section);
377 emitValueToAlignment(Alignment: ByteAlignment, Fill: 0, FillLen: 1, MaxBytesToEmit: 0);
378 emitLabel(S: Symbol);
379 Symbol->setExternal(false);
380 emitZeros(NumBytes: Size);
381 popSection();
382}
383
384// Hack: Used by llvm-ml to implement the alias directive.
385void MCWinCOFFStreamer::emitWeakReference(MCSymbol *AliasS,
386 const MCSymbol *Symbol) {
387 auto *Alias = static_cast<MCSymbolCOFF *>(AliasS);
388 emitSymbolAttribute(S: Alias, Attribute: MCSA_Weak);
389 Alias->setIsWeakExternal(true);
390
391 getAssembler().registerSymbol(Symbol: *Symbol);
392 Alias->setVariableValue(MCSymbolRefExpr::create(Symbol, Ctx&: getContext()));
393}
394
395// TODO: Implement this if you want to emit .comment section in COFF obj files.
396void MCWinCOFFStreamer::emitIdent(StringRef IdentString) {
397 llvm_unreachable("not implemented");
398}
399
400void MCWinCOFFStreamer::emitWinEHHandlerData(SMLoc Loc) {
401 llvm_unreachable("not implemented");
402}
403
404void MCWinCOFFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
405 const MCSymbolRefExpr *To,
406 uint64_t Count) {
407 // Ignore temporary symbols for now.
408 if (!From->getSymbol().isTemporary() && !To->getSymbol().isTemporary())
409 getWriter().getCGProfile().push_back(Elt: {.From: From, .To: To, .Count: Count});
410}
411
412void MCWinCOFFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) {
413 const MCSymbol *S = &SRE->getSymbol();
414 if (getAssembler().registerSymbol(Symbol: *S))
415 static_cast<const MCSymbolCOFF *>(S)->setExternal(true);
416}
417
418void MCWinCOFFStreamer::finishImpl() {
419 getContext().getCVContext().finish();
420 MCAssembler &Asm = getAssembler();
421 if (Asm.getWriter().getEmitAddrsigSection()) {
422 // Register the section.
423 switchSection(Section: Asm.getContext().getCOFFSection(Section: ".llvm_addrsig",
424 Characteristics: COFF::IMAGE_SCN_LNK_REMOVE));
425 }
426 if (!Asm.getWriter().getCGProfile().empty()) {
427 for (auto &E : Asm.getWriter().getCGProfile()) {
428 finalizeCGProfileEntry(SRE&: E.From);
429 finalizeCGProfileEntry(SRE&: E.To);
430 }
431 switchSection(Section: Asm.getContext().getCOFFSection(Section: ".llvm.call-graph-profile",
432 Characteristics: COFF::IMAGE_SCN_LNK_REMOVE));
433 }
434
435 MCObjectStreamer::finishImpl();
436}
437
438void MCWinCOFFStreamer::Error(const Twine &Msg) const {
439 getContext().reportError(L: SMLoc(), Msg);
440}
441