| //===- lib/MC/MCWasmStreamer.cpp - Wasm Object Output ---------------------===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file assembles .s files and emits Wasm .o object files. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/MC/MCWasmStreamer.h" | |
| #include "llvm/ADT/STLExtras.h" | |
| #include "llvm/ADT/SmallPtrSet.h" | |
| #include "llvm/MC/MCAsmBackend.h" | |
| #include "llvm/MC/MCAsmLayout.h" | |
| #include "llvm/MC/MCAssembler.h" | |
| #include "llvm/MC/MCCodeEmitter.h" | |
| #include "llvm/MC/MCContext.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCObjectStreamer.h" | |
| #include "llvm/MC/MCSection.h" | |
| #include "llvm/MC/MCSectionWasm.h" | |
| #include "llvm/MC/MCSymbol.h" | |
| #include "llvm/MC/MCSymbolWasm.h" | |
| #include "llvm/MC/MCValue.h" | |
| #include "llvm/Support/Casting.h" | |
| #include "llvm/Support/Debug.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/TargetRegistry.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| using namespace llvm; | |
| MCWasmStreamer::~MCWasmStreamer() {} | |
| void MCWasmStreamer::mergeFragment(MCDataFragment *DF, MCDataFragment *EF) { | |
| flushPendingLabels(DF, DF->getContents().size()); | |
| for (unsigned i = 0, e = EF->getFixups().size(); i != e; ++i) { | |
| EF->getFixups()[i].setOffset(EF->getFixups()[i].getOffset() + | |
| DF->getContents().size()); | |
| DF->getFixups().push_back(EF->getFixups()[i]); | |
| } | |
| if (DF->getSubtargetInfo() == nullptr && EF->getSubtargetInfo()) | |
| DF->setHasInstructions(*EF->getSubtargetInfo()); | |
| DF->getContents().append(EF->getContents().begin(), EF->getContents().end()); | |
| } | |
| void MCWasmStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) { | |
| // Let the target do whatever target specific stuff it needs to do. | |
| getAssembler().getBackend().handleAssemblerFlag(Flag); | |
| // Do any generic stuff we need to do. | |
| llvm_unreachable("invalid assembler flag!"); | |
| } | |
| void MCWasmStreamer::ChangeSection(MCSection *Section, | |
| const MCExpr *Subsection) { | |
| MCAssembler &Asm = getAssembler(); | |
| auto *SectionWasm = static_cast<const MCSectionWasm *>(Section); | |
| const MCSymbol *Grp = SectionWasm->getGroup(); | |
| if (Grp) | |
| Asm.registerSymbol(*Grp); | |
| this->MCObjectStreamer::ChangeSection(Section, Subsection); | |
| Asm.registerSymbol(*Section->getBeginSymbol()); | |
| } | |
| void MCWasmStreamer::EmitWeakReference(MCSymbol *Alias, | |
| const MCSymbol *Symbol) { | |
| getAssembler().registerSymbol(*Symbol); | |
| const MCExpr *Value = MCSymbolRefExpr::create( | |
| Symbol, MCSymbolRefExpr::VK_WEAKREF, getContext()); | |
| Alias->setVariableValue(Value); | |
| } | |
| bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { | |
| assert(Attribute != MCSA_IndirectSymbol && "indirect symbols not supported"); | |
| auto *Symbol = cast<MCSymbolWasm>(S); | |
| // Adding a symbol attribute always introduces the symbol; note that an | |
| // important side effect of calling registerSymbol here is to register the | |
| // symbol with the assembler. | |
| getAssembler().registerSymbol(*Symbol); | |
| switch (Attribute) { | |
| case MCSA_LazyReference: | |
| case MCSA_Reference: | |
| case MCSA_SymbolResolver: | |
| case MCSA_PrivateExtern: | |
| case MCSA_WeakDefinition: | |
| case MCSA_WeakDefAutoPrivate: | |
| case MCSA_Invalid: | |
| case MCSA_IndirectSymbol: | |
| case MCSA_Protected: | |
| return false; | |
| case MCSA_Hidden: | |
| Symbol->setHidden(true); | |
| break; | |
| case MCSA_Weak: | |
| case MCSA_WeakReference: | |
| Symbol->setWeak(true); | |
| Symbol->setExternal(true); | |
| break; | |
| case MCSA_Global: | |
| Symbol->setExternal(true); | |
| break; | |
| case MCSA_ELF_TypeFunction: | |
| Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); | |
| break; | |
| case MCSA_ELF_TypeObject: | |
| Symbol->setType(wasm::WASM_SYMBOL_TYPE_DATA); | |
| break; | |
| default: | |
| // unrecognized directive | |
| llvm_unreachable("unexpected MCSymbolAttr"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| void MCWasmStreamer::EmitCommonSymbol(MCSymbol *S, uint64_t Size, | |
| unsigned ByteAlignment) { | |
| llvm_unreachable("Common symbols are not yet implemented for Wasm"); | |
| } | |
| void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) { | |
| cast<MCSymbolWasm>(Symbol)->setSize(Value); | |
| } | |
| void MCWasmStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size, | |
| unsigned ByteAlignment) { | |
| llvm_unreachable("Local common symbols are not yet implemented for Wasm"); | |
| } | |
| void MCWasmStreamer::EmitValueImpl(const MCExpr *Value, unsigned Size, | |
| SMLoc Loc) { | |
| MCObjectStreamer::EmitValueImpl(Value, Size, Loc); | |
| } | |
| void MCWasmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, | |
| unsigned ValueSize, | |
| unsigned MaxBytesToEmit) { | |
| MCObjectStreamer::EmitValueToAlignment(ByteAlignment, Value, ValueSize, | |
| MaxBytesToEmit); | |
| } | |
| void MCWasmStreamer::EmitIdent(StringRef IdentString) { | |
| // TODO(sbc): Add the ident section once we support mergable strings | |
| // sections in the object format | |
| } | |
| void MCWasmStreamer::EmitInstToFragment(const MCInst &Inst, | |
| const MCSubtargetInfo &STI) { | |
| this->MCObjectStreamer::EmitInstToFragment(Inst, STI); | |
| } | |
| void MCWasmStreamer::EmitInstToData(const MCInst &Inst, | |
| const MCSubtargetInfo &STI) { | |
| MCAssembler &Assembler = getAssembler(); | |
| SmallVector<MCFixup, 4> Fixups; | |
| SmallString<256> Code; | |
| raw_svector_ostream VecOS(Code); | |
| Assembler.getEmitter().encodeInstruction(Inst, VecOS, Fixups, STI); | |
| // Append the encoded instruction to the current data fragment (or create a | |
| // new such fragment if the current fragment is not a data fragment). | |
| MCDataFragment *DF = getOrCreateDataFragment(); | |
| // 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->setHasInstructions(STI); | |
| DF->getContents().append(Code.begin(), Code.end()); | |
| } | |
| void MCWasmStreamer::FinishImpl() { | |
| EmitFrames(nullptr); | |
| this->MCObjectStreamer::FinishImpl(); | |
| } | |
| MCStreamer *llvm::createWasmStreamer(MCContext &Context, | |
| std::unique_ptr<MCAsmBackend> &&MAB, | |
| std::unique_ptr<MCObjectWriter> &&OW, | |
| std::unique_ptr<MCCodeEmitter> &&CE, | |
| bool RelaxAll) { | |
| MCWasmStreamer *S = | |
| new MCWasmStreamer(Context, std::move(MAB), std::move(OW), std::move(CE)); | |
| if (RelaxAll) | |
| S->getAssembler().setRelaxAll(true); | |
| return S; | |
| } | |
| void MCWasmStreamer::EmitThumbFunc(MCSymbol *Func) { | |
| llvm_unreachable("Generic Wasm doesn't support this directive"); | |
| } | |
| void MCWasmStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) { | |
| llvm_unreachable("Wasm doesn't support this directive"); | |
| } | |
| void MCWasmStreamer::EmitZerofill(MCSection *Section, MCSymbol *Symbol, | |
| uint64_t Size, unsigned ByteAlignment, | |
| SMLoc Loc) { | |
| llvm_unreachable("Wasm doesn't support this directive"); | |
| } | |
| void MCWasmStreamer::EmitTBSSSymbol(MCSection *Section, MCSymbol *Symbol, | |
| uint64_t Size, unsigned ByteAlignment) { | |
| llvm_unreachable("Wasm doesn't support this directive"); | |
| } |