brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.7 KiB · 2e632de Raw
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