1320374Sdim//===- llvm/MC/MCWinCOFFStreamer.cpp --------------------------------------===//
2320374Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6320374Sdim//
7320374Sdim//===----------------------------------------------------------------------===//
8320374Sdim//
9320374Sdim// This file contains an implementation of a Windows COFF object file streamer.
10320374Sdim//
11320374Sdim//===----------------------------------------------------------------------===//
12320374Sdim
13320374Sdim#include "llvm/ADT/SmallString.h"
14320374Sdim#include "llvm/ADT/SmallVector.h"
15320374Sdim#include "llvm/ADT/Triple.h"
16320374Sdim#include "llvm/ADT/Twine.h"
17320374Sdim#include "llvm/BinaryFormat/COFF.h"
18320374Sdim#include "llvm/MC/MCAsmBackend.h"
19320374Sdim#include "llvm/MC/MCAssembler.h"
20320374Sdim#include "llvm/MC/MCCodeEmitter.h"
21320374Sdim#include "llvm/MC/MCContext.h"
22320374Sdim#include "llvm/MC/MCExpr.h"
23320374Sdim#include "llvm/MC/MCFixup.h"
24320374Sdim#include "llvm/MC/MCFragment.h"
25320374Sdim#include "llvm/MC/MCObjectFileInfo.h"
26320374Sdim#include "llvm/MC/MCObjectStreamer.h"
27341825Sdim#include "llvm/MC/MCObjectWriter.h"
28320374Sdim#include "llvm/MC/MCSection.h"
29320374Sdim#include "llvm/MC/MCSymbolCOFF.h"
30320374Sdim#include "llvm/MC/MCWinCOFFStreamer.h"
31320374Sdim#include "llvm/Support/Casting.h"
32320374Sdim#include "llvm/Support/ErrorHandling.h"
33320374Sdim#include "llvm/Support/MathExtras.h"
34320374Sdim#include "llvm/Support/SMLoc.h"
35320374Sdim#include "llvm/Support/raw_ostream.h"
36320374Sdim#include <algorithm>
37320374Sdim#include <cassert>
38320374Sdim#include <cstdint>
39320374Sdim
40320374Sdimusing namespace llvm;
41320374Sdim
42320374Sdim#define DEBUG_TYPE "WinCOFFStreamer"
43320374Sdim
44327952SdimMCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context,
45327952Sdim                                     std::unique_ptr<MCAsmBackend> MAB,
46327952Sdim                                     std::unique_ptr<MCCodeEmitter> CE,
47341825Sdim                                     std::unique_ptr<MCObjectWriter> OW)
48341825Sdim    : MCObjectStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)),
49327952Sdim      CurSymbol(nullptr) {}
50320374Sdim
51320374Sdimvoid MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst,
52320374Sdim                                       const MCSubtargetInfo &STI) {
53320374Sdim  MCDataFragment *DF = getOrCreateDataFragment();
54320374Sdim
55320374Sdim  SmallVector<MCFixup, 4> Fixups;
56320374Sdim  SmallString<256> Code;
57320374Sdim  raw_svector_ostream VecOS(Code);
58320374Sdim  getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
59320374Sdim
60320374Sdim  // Add the fixups and data.
61320374Sdim  for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
62320374Sdim    Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
63320374Sdim    DF->getFixups().push_back(Fixups[i]);
64320374Sdim  }
65341825Sdim  DF->setHasInstructions(STI);
66320374Sdim  DF->getContents().append(Code.begin(), Code.end());
67320374Sdim}
68320374Sdim
69320374Sdimvoid MCWinCOFFStreamer::InitSections(bool NoExecStack) {
70320374Sdim  // FIXME: this is identical to the ELF one.
71320374Sdim  // This emulates the same behavior of GNU as. This makes it easier
72320374Sdim  // to compare the output as the major sections are in the same order.
73320374Sdim  SwitchSection(getContext().getObjectFileInfo()->getTextSection());
74320374Sdim  EmitCodeAlignment(4);
75320374Sdim
76320374Sdim  SwitchSection(getContext().getObjectFileInfo()->getDataSection());
77320374Sdim  EmitCodeAlignment(4);
78320374Sdim
79320374Sdim  SwitchSection(getContext().getObjectFileInfo()->getBSSSection());
80320374Sdim  EmitCodeAlignment(4);
81320374Sdim
82320374Sdim  SwitchSection(getContext().getObjectFileInfo()->getTextSection());
83320374Sdim}
84320374Sdim
85320374Sdimvoid MCWinCOFFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc) {
86320374Sdim  auto *Symbol = cast<MCSymbolCOFF>(S);
87320374Sdim  MCObjectStreamer::EmitLabel(Symbol, Loc);
88320374Sdim}
89320374Sdim
90320374Sdimvoid MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
91360784Sdim  // Let the target do whatever target specific stuff it needs to do.
92360784Sdim  getAssembler().getBackend().handleAssemblerFlag(Flag);
93360784Sdim
94360784Sdim  switch (Flag) {
95360784Sdim  // None of these require COFF specific handling.
96360784Sdim  case MCAF_SyntaxUnified:
97360784Sdim  case MCAF_Code16:
98360784Sdim  case MCAF_Code32:
99360784Sdim  case MCAF_Code64:
100360784Sdim    break;
101360784Sdim  case MCAF_SubsectionsViaSymbols:
102360784Sdim    llvm_unreachable("COFF doesn't support .subsections_via_symbols");
103360784Sdim  }
104320374Sdim}
105320374Sdim
106320374Sdimvoid MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) {
107320374Sdim  llvm_unreachable("not implemented");
108320374Sdim}
109320374Sdim
110320374Sdimbool MCWinCOFFStreamer::EmitSymbolAttribute(MCSymbol *S,
111320374Sdim                                            MCSymbolAttr Attribute) {
112320374Sdim  auto *Symbol = cast<MCSymbolCOFF>(S);
113320374Sdim  getAssembler().registerSymbol(*Symbol);
114320374Sdim
115320374Sdim  switch (Attribute) {
116320374Sdim  default: return false;
117320374Sdim  case MCSA_WeakReference:
118320374Sdim  case MCSA_Weak:
119320374Sdim    Symbol->setIsWeakExternal();
120320374Sdim    Symbol->setExternal(true);
121320374Sdim    break;
122320374Sdim  case MCSA_Global:
123320374Sdim    Symbol->setExternal(true);
124320374Sdim    break;
125320374Sdim  case MCSA_AltEntry:
126320374Sdim    llvm_unreachable("COFF doesn't support the .alt_entry attribute");
127320374Sdim  }
128320374Sdim
129320374Sdim  return true;
130320374Sdim}
131320374Sdim
132320374Sdimvoid MCWinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
133320374Sdim  llvm_unreachable("not implemented");
134320374Sdim}
135320374Sdim
136320374Sdimvoid MCWinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *S) {
137320374Sdim  auto *Symbol = cast<MCSymbolCOFF>(S);
138320374Sdim  if (CurSymbol)
139320374Sdim    Error("starting a new symbol definition without completing the "
140320374Sdim          "previous one");
141320374Sdim  CurSymbol = Symbol;
142320374Sdim}
143320374Sdim
144320374Sdimvoid MCWinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {
145320374Sdim  if (!CurSymbol) {
146320374Sdim    Error("storage class specified outside of symbol definition");
147320374Sdim    return;
148320374Sdim  }
149320374Sdim
150320374Sdim  if (StorageClass & ~COFF::SSC_Invalid) {
151320374Sdim    Error("storage class value '" + Twine(StorageClass) +
152320374Sdim               "' out of range");
153320374Sdim    return;
154320374Sdim  }
155320374Sdim
156320374Sdim  getAssembler().registerSymbol(*CurSymbol);
157320374Sdim  cast<MCSymbolCOFF>(CurSymbol)->setClass((uint16_t)StorageClass);
158320374Sdim}
159320374Sdim
160320374Sdimvoid MCWinCOFFStreamer::EmitCOFFSymbolType(int Type) {
161320374Sdim  if (!CurSymbol) {
162320374Sdim    Error("symbol type specified outside of a symbol definition");
163320374Sdim    return;
164320374Sdim  }
165320374Sdim
166320374Sdim  if (Type & ~0xffff) {
167320374Sdim    Error("type value '" + Twine(Type) + "' out of range");
168320374Sdim    return;
169320374Sdim  }
170320374Sdim
171320374Sdim  getAssembler().registerSymbol(*CurSymbol);
172320374Sdim  cast<MCSymbolCOFF>(CurSymbol)->setType((uint16_t)Type);
173320374Sdim}
174320374Sdim
175320374Sdimvoid MCWinCOFFStreamer::EndCOFFSymbolDef() {
176320374Sdim  if (!CurSymbol)
177320374Sdim    Error("ending symbol definition without starting one");
178320374Sdim  CurSymbol = nullptr;
179320374Sdim}
180320374Sdim
181320374Sdimvoid MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) {
182320374Sdim  // SafeSEH is a feature specific to 32-bit x86.  It does not exist (and is
183320374Sdim  // unnecessary) on all platforms which use table-based exception dispatch.
184320374Sdim  if (getContext().getObjectFileInfo()->getTargetTriple().getArch() !=
185320374Sdim      Triple::x86)
186320374Sdim    return;
187320374Sdim
188320374Sdim  const MCSymbolCOFF *CSymbol = cast<MCSymbolCOFF>(Symbol);
189320374Sdim  if (CSymbol->isSafeSEH())
190320374Sdim    return;
191320374Sdim
192320374Sdim  MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection();
193320374Sdim  getAssembler().registerSection(*SXData);
194320374Sdim  if (SXData->getAlignment() < 4)
195360784Sdim    SXData->setAlignment(Align(4));
196320374Sdim
197327952Sdim  new MCSymbolIdFragment(Symbol, SXData);
198320374Sdim
199320374Sdim  getAssembler().registerSymbol(*Symbol);
200320374Sdim  CSymbol->setIsSafeSEH();
201320374Sdim
202320374Sdim  // The Microsoft linker requires that the symbol type of a handler be
203320374Sdim  // function. Go ahead and oblige it here.
204320374Sdim  CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION
205320374Sdim                   << COFF::SCT_COMPLEX_TYPE_SHIFT);
206320374Sdim}
207320374Sdim
208341825Sdimvoid MCWinCOFFStreamer::EmitCOFFSymbolIndex(MCSymbol const *Symbol) {
209341825Sdim  MCSection *Sec = getCurrentSectionOnly();
210341825Sdim  getAssembler().registerSection(*Sec);
211341825Sdim  if (Sec->getAlignment() < 4)
212360784Sdim    Sec->setAlignment(Align(4));
213341825Sdim
214341825Sdim  new MCSymbolIdFragment(Symbol, getCurrentSectionOnly());
215341825Sdim
216341825Sdim  getAssembler().registerSymbol(*Symbol);
217341825Sdim}
218341825Sdim
219320374Sdimvoid MCWinCOFFStreamer::EmitCOFFSectionIndex(const MCSymbol *Symbol) {
220320374Sdim  visitUsedSymbol(*Symbol);
221320374Sdim  MCDataFragment *DF = getOrCreateDataFragment();
222320374Sdim  const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
223320374Sdim  MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_2);
224320374Sdim  DF->getFixups().push_back(Fixup);
225320374Sdim  DF->getContents().resize(DF->getContents().size() + 2, 0);
226320374Sdim}
227320374Sdim
228320374Sdimvoid MCWinCOFFStreamer::EmitCOFFSecRel32(const MCSymbol *Symbol,
229320374Sdim                                         uint64_t Offset) {
230320374Sdim  visitUsedSymbol(*Symbol);
231320374Sdim  MCDataFragment *DF = getOrCreateDataFragment();
232320374Sdim  // Create Symbol A for the relocation relative reference.
233320374Sdim  const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, getContext());
234320374Sdim  // Add the constant offset, if given.
235320374Sdim  if (Offset)
236320374Sdim    MCE = MCBinaryExpr::createAdd(
237320374Sdim        MCE, MCConstantExpr::create(Offset, getContext()), getContext());
238320374Sdim  // Build the secrel32 relocation.
239320374Sdim  MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_SecRel_4);
240320374Sdim  // Record the relocation.
241320374Sdim  DF->getFixups().push_back(Fixup);
242320374Sdim  // Emit 4 bytes (zeros) to the object file.
243320374Sdim  DF->getContents().resize(DF->getContents().size() + 4, 0);
244320374Sdim}
245320374Sdim
246341825Sdimvoid MCWinCOFFStreamer::EmitCOFFImgRel32(const MCSymbol *Symbol,
247341825Sdim                                         int64_t Offset) {
248341825Sdim  visitUsedSymbol(*Symbol);
249341825Sdim  MCDataFragment *DF = getOrCreateDataFragment();
250341825Sdim  // Create Symbol A for the relocation relative reference.
251341825Sdim  const MCExpr *MCE = MCSymbolRefExpr::create(
252341825Sdim      Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32, getContext());
253341825Sdim  // Add the constant offset, if given.
254341825Sdim  if (Offset)
255341825Sdim    MCE = MCBinaryExpr::createAdd(
256341825Sdim        MCE, MCConstantExpr::create(Offset, getContext()), getContext());
257341825Sdim  // Build the imgrel relocation.
258341825Sdim  MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_Data_4);
259341825Sdim  // Record the relocation.
260341825Sdim  DF->getFixups().push_back(Fixup);
261341825Sdim  // Emit 4 bytes (zeros) to the object file.
262341825Sdim  DF->getContents().resize(DF->getContents().size() + 4, 0);
263341825Sdim}
264341825Sdim
265320374Sdimvoid MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size,
266320374Sdim                                         unsigned ByteAlignment) {
267320374Sdim  auto *Symbol = cast<MCSymbolCOFF>(S);
268320374Sdim
269320374Sdim  const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
270353358Sdim  if (T.isWindowsMSVCEnvironment()) {
271320374Sdim    if (ByteAlignment > 32)
272320374Sdim      report_fatal_error("alignment is limited to 32-bytes");
273320374Sdim
274320374Sdim    // Round size up to alignment so that we will honor the alignment request.
275320374Sdim    Size = std::max(Size, static_cast<uint64_t>(ByteAlignment));
276320374Sdim  }
277320374Sdim
278320374Sdim  getAssembler().registerSymbol(*Symbol);
279320374Sdim  Symbol->setExternal(true);
280320374Sdim  Symbol->setCommon(Size, ByteAlignment);
281320374Sdim
282353358Sdim  if (!T.isWindowsMSVCEnvironment() && ByteAlignment > 1) {
283320374Sdim    SmallString<128> Directive;
284320374Sdim    raw_svector_ostream OS(Directive);
285320374Sdim    const MCObjectFileInfo *MFI = getContext().getObjectFileInfo();
286320374Sdim
287320374Sdim    OS << " -aligncomm:\"" << Symbol->getName() << "\","
288320374Sdim       << Log2_32_Ceil(ByteAlignment);
289320374Sdim
290320374Sdim    PushSection();
291320374Sdim    SwitchSection(MFI->getDrectveSection());
292320374Sdim    EmitBytes(Directive);
293320374Sdim    PopSection();
294320374Sdim  }
295320374Sdim}
296320374Sdim
297320374Sdimvoid MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
298320374Sdim                                              unsigned ByteAlignment) {
299320374Sdim  auto *Symbol = cast<MCSymbolCOFF>(S);
300320374Sdim
301320374Sdim  MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
302328595Semaste  PushSection();
303328595Semaste  SwitchSection(Section);
304328595Semaste  EmitValueToAlignment(ByteAlignment, 0, 1, 0);
305328595Semaste  EmitLabel(Symbol);
306320374Sdim  Symbol->setExternal(false);
307328595Semaste  EmitZeros(Size);
308328595Semaste  PopSection();
309320374Sdim}
310320374Sdim
311320374Sdimvoid MCWinCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
312341825Sdim                                     uint64_t Size, unsigned ByteAlignment,
313341825Sdim                                     SMLoc Loc) {
314320374Sdim  llvm_unreachable("not implemented");
315320374Sdim}
316320374Sdim
317320374Sdimvoid MCWinCOFFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
318320374Sdim                                       uint64_t Size, unsigned ByteAlignment) {
319320374Sdim  llvm_unreachable("not implemented");
320320374Sdim}
321320374Sdim
322320374Sdim// TODO: Implement this if you want to emit .comment section in COFF obj files.
323320374Sdimvoid MCWinCOFFStreamer::EmitIdent(StringRef IdentString) {
324320374Sdim  llvm_unreachable("not implemented");
325320374Sdim}
326320374Sdim
327327952Sdimvoid MCWinCOFFStreamer::EmitWinEHHandlerData(SMLoc Loc) {
328320374Sdim  llvm_unreachable("not implemented");
329320374Sdim}
330320374Sdim
331320374Sdimvoid MCWinCOFFStreamer::FinishImpl() {
332320374Sdim  MCObjectStreamer::FinishImpl();
333320374Sdim}
334320374Sdim
335320374Sdimvoid MCWinCOFFStreamer::Error(const Twine &Msg) const {
336320374Sdim  getContext().reportError(SMLoc(), Msg);
337320374Sdim}
338