Index: include/llvm/MC/MCSectionWasm.h =================================================================== --- include/llvm/MC/MCSectionWasm.h +++ include/llvm/MC/MCSectionWasm.h @@ -14,6 +14,7 @@ #ifndef LLVM_MC_MCSECTIONWASM_H #define LLVM_MC_MCSECTIONWASM_H +#include "llvm/ADT/Optional.h" #include "llvm/ADT/Twine.h" #include "llvm/MC/MCSection.h" #include "llvm/MC/MCSymbolWasm.h" @@ -41,13 +42,13 @@ // The offset of the MC function/data section in the wasm code/data section. // For data relocations the offset is relative to start of the data payload // itself and does not include the size of the section header. - uint64_t SectionOffset; + Optional SectionOffset; friend class MCContext; MCSectionWasm(StringRef Section, unsigned type, SectionKind K, const MCSymbolWasm *group, unsigned UniqueID, MCSymbol *Begin) : MCSection(SV_Wasm, K, Begin), SectionName(Section), Type(type), - UniqueID(UniqueID), Group(group), SectionOffset(0) {} + UniqueID(UniqueID), Group(group) {} void setSectionName(StringRef Name) { SectionName = Name; } @@ -71,7 +72,7 @@ bool isUnique() const { return UniqueID != ~0U; } unsigned getUniqueID() const { return UniqueID; } - uint64_t getSectionOffset() const { return SectionOffset; } + uint64_t getSectionOffset() const { return SectionOffset.getValue(); } void setSectionOffset(uint64_t Offset) { SectionOffset = Offset; } static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; } Index: lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1326,7 +1326,7 @@ MCSymbolRefExpr::create(TM.getSymbol(RHS), getContext()), getContext()); } -void -TargetLoweringObjectFileWasm::InitializeWasm() { - // TODO: Initialize StaticCtorSection and StaticDtorSection. +void TargetLoweringObjectFileWasm::InitializeWasm() { + StaticCtorSection = getContext().getWasmSection(".init_array", 0); + StaticDtorSection = getContext().getWasmSection(".fini_array", 0); } Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -153,7 +153,8 @@ void print(raw_ostream &Out) const { Out << "Off=" << Offset << ", Sym=" << *Symbol << ", Addend=" << Addend - << ", Type=" << Type << ", FixupSection=" << FixupSection; + << ", Type=" << Type + << ", FixupSection=" << FixupSection->getSectionName(); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -199,6 +200,9 @@ DenseMap FunctionTypeIndices; SmallVector FunctionTypes; + SmallVector Globals; + SmallVector Exports; + unsigned NumGlobalImports = 0; // TargetObjectWriter wrappers. bool is64Bit() const { return TargetObjectWriter->is64Bit(); } @@ -225,11 +229,16 @@ IndirectSymbolIndices.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); + Globals.clear(); + Exports.clear(); MCObjectWriter::reset(); + NumGlobalImports = 0; } void writeHeader(const MCAssembler &Asm); + void addGlobal(StringRef Name, uint32_t Value); + void recordRelocation(MCAssembler &Asm, const MCAsmLayout &Layout, const MCFragment *Fragment, const MCFixup &Fixup, MCValue Target, uint64_t &FixedValue) override; @@ -484,6 +493,38 @@ return Value; } +static void addData(SmallVector &DataBytes, MCSectionWasm &DataSection, + uint32_t &DataAlignment) { + DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); + DataAlignment = std::max(DataAlignment, DataSection.getAlignment()); + + DataSection.setSectionOffset(DataBytes.size()); + + for (const MCFragment &Frag : DataSection) { + if (Frag.hasInstructions()) + report_fatal_error("only data supported in data sections"); + + if (auto *Align = dyn_cast(&Frag)) { + if (Align->getValueSize() != 1) + report_fatal_error("only byte values supported for alignment"); + // If nops are requested, use zeros, as this is the data section. + uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); + uint64_t Size = std::min(alignTo(DataBytes.size(), + Align->getAlignment()), + DataBytes.size() + + Align->getMaxBytesToEmit()); + DataBytes.resize(Size, Value); + } else if (auto *Fill = dyn_cast(&Frag)) { + DataBytes.insert(DataBytes.end(), Fill->getSize(), Fill->getValue()); + } else { + const auto &DataFrag = cast(Frag); + const SmallVectorImpl &Contents = DataFrag.getContents(); + + DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); + } + } +} + uint32_t WasmObjectWriter::getRelocationIndexValue( const WasmRelocationEntry &RelEntry) { switch (RelEntry.Type) { @@ -942,6 +983,22 @@ return Pair.first->second; } +void WasmObjectWriter::addGlobal(StringRef Name, uint32_t Value) { + uint32_t Index = NumGlobalImports + Globals.size(); + WasmGlobal Global; + Global.Type = is64Bit() ? wasm::ValType::I64 : wasm::ValType::I32; + Global.IsMutable = false; + Global.HasImport = false; + Global.InitialValue = Value; + Global.ImportIndex = 0; + Globals.push_back(Global); + WasmExport Export; + Export.FieldName = Name; + Export.Index = Index; + Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; + Exports.push_back(Export); +} + void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); @@ -951,13 +1008,10 @@ // Collect information from the available symbols. SmallVector Functions; SmallVector TableElems; - SmallVector Globals; SmallVector Imports; - SmallVector Exports; SmallVector WeakSymbols; SmallPtrSet IsAddressTaken; unsigned NumFuncImports = 0; - unsigned NumGlobalImports = 0; SmallVector DataBytes; uint32_t DataAlignment = 1; uint32_t StackPointerGlobal = 0; @@ -1093,6 +1147,20 @@ StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); } + MCSectionWasm *InitArray = Ctx.getWasmSection(".init_array", 0, 0); + if (!InitArray->getFragmentList().empty()) { + addGlobal("__init_array_start", DataBytes.size()); + addData(DataBytes, *InitArray, DataAlignment); + addGlobal("__init_array_end", DataBytes.size()); + } + + MCSectionWasm *FiniArray = Ctx.getWasmSection(".fini_array", 0, 0); + if (!FiniArray->getFragmentList().empty()) { + addGlobal("__fini_array_start", DataBytes.size()); + addData(DataBytes, *FiniArray, DataAlignment); + addGlobal("__fini_array_end", DataBytes.size()); + } + // Handle regular defined and undefined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, @@ -1167,38 +1235,10 @@ report_fatal_error(".size expression must be evaluatable"); auto &DataSection = static_cast(WS.getSection()); - if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection)) report_fatal_error("data sections must contain at most one variable"); - DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); - DataAlignment = std::max(DataAlignment, DataSection.getAlignment()); - - DataSection.setSectionOffset(DataBytes.size()); - - for (const MCFragment &Frag : DataSection) { - if (Frag.hasInstructions()) - report_fatal_error("only data supported in data sections"); - - if (auto *Align = dyn_cast(&Frag)) { - if (Align->getValueSize() != 1) - report_fatal_error("only byte values supported for alignment"); - // If nops are requested, use zeros, as this is the data section. - uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue(); - uint64_t Size = std::min(alignTo(DataBytes.size(), - Align->getAlignment()), - DataBytes.size() + - Align->getMaxBytesToEmit()); - DataBytes.resize(Size, Value); - } else if (auto *Fill = dyn_cast(&Frag)) { - DataBytes.insert(DataBytes.end(), Fill->getSize(), Fill->getValue()); - } else { - const auto &DataFrag = cast(Frag); - const SmallVectorImpl &Contents = DataFrag.getContents(); - - DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); - } - } + addData(DataBytes, DataSection, DataAlignment); // For each global, prepare a corresponding wasm global holding its // address. For externals these will also be named exports.