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