Home | History | Annotate | Download | only in MC
      1 //===-- llvm/MC/WinCOFFStreamer.cpp -----------------------------*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 // This file contains an implementation of a Windows COFF object file streamer.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "llvm/MC/MCAsmBackend.h"
     15 #include "llvm/MC/MCAsmLayout.h"
     16 #include "llvm/MC/MCAssembler.h"
     17 #include "llvm/MC/MCCodeEmitter.h"
     18 #include "llvm/MC/MCContext.h"
     19 #include "llvm/MC/MCExpr.h"
     20 #include "llvm/MC/MCObjectFileInfo.h"
     21 #include "llvm/MC/MCObjectStreamer.h"
     22 #include "llvm/MC/MCSection.h"
     23 #include "llvm/MC/MCSectionCOFF.h"
     24 #include "llvm/MC/MCStreamer.h"
     25 #include "llvm/MC/MCSymbolCOFF.h"
     26 #include "llvm/MC/MCValue.h"
     27 #include "llvm/MC/MCWinCOFFStreamer.h"
     28 #include "llvm/Support/COFF.h"
     29 #include "llvm/Support/Debug.h"
     30 #include "llvm/Support/ErrorHandling.h"
     31 #include "llvm/Support/MathExtras.h"
     32 #include "llvm/Support/TargetRegistry.h"
     33 #include "llvm/Support/raw_ostream.h"
     34 
     35 using namespace llvm;
     36 
     37 #define DEBUG_TYPE "WinCOFFStreamer"
     38 
     39 namespace llvm {
     40 MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB,
     41                                      MCCodeEmitter &CE, raw_pwrite_stream &OS)
     42     : MCObjectStreamer(Context, MAB, OS, &CE), CurSymbol(nullptr) {}
     43 
     44 void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst,
     45                                        const MCSubtargetInfo &STI) {
     46   MCDataFragment *DF = getOrCreateDataFragment();
     47 
     48   SmallVector<MCFixup, 4> Fixups;
     49   SmallString<256> Code;
     50   raw_svector_ostream VecOS(Code);
     51   getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI);
     52 
     53   // Add the fixups and data.
     54   for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
     55     Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
     56     DF->getFixups().push_back(Fixups[i]);
     57   }
     58 
     59   DF->getContents().append(Code.begin(), Code.end());
     60 }
     61 
     62 void MCWinCOFFStreamer::InitSections(bool NoExecStack) {
     63   // FIXME: this is identical to the ELF one.
     64   // This emulates the same behavior of GNU as. This makes it easier
     65   // to compare the output as the major sections are in the same order.
     66   SwitchSection(getContext().getObjectFileInfo()->getTextSection());
     67   EmitCodeAlignment(4);
     68 
     69   SwitchSection(getContext().getObjectFileInfo()->getDataSection());
     70   EmitCodeAlignment(4);
     71 
     72   SwitchSection(getContext().getObjectFileInfo()->getBSSSection());
     73   EmitCodeAlignment(4);
     74 
     75   SwitchSection(getContext().getObjectFileInfo()->getTextSection());
     76 }
     77 
     78 void MCWinCOFFStreamer::EmitLabel(MCSymbol *S) {
     79   auto *Symbol = cast<MCSymbolCOFF>(S);
     80   assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
     81   MCObjectStreamer::EmitLabel(Symbol);
     82 }
     83 
     84 void MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
     85   llvm_unreachable("not implemented");
     86 }
     87 
     88 void MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) {
     89   llvm_unreachable("not implemented");
     90 }
     91 
     92 bool MCWinCOFFStreamer::EmitSymbolAttribute(MCSymbol *S,
     93                                             MCSymbolAttr Attribute) {
     94   auto *Symbol = cast<MCSymbolCOFF>(S);
     95   getAssembler().registerSymbol(*Symbol);
     96 
     97   switch (Attribute) {
     98   default: return false;
     99   case MCSA_WeakReference:
    100   case MCSA_Weak:
    101     Symbol->setIsWeakExternal();
    102     Symbol->setExternal(true);
    103     break;
    104   case MCSA_Global:
    105     Symbol->setExternal(true);
    106     break;
    107   case MCSA_AltEntry:
    108     llvm_unreachable("COFF doesn't support the .alt_entry attribute");
    109   }
    110 
    111   return true;
    112 }
    113 
    114 void MCWinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
    115   llvm_unreachable("not implemented");
    116 }
    117 
    118 void MCWinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *S) {
    119   auto *Symbol = cast<MCSymbolCOFF>(S);
    120   if (CurSymbol)
    121     Error("starting a new symbol definition without completing the "
    122           "previous one");
    123   CurSymbol = Symbol;
    124 }
    125 
    126 void MCWinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {
    127   if (!CurSymbol) {
    128     Error("storage class specified outside of symbol definition");
    129     return;
    130   }
    131 
    132   if (StorageClass & ~COFF::SSC_Invalid) {
    133     Error("storage class value '" + Twine(StorageClass) +
    134                "' out of range");
    135     return;
    136   }
    137 
    138   getAssembler().registerSymbol(*CurSymbol);
    139   cast<MCSymbolCOFF>(CurSymbol)->setClass((uint16_t)StorageClass);
    140 }
    141 
    142 void MCWinCOFFStreamer::EmitCOFFSymbolType(int Type) {
    143   if (!CurSymbol) {
    144     Error("symbol type specified outside of a symbol definition");
    145     return;
    146   }
    147 
    148   if (Type & ~0xffff) {
    149     Error("type value '" + Twine(Type) + "' out of range");
    150     return;
    151   }
    152 
    153   getAssembler().registerSymbol(*CurSymbol);
    154   cast<MCSymbolCOFF>(CurSymbol)->setType((uint16_t)Type);
    155 }
    156 
    157 void MCWinCOFFStreamer::EndCOFFSymbolDef() {
    158   if (!CurSymbol)
    159     Error("ending symbol definition without starting one");
    160   CurSymbol = nullptr;
    161 }
    162 
    163 void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) {
    164   // SafeSEH is a feature specific to 32-bit x86.  It does not exist (and is
    165   // unnecessary) on all platforms which use table-based exception dispatch.
    166   if (getContext().getObjectFileInfo()->getTargetTriple().getArch() !=
    167       Triple::x86)
    168     return;
    169 
    170   const MCSymbolCOFF *CSymbol = cast<MCSymbolCOFF>(Symbol);
    171   if (CSymbol->isSafeSEH())
    172     return;
    173 
    174   MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection();
    175   getAssembler().registerSection(*SXData);
    176   if (SXData->getAlignment() < 4)
    177     SXData->setAlignment(4);
    178 
    179   new MCSafeSEHFragment(Symbol, SXData);
    180 
    181   getAssembler().registerSymbol(*Symbol);
    182   CSymbol->setIsSafeSEH();
    183 
    184   // The Microsoft linker requires that the symbol type of a handler be
    185   // function. Go ahead and oblige it here.
    186   CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION
    187                    << COFF::SCT_COMPLEX_TYPE_SHIFT);
    188 }
    189 
    190 void MCWinCOFFStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {
    191   MCDataFragment *DF = getOrCreateDataFragment();
    192   const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
    193   MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_2);
    194   DF->getFixups().push_back(Fixup);
    195   DF->getContents().resize(DF->getContents().size() + 2, 0);
    196 }
    197 
    198 void MCWinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) {
    199   MCDataFragment *DF = getOrCreateDataFragment();
    200   const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext());
    201   MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_4);
    202   DF->getFixups().push_back(Fixup);
    203   DF->getContents().resize(DF->getContents().size() + 4, 0);
    204 }
    205 
    206 void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size,
    207                                          unsigned ByteAlignment) {
    208   auto *Symbol = cast<MCSymbolCOFF>(S);
    209 
    210   const Triple &T = getContext().getObjectFileInfo()->getTargetTriple();
    211   if (T.isKnownWindowsMSVCEnvironment()) {
    212     if (ByteAlignment > 32)
    213       report_fatal_error("alignment is limited to 32-bytes");
    214 
    215     // Round size up to alignment so that we will honor the alignment request.
    216     Size = std::max(Size, static_cast<uint64_t>(ByteAlignment));
    217   }
    218 
    219   getAssembler().registerSymbol(*Symbol);
    220   Symbol->setExternal(true);
    221   Symbol->setCommon(Size, ByteAlignment);
    222 
    223   if (!T.isKnownWindowsMSVCEnvironment() && ByteAlignment > 1) {
    224     SmallString<128> Directive;
    225     raw_svector_ostream OS(Directive);
    226     const MCObjectFileInfo *MFI = getContext().getObjectFileInfo();
    227 
    228     OS << " -aligncomm:\"" << Symbol->getName() << "\","
    229        << Log2_32_Ceil(ByteAlignment);
    230 
    231     PushSection();
    232     SwitchSection(MFI->getDrectveSection());
    233     EmitBytes(Directive);
    234     PopSection();
    235   }
    236 }
    237 
    238 void MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
    239                                               unsigned ByteAlignment) {
    240   auto *Symbol = cast<MCSymbolCOFF>(S);
    241 
    242   MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
    243   getAssembler().registerSection(*Section);
    244   if (Section->getAlignment() < ByteAlignment)
    245     Section->setAlignment(ByteAlignment);
    246 
    247   getAssembler().registerSymbol(*Symbol);
    248   Symbol->setExternal(false);
    249 
    250   if (ByteAlignment != 1)
    251     new MCAlignFragment(ByteAlignment, /*Value=*/0, /*ValueSize=*/0,
    252                         ByteAlignment, Section);
    253 
    254   MCFillFragment *Fragment = new MCFillFragment(
    255       /*Value=*/0, Size, Section);
    256   Symbol->setFragment(Fragment);
    257 }
    258 
    259 void MCWinCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol,
    260                                      uint64_t Size, unsigned ByteAlignment) {
    261   llvm_unreachable("not implemented");
    262 }
    263 
    264 void MCWinCOFFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
    265                                        uint64_t Size, unsigned ByteAlignment) {
    266   llvm_unreachable("not implemented");
    267 }
    268 
    269 void MCWinCOFFStreamer::EmitFileDirective(StringRef Filename) {
    270   getAssembler().addFileName(Filename);
    271 }
    272 
    273 // TODO: Implement this if you want to emit .comment section in COFF obj files.
    274 void MCWinCOFFStreamer::EmitIdent(StringRef IdentString) {
    275   llvm_unreachable("not implemented");
    276 }
    277 
    278 void MCWinCOFFStreamer::EmitWinEHHandlerData() {
    279   llvm_unreachable("not implemented");
    280 }
    281 
    282 void MCWinCOFFStreamer::FinishImpl() {
    283   MCObjectStreamer::FinishImpl();
    284 }
    285 
    286 void MCWinCOFFStreamer::Error(const Twine &Msg) const {
    287   getContext().reportError(SMLoc(), Msg);
    288 }
    289 }
    290 
    291