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