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