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/ADT/StringExtras.h"
     15 #include "llvm/MC/MCStreamer.h"
     16 #include "llvm/MC/MCAsmBackend.h"
     17 #include "llvm/MC/MCAsmLayout.h"
     18 #include "llvm/MC/MCAssembler.h"
     19 #include "llvm/MC/MCCodeEmitter.h"
     20 #include "llvm/MC/MCContext.h"
     21 #include "llvm/MC/MCExpr.h"
     22 #include "llvm/MC/MCObjectFileInfo.h"
     23 #include "llvm/MC/MCObjectStreamer.h"
     24 #include "llvm/MC/MCSection.h"
     25 #include "llvm/MC/MCSectionCOFF.h"
     26 #include "llvm/MC/MCSymbol.h"
     27 #include "llvm/MC/MCValue.h"
     28 #include "llvm/MC/MCWin64EH.h"
     29 #include "llvm/MC/MCWinCOFFStreamer.h"
     30 #include "llvm/Support/COFF.h"
     31 #include "llvm/Support/Debug.h"
     32 #include "llvm/Support/ErrorHandling.h"
     33 #include "llvm/Support/TargetRegistry.h"
     34 #include "llvm/Support/raw_ostream.h"
     35 
     36 using namespace llvm;
     37 
     38 #define DEBUG_TYPE "WinCOFFStreamer"
     39 
     40 namespace llvm {
     41 MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB,
     42                                      MCCodeEmitter &CE, raw_ostream &OS)
     43     : MCObjectStreamer(Context, MAB, OS, &CE), CurSymbol(nullptr) {}
     44 
     45 void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst,
     46                                        const MCSubtargetInfo &STI) {
     47   MCDataFragment *DF = getOrCreateDataFragment();
     48 
     49   SmallVector<MCFixup, 4> Fixups;
     50   SmallString<256> Code;
     51   raw_svector_ostream VecOS(Code);
     52   getAssembler().getEmitter().EncodeInstruction(Inst, VecOS, Fixups, STI);
     53   VecOS.flush();
     54 
     55   // Add the fixups and data.
     56   for (unsigned i = 0, e = Fixups.size(); i != e; ++i) {
     57     Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size());
     58     DF->getFixups().push_back(Fixups[i]);
     59   }
     60 
     61   DF->getContents().append(Code.begin(), Code.end());
     62 }
     63 
     64 void MCWinCOFFStreamer::InitSections() {
     65   // FIXME: this is identical to the ELF one.
     66   // This emulates the same behavior of GNU as. This makes it easier
     67   // to compare the output as the major sections are in the same order.
     68   SwitchSection(getContext().getObjectFileInfo()->getTextSection());
     69   EmitCodeAlignment(4);
     70 
     71   SwitchSection(getContext().getObjectFileInfo()->getDataSection());
     72   EmitCodeAlignment(4);
     73 
     74   SwitchSection(getContext().getObjectFileInfo()->getBSSSection());
     75   EmitCodeAlignment(4);
     76 
     77   SwitchSection(getContext().getObjectFileInfo()->getTextSection());
     78 }
     79 
     80 void MCWinCOFFStreamer::EmitLabel(MCSymbol *Symbol) {
     81   assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
     82   MCObjectStreamer::EmitLabel(Symbol);
     83 }
     84 
     85 void MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
     86   llvm_unreachable("not implemented");
     87 }
     88 
     89 void MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) {
     90   llvm_unreachable("not implemented");
     91 }
     92 
     93 bool MCWinCOFFStreamer::EmitSymbolAttribute(MCSymbol *Symbol,
     94                                             MCSymbolAttr Attribute) {
     95   assert(Symbol && "Symbol must be non-null!");
     96   assert((!Symbol->isInSection() ||
     97           Symbol->getSection().getVariant() == MCSection::SV_COFF) &&
     98          "Got non-COFF section in the COFF backend!");
     99 
    100   MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
    101 
    102   switch (Attribute) {
    103   default: return false;
    104   case MCSA_WeakReference:
    105   case MCSA_Weak:
    106     SD.modifyFlags(COFF::SF_WeakExternal, COFF::SF_WeakExternal);
    107     SD.setExternal(true);
    108     break;
    109   case MCSA_Global:
    110     SD.setExternal(true);
    111     break;
    112   }
    113 
    114   return true;
    115 }
    116 
    117 void MCWinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
    118   llvm_unreachable("not implemented");
    119 }
    120 
    121 void MCWinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *Symbol) {
    122   assert((!Symbol->isInSection() ||
    123           Symbol->getSection().getVariant() == MCSection::SV_COFF) &&
    124          "Got non-COFF section in the COFF backend!");
    125 
    126   if (CurSymbol)
    127     FatalError("starting a new symbol definition without completing the "
    128                "previous one");
    129   CurSymbol = Symbol;
    130 }
    131 
    132 void MCWinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) {
    133   if (!CurSymbol)
    134     FatalError("storage class specified outside of symbol definition");
    135 
    136   if (StorageClass & ~0xff)
    137     FatalError(Twine("storage class value '") + itostr(StorageClass) +
    138                "' out of range");
    139 
    140   MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*CurSymbol);
    141   SD.modifyFlags(StorageClass << COFF::SF_ClassShift, COFF::SF_ClassMask);
    142 }
    143 
    144 void MCWinCOFFStreamer::EmitCOFFSymbolType(int Type) {
    145   if (!CurSymbol)
    146     FatalError("symbol type specified outside of a symbol definition");
    147 
    148   if (Type & ~0xffff)
    149     FatalError(Twine("type value '") + itostr(Type) + "' out of range");
    150 
    151   MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*CurSymbol);
    152   SD.modifyFlags(Type << COFF::SF_TypeShift, COFF::SF_TypeMask);
    153 }
    154 
    155 void MCWinCOFFStreamer::EndCOFFSymbolDef() {
    156   if (!CurSymbol)
    157     FatalError("ending symbol definition without starting one");
    158   CurSymbol = nullptr;
    159 }
    160 
    161 void MCWinCOFFStreamer::EmitCOFFSectionIndex(MCSymbol const *Symbol) {
    162   MCDataFragment *DF = getOrCreateDataFragment();
    163   const MCSymbolRefExpr *SRE = MCSymbolRefExpr::Create(Symbol, getContext());
    164   MCFixup Fixup = MCFixup::Create(DF->getContents().size(), SRE, FK_SecRel_2);
    165   DF->getFixups().push_back(Fixup);
    166   DF->getContents().resize(DF->getContents().size() + 4, 0);
    167 }
    168 
    169 void MCWinCOFFStreamer::EmitCOFFSecRel32(MCSymbol const *Symbol) {
    170   MCDataFragment *DF = getOrCreateDataFragment();
    171   const MCSymbolRefExpr *SRE = MCSymbolRefExpr::Create(Symbol, getContext());
    172   MCFixup Fixup = MCFixup::Create(DF->getContents().size(), SRE, FK_SecRel_4);
    173   DF->getFixups().push_back(Fixup);
    174   DF->getContents().resize(DF->getContents().size() + 4, 0);
    175 }
    176 
    177 void MCWinCOFFStreamer::EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
    178   llvm_unreachable("not supported");
    179 }
    180 
    181 void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
    182                                          unsigned ByteAlignment) {
    183   assert((!Symbol->isInSection() ||
    184           Symbol->getSection().getVariant() == MCSection::SV_COFF) &&
    185          "Got non-COFF section in the COFF backend!");
    186 
    187   if (ByteAlignment > 32)
    188     report_fatal_error("alignment is limited to 32-bytes");
    189 
    190   AssignSection(Symbol, nullptr);
    191 
    192   MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
    193   SD.setExternal(true);
    194   SD.setCommon(Size, ByteAlignment);
    195 }
    196 
    197 void MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
    198                                               unsigned ByteAlignment) {
    199   assert(!Symbol->isInSection() && "Symbol must not already have a section!");
    200 
    201   const MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
    202   MCSectionData &SectionData = getAssembler().getOrCreateSectionData(*Section);
    203   if (SectionData.getAlignment() < ByteAlignment)
    204     SectionData.setAlignment(ByteAlignment);
    205 
    206   MCSymbolData &SD = getAssembler().getOrCreateSymbolData(*Symbol);
    207   SD.setExternal(false);
    208 
    209   AssignSection(Symbol, Section);
    210 
    211   if (ByteAlignment != 1)
    212     new MCAlignFragment(ByteAlignment, /*_Value=*/0, /*_ValueSize=*/0,
    213                         ByteAlignment, &SectionData);
    214 
    215   MCFillFragment *Fragment =
    216       new MCFillFragment(/*_Value=*/0, /*_ValueSize=*/0, Size, &SectionData);
    217   SD.setFragment(Fragment);
    218 }
    219 
    220 void MCWinCOFFStreamer::EmitZerofill(const MCSection *Section,
    221                                      MCSymbol *Symbol, uint64_t Size,
    222                                      unsigned ByteAlignment) {
    223   llvm_unreachable("not implemented");
    224 }
    225 
    226 void MCWinCOFFStreamer::EmitTBSSSymbol(const MCSection *Section,
    227                                        MCSymbol *Symbol, uint64_t Size,
    228                                        unsigned ByteAlignment) {
    229   llvm_unreachable("not implemented");
    230 }
    231 
    232 void MCWinCOFFStreamer::EmitFileDirective(StringRef Filename) {
    233   getAssembler().addFileName(Filename);
    234 }
    235 
    236 // TODO: Implement this if you want to emit .comment section in COFF obj files.
    237 void MCWinCOFFStreamer::EmitIdent(StringRef IdentString) {
    238   llvm_unreachable("not implemented");
    239 }
    240 
    241 void MCWinCOFFStreamer::EmitWinEHHandlerData() {
    242   llvm_unreachable("not implemented");
    243 }
    244 
    245 void MCWinCOFFStreamer::FinishImpl() {
    246   MCObjectStreamer::FinishImpl();
    247 }
    248 
    249 LLVM_ATTRIBUTE_NORETURN
    250 void MCWinCOFFStreamer::FatalError(const Twine &Msg) const {
    251   getContext().FatalError(SMLoc(), Msg);
    252 }
    253 }
    254 
    255