442 lines · cpp
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-exception6//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 contains46/// 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(SectionSymbol.getSection());70 assert(sectionNumber != 0 &&71 "Containing section was not assigned a number");72 Res = MCValue::get(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 its86/// 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(Symbol, CallsiteOffset)) {107 return true;108 }109 Res = MCValue::get(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 easier141 // to compare the output as the major sections are in the same order.142 switchSection(getContext().getObjectFileInfo()->getTextSection());143 emitCodeAlignment(Align(4), &STI);144 145 switchSection(getContext().getObjectFileInfo()->getDataSection());146 emitCodeAlignment(Align(4), &STI);147 148 switchSection(getContext().getObjectFileInfo()->getBSSSection());149 emitCodeAlignment(Align(4), &STI);150 151 switchSection(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 are157 // the section symbol and the COMDAT symbol.158 getAssembler().registerSymbol(*Section->getBeginSymbol());159 if (auto *Sym =160 static_cast<const MCSectionCOFF *>(Section)->getCOMDATSymbol())161 getAssembler().registerSymbol(*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);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("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("storage class specified outside of symbol definition");210 return;211 }212 213 if (StorageClass & ~COFF::SSC_Invalid) {214 Error("storage class value '" + Twine(StorageClass) +215 "' out of range");216 return;217 }218 219 getAssembler().registerSymbol(*CurSymbol);220 static_cast<MCSymbolCOFF *>(CurSymbol)->setClass((uint16_t)StorageClass);221}222 223void MCWinCOFFStreamer::emitCOFFSymbolType(int Type) {224 if (!CurSymbol) {225 Error("symbol type specified outside of a symbol definition");226 return;227 }228 229 if (Type & ~0xffff) {230 Error("type value '" + Twine(Type) + "' out of range");231 return;232 }233 234 getAssembler().registerSymbol(*CurSymbol);235 static_cast<const MCSymbolCOFF *>(CurSymbol)->setType((uint16_t)Type);236}237 238void MCWinCOFFStreamer::endCOFFSymbolDef() {239 if (!CurSymbol)240 Error("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 is246 // 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(SXData);257 SXData->ensureMinAlignment(Align(4));258 259 newSpecialFragment<MCSymbolIdFragment>(Symbol);260 getAssembler().registerSymbol(*Symbol);261 CSymbol->setIsSafeSEH();262 263 // The Microsoft linker requires that the symbol type of a handler be264 // function. Go ahead and oblige it here.265 CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION266 << COFF::SCT_COMPLEX_TYPE_SHIFT);267 popSection();268}269 270void MCWinCOFFStreamer::emitCOFFSymbolIndex(MCSymbol const *Symbol) {271 MCSection *Sec = getCurrentSectionOnly();272 Sec->ensureMinAlignment(Align(4));273 274 newSpecialFragment<MCSymbolIdFragment>(Symbol);275 getAssembler().registerSymbol(*Symbol);276}277 278void MCWinCOFFStreamer::emitCOFFSectionIndex(const MCSymbol *Symbol) {279 visitUsedSymbol(*Symbol);280 const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());281 ensureHeadroom(2);282 addFixup(SRE, FK_SecRel_2);283 appendContents(2, 0);284}285 286void MCWinCOFFStreamer::emitCOFFSecRel32(const MCSymbol *Symbol,287 uint64_t Offset) {288 visitUsedSymbol(*Symbol);289 // Create Symbol A for the relocation relative reference.290 const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, getContext());291 // Add the constant offset, if given.292 if (Offset)293 MCE = MCBinaryExpr::createAdd(294 MCE, MCConstantExpr::create(Offset, getContext()), getContext());295 ensureHeadroom(4);296 addFixup(MCE, FK_SecRel_4);297 // Emit 4 bytes (zeros) to the object file.298 appendContents(4, 0);299}300 301void MCWinCOFFStreamer::emitCOFFImgRel32(const MCSymbol *Symbol,302 int64_t Offset) {303 visitUsedSymbol(*Symbol);304 // Create Symbol A for the relocation relative reference.305 const MCExpr *MCE = MCSymbolRefExpr::create(306 Symbol, MCSymbolRefExpr::VK_COFF_IMGREL32, getContext());307 // Add the constant offset, if given.308 if (Offset)309 MCE = MCBinaryExpr::createAdd(310 MCE, MCConstantExpr::create(Offset, getContext()), getContext());311 ensureHeadroom(4);312 addFixup(MCE, FK_Data_4);313 // Emit 4 bytes (zeros) to the object file.314 appendContents(4, 0);315}316 317void MCWinCOFFStreamer::emitCOFFSecNumber(MCSymbol const *Symbol) {318 visitUsedSymbol(*Symbol);319 // Create Symbol for section number.320 const MCExpr *MCE = MCCOFFSectionNumberTargetExpr::create(321 *Symbol, this->getWriter(), getContext());322 ensureHeadroom(4);323 addFixup(MCE, FK_Data_4);324 // Emit 4 bytes (zeros) to the object file.325 appendContents(4, 0);326}327 328void MCWinCOFFStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {329 visitUsedSymbol(*Symbol);330 // Create Symbol for section offset.331 const MCExpr *MCE =332 MCCOFFSectionOffsetTargetExpr::create(*Symbol, getContext());333 ensureHeadroom(4);334 addFixup(MCE, FK_Data_4);335 // Emit 4 bytes (zeros) to the object file.336 appendContents(4, 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("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(Size, ByteAlignment.value());350 }351 352 getAssembler().registerSymbol(*Symbol);353 Symbol->setExternal(true);354 Symbol->setCommon(Size, 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(ByteAlignment.value());363 364 pushSection();365 switchSection(MFI->getDrectveSection());366 emitBytes(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(ByteAlignment, 0, 1, 0);379 emitLabel(Symbol);380 Symbol->setExternal(false);381 emitZeros(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(Alias, MCSA_Weak);390 Alias->setIsWeakExternal(true);391 392 getAssembler().registerSymbol(*Symbol);393 Alias->setVariableValue(MCSymbolRefExpr::create(Symbol, 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({From, To, Count});411}412 413void MCWinCOFFStreamer::finalizeCGProfileEntry(const MCSymbolRefExpr *&SRE) {414 const MCSymbol *S = &SRE->getSymbol();415 if (getAssembler().registerSymbol(*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(Asm.getContext().getCOFFSection(".llvm_addrsig",425 COFF::IMAGE_SCN_LNK_REMOVE));426 }427 if (!Asm.getWriter().getCGProfile().empty()) {428 for (auto &E : Asm.getWriter().getCGProfile()) {429 finalizeCGProfileEntry(E.From);430 finalizeCGProfileEntry(E.To);431 }432 switchSection(Asm.getContext().getCOFFSection(".llvm.call-graph-profile",433 COFF::IMAGE_SCN_LNK_REMOVE));434 }435 436 MCObjectStreamer::finishImpl();437}438 439void MCWinCOFFStreamer::Error(const Twine &Msg) const {440 getContext().reportError(SMLoc(), Msg);441}442