diff options
Diffstat (limited to 'contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp')
-rw-r--r-- | contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp new file mode 100644 index 0000000..bf341bb --- /dev/null +++ b/contrib/llvm/lib/MC/MCWinCOFFStreamer.cpp @@ -0,0 +1,298 @@ +//===- llvm/MC/MCWinCOFFStreamer.cpp --------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains an implementation of a Windows COFF object file streamer. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFragment.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCObjectStreamer.h" +#include "llvm/MC/MCSection.h" +#include "llvm/MC/MCSymbolCOFF.h" +#include "llvm/MC/MCWinCOFFStreamer.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/SMLoc.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cassert> +#include <cstdint> + +using namespace llvm; + +#define DEBUG_TYPE "WinCOFFStreamer" + +MCWinCOFFStreamer::MCWinCOFFStreamer(MCContext &Context, MCAsmBackend &MAB, + MCCodeEmitter &CE, raw_pwrite_stream &OS) + : MCObjectStreamer(Context, MAB, OS, &CE), CurSymbol(nullptr) {} + +void MCWinCOFFStreamer::EmitInstToData(const MCInst &Inst, + const MCSubtargetInfo &STI) { + MCDataFragment *DF = getOrCreateDataFragment(); + + SmallVector<MCFixup, 4> Fixups; + SmallString<256> Code; + raw_svector_ostream VecOS(Code); + getAssembler().getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); + + // Add the fixups and data. + for (unsigned i = 0, e = Fixups.size(); i != e; ++i) { + Fixups[i].setOffset(Fixups[i].getOffset() + DF->getContents().size()); + DF->getFixups().push_back(Fixups[i]); + } + + DF->getContents().append(Code.begin(), Code.end()); +} + +void MCWinCOFFStreamer::InitSections(bool NoExecStack) { + // FIXME: this is identical to the ELF one. + // This emulates the same behavior of GNU as. This makes it easier + // to compare the output as the major sections are in the same order. + SwitchSection(getContext().getObjectFileInfo()->getTextSection()); + EmitCodeAlignment(4); + + SwitchSection(getContext().getObjectFileInfo()->getDataSection()); + EmitCodeAlignment(4); + + SwitchSection(getContext().getObjectFileInfo()->getBSSSection()); + EmitCodeAlignment(4); + + SwitchSection(getContext().getObjectFileInfo()->getTextSection()); +} + +void MCWinCOFFStreamer::EmitLabel(MCSymbol *S, SMLoc Loc) { + auto *Symbol = cast<MCSymbolCOFF>(S); + MCObjectStreamer::EmitLabel(Symbol, Loc); +} + +void MCWinCOFFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { + llvm_unreachable("not implemented"); +} + +void MCWinCOFFStreamer::EmitThumbFunc(MCSymbol *Func) { + llvm_unreachable("not implemented"); +} + +bool MCWinCOFFStreamer::EmitSymbolAttribute(MCSymbol *S, + MCSymbolAttr Attribute) { + auto *Symbol = cast<MCSymbolCOFF>(S); + getAssembler().registerSymbol(*Symbol); + + switch (Attribute) { + default: return false; + case MCSA_WeakReference: + case MCSA_Weak: + Symbol->setIsWeakExternal(); + Symbol->setExternal(true); + break; + case MCSA_Global: + Symbol->setExternal(true); + break; + case MCSA_AltEntry: + llvm_unreachable("COFF doesn't support the .alt_entry attribute"); + } + + return true; +} + +void MCWinCOFFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { + llvm_unreachable("not implemented"); +} + +void MCWinCOFFStreamer::BeginCOFFSymbolDef(MCSymbol const *S) { + auto *Symbol = cast<MCSymbolCOFF>(S); + if (CurSymbol) + Error("starting a new symbol definition without completing the " + "previous one"); + CurSymbol = Symbol; +} + +void MCWinCOFFStreamer::EmitCOFFSymbolStorageClass(int StorageClass) { + if (!CurSymbol) { + Error("storage class specified outside of symbol definition"); + return; + } + + if (StorageClass & ~COFF::SSC_Invalid) { + Error("storage class value '" + Twine(StorageClass) + + "' out of range"); + return; + } + + getAssembler().registerSymbol(*CurSymbol); + cast<MCSymbolCOFF>(CurSymbol)->setClass((uint16_t)StorageClass); +} + +void MCWinCOFFStreamer::EmitCOFFSymbolType(int Type) { + if (!CurSymbol) { + Error("symbol type specified outside of a symbol definition"); + return; + } + + if (Type & ~0xffff) { + Error("type value '" + Twine(Type) + "' out of range"); + return; + } + + getAssembler().registerSymbol(*CurSymbol); + cast<MCSymbolCOFF>(CurSymbol)->setType((uint16_t)Type); +} + +void MCWinCOFFStreamer::EndCOFFSymbolDef() { + if (!CurSymbol) + Error("ending symbol definition without starting one"); + CurSymbol = nullptr; +} + +void MCWinCOFFStreamer::EmitCOFFSafeSEH(MCSymbol const *Symbol) { + // SafeSEH is a feature specific to 32-bit x86. It does not exist (and is + // unnecessary) on all platforms which use table-based exception dispatch. + if (getContext().getObjectFileInfo()->getTargetTriple().getArch() != + Triple::x86) + return; + + const MCSymbolCOFF *CSymbol = cast<MCSymbolCOFF>(Symbol); + if (CSymbol->isSafeSEH()) + return; + + MCSection *SXData = getContext().getObjectFileInfo()->getSXDataSection(); + getAssembler().registerSection(*SXData); + if (SXData->getAlignment() < 4) + SXData->setAlignment(4); + + new MCSafeSEHFragment(Symbol, SXData); + + getAssembler().registerSymbol(*Symbol); + CSymbol->setIsSafeSEH(); + + // The Microsoft linker requires that the symbol type of a handler be + // function. Go ahead and oblige it here. + CSymbol->setType(COFF::IMAGE_SYM_DTYPE_FUNCTION + << COFF::SCT_COMPLEX_TYPE_SHIFT); +} + +void MCWinCOFFStreamer::EmitCOFFSectionIndex(const MCSymbol *Symbol) { + visitUsedSymbol(*Symbol); + MCDataFragment *DF = getOrCreateDataFragment(); + const MCSymbolRefExpr *SRE = MCSymbolRefExpr::create(Symbol, getContext()); + MCFixup Fixup = MCFixup::create(DF->getContents().size(), SRE, FK_SecRel_2); + DF->getFixups().push_back(Fixup); + DF->getContents().resize(DF->getContents().size() + 2, 0); +} + +void MCWinCOFFStreamer::EmitCOFFSecRel32(const MCSymbol *Symbol, + uint64_t Offset) { + visitUsedSymbol(*Symbol); + MCDataFragment *DF = getOrCreateDataFragment(); + // Create Symbol A for the relocation relative reference. + const MCExpr *MCE = MCSymbolRefExpr::create(Symbol, getContext()); + // Add the constant offset, if given. + if (Offset) + MCE = MCBinaryExpr::createAdd( + MCE, MCConstantExpr::create(Offset, getContext()), getContext()); + // Build the secrel32 relocation. + MCFixup Fixup = MCFixup::create(DF->getContents().size(), MCE, FK_SecRel_4); + // Record the relocation. + DF->getFixups().push_back(Fixup); + // Emit 4 bytes (zeros) to the object file. + DF->getContents().resize(DF->getContents().size() + 4, 0); +} + +void MCWinCOFFStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, + unsigned ByteAlignment) { + auto *Symbol = cast<MCSymbolCOFF>(S); + + const Triple &T = getContext().getObjectFileInfo()->getTargetTriple(); + if (T.isKnownWindowsMSVCEnvironment()) { + if (ByteAlignment > 32) + report_fatal_error("alignment is limited to 32-bytes"); + + // Round size up to alignment so that we will honor the alignment request. + Size = std::max(Size, static_cast<uint64_t>(ByteAlignment)); + } + + getAssembler().registerSymbol(*Symbol); + Symbol->setExternal(true); + Symbol->setCommon(Size, ByteAlignment); + + if (!T.isKnownWindowsMSVCEnvironment() && ByteAlignment > 1) { + SmallString<128> Directive; + raw_svector_ostream OS(Directive); + const MCObjectFileInfo *MFI = getContext().getObjectFileInfo(); + + OS << " -aligncomm:\"" << Symbol->getName() << "\"," + << Log2_32_Ceil(ByteAlignment); + + PushSection(); + SwitchSection(MFI->getDrectveSection()); + EmitBytes(Directive); + PopSection(); + } +} + +void MCWinCOFFStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size, + unsigned ByteAlignment) { + auto *Symbol = cast<MCSymbolCOFF>(S); + + MCSection *Section = getContext().getObjectFileInfo()->getBSSSection(); + getAssembler().registerSection(*Section); + if (Section->getAlignment() < ByteAlignment) + Section->setAlignment(ByteAlignment); + + getAssembler().registerSymbol(*Symbol); + Symbol->setExternal(false); + + if (ByteAlignment != 1) + new MCAlignFragment(ByteAlignment, /*Value=*/0, /*ValueSize=*/0, + ByteAlignment, Section); + + MCFillFragment *Fragment = new MCFillFragment( + /*Value=*/0, Size, Section); + Symbol->setFragment(Fragment); +} + +void MCWinCOFFStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("not implemented"); +} + +void MCWinCOFFStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, + uint64_t Size, unsigned ByteAlignment) { + llvm_unreachable("not implemented"); +} + +// TODO: Implement this if you want to emit .comment section in COFF obj files. +void MCWinCOFFStreamer::EmitIdent(StringRef IdentString) { + llvm_unreachable("not implemented"); +} + +void MCWinCOFFStreamer::EmitWinEHHandlerData() { + llvm_unreachable("not implemented"); +} + +void MCWinCOFFStreamer::FinishImpl() { + MCObjectStreamer::FinishImpl(); +} + +void MCWinCOFFStreamer::Error(const Twine &Msg) const { + getContext().reportError(SMLoc(), Msg); +} |