diff --git a/include/llvm/MC/MCSectionWasm.h b/include/llvm/MC/MCSectionWasm.h index dc9f042fc4f..66ae8d68d33 100644 --- a/include/llvm/MC/MCSectionWasm.h +++ b/include/llvm/MC/MCSectionWasm.h @@ -43,11 +43,17 @@ private: // itself and does not include the size of the section header. uint64_t SectionOffset; + // For data sections, this is the offset of the corresponding wasm data + // segment + uint64_t MemoryOffset; + 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), SectionOffset(0) { + assert(type == wasm::WASM_SEC_CODE || type == wasm::WASM_SEC_DATA); + } void setSectionName(StringRef Name) { SectionName = Name; } @@ -74,6 +80,9 @@ public: uint64_t getSectionOffset() const { return SectionOffset; } void setSectionOffset(uint64_t Offset) { SectionOffset = Offset; } + uint32_t getMemoryOffset() const { return MemoryOffset; } + void setMemoryOffset(uint32_t Offset) { MemoryOffset = Offset; } + static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; } }; diff --git a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index fcb20184116..0149c82a00e 100644 --- a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1248,8 +1248,8 @@ static const Comdat *getWasmComdat(const GlobalValue *GV) { MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { - llvm_unreachable("getExplicitSectionGlobal not yet implemented"); - return nullptr; + StringRef Name = GO->getSection(); + return getContext().getWasmSection(Name, wasm::WASM_SEC_DATA); } static MCSectionWasm *selectWasmSectionForGlobal( @@ -1262,10 +1262,12 @@ static MCSectionWasm *selectWasmSectionForGlobal( bool UniqueSectionNames = TM.getUniqueSectionNames(); SmallString<128> Name = getSectionPrefixForGlobal(Kind); + uint32_t Type = wasm::WASM_SEC_DATA; if (const auto *F = dyn_cast(GO)) { const auto &OptionalPrefix = F->getSectionPrefix(); if (OptionalPrefix) Name += *OptionalPrefix; + Type = wasm::WASM_SEC_CODE; } if (EmitUniqueSection && UniqueSectionNames) { @@ -1277,7 +1279,7 @@ static MCSectionWasm *selectWasmSectionForGlobal( UniqueID = *NextUniqueID; (*NextUniqueID)++; } - return Ctx.getWasmSection(Name, /*Type=*/0, Group, UniqueID); + return Ctx.getWasmSection(Name, Type, Group, UniqueID); } MCSection *TargetLoweringObjectFileWasm::SelectSectionForGlobal( diff --git a/lib/MC/MCObjectFileInfo.cpp b/lib/MC/MCObjectFileInfo.cpp index ba376227767..c6c5cb31690 100644 --- a/lib/MC/MCObjectFileInfo.cpp +++ b/lib/MC/MCObjectFileInfo.cpp @@ -820,24 +820,24 @@ void MCObjectFileInfo::initCOFFMCObjectFileInfo(const Triple &T) { void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) { // TODO: Set the section types and flags. - TextSection = Ctx->getWasmSection(".text", 0); - DataSection = Ctx->getWasmSection(".data", 0); + TextSection = Ctx->getWasmSection(".text", wasm::WASM_SEC_CODE); + DataSection = Ctx->getWasmSection(".data", wasm::WASM_SEC_DATA); // TODO: Set the section types and flags. - DwarfLineSection = Ctx->getWasmSection(".debug_line", 0); - DwarfStrSection = Ctx->getWasmSection(".debug_str", 0); - DwarfLocSection = Ctx->getWasmSection(".debug_loc", 0); - DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", 0, "section_abbrev"); - DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", 0); - DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", 0, "debug_range"); - DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", 0, "debug_macinfo"); - DwarfAddrSection = Ctx->getWasmSection(".debug_addr", 0); - DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", 0); - DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", 0); - DwarfInfoSection = Ctx->getWasmSection(".debug_info", 0, "section_info"); - DwarfFrameSection = Ctx->getWasmSection(".debug_frame", 0); - DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", 0); - DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", 0); + DwarfLineSection = Ctx->getWasmSection(".debug_line", wasm::WASM_SEC_DATA); + DwarfStrSection = Ctx->getWasmSection(".debug_str", wasm::WASM_SEC_DATA); + DwarfLocSection = Ctx->getWasmSection(".debug_loc", wasm::WASM_SEC_DATA); + DwarfAbbrevSection = Ctx->getWasmSection(".debug_abbrev", wasm::WASM_SEC_DATA, "section_abbrev"); + DwarfARangesSection = Ctx->getWasmSection(".debug_aranges", wasm::WASM_SEC_DATA); + DwarfRangesSection = Ctx->getWasmSection(".debug_ranges", wasm::WASM_SEC_DATA, "debug_range"); + DwarfMacinfoSection = Ctx->getWasmSection(".debug_macinfo", wasm::WASM_SEC_DATA, "debug_macinfo"); + DwarfAddrSection = Ctx->getWasmSection(".debug_addr", wasm::WASM_SEC_DATA); + DwarfCUIndexSection = Ctx->getWasmSection(".debug_cu_index", wasm::WASM_SEC_DATA); + DwarfTUIndexSection = Ctx->getWasmSection(".debug_tu_index", wasm::WASM_SEC_DATA); + DwarfInfoSection = Ctx->getWasmSection(".debug_info", wasm::WASM_SEC_DATA, "section_info"); + DwarfFrameSection = Ctx->getWasmSection(".debug_frame", wasm::WASM_SEC_DATA); + DwarfPubNamesSection = Ctx->getWasmSection(".debug_pubnames", wasm::WASM_SEC_DATA); + DwarfPubTypesSection = Ctx->getWasmSection(".debug_pubtypes", wasm::WASM_SEC_DATA); // TODO: Define more sections. } diff --git a/lib/MC/MCWasmStreamer.cpp b/lib/MC/MCWasmStreamer.cpp index 02fa070f0c5..be8a5c21610 100644 --- a/lib/MC/MCWasmStreamer.cpp +++ b/lib/MC/MCWasmStreamer.cpp @@ -156,7 +156,7 @@ void MCWasmStreamer::EmitValueToAlignment(unsigned ByteAlignment, int64_t Value, void MCWasmStreamer::EmitIdent(StringRef IdentString) { MCSection *Comment = getAssembler().getContext().getWasmSection( - ".comment", 0, 0); + ".comment", wasm::WASM_SEC_DATA); PushSection(); SwitchSection(Comment); if (!SeenIdent) { diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index f601c144c30..7ed20d32fd2 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -163,7 +163,8 @@ struct WasmRelocationEntry { 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) @@ -495,6 +496,39 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { return Value; } +static void addData(SmallVectorImpl &DataBytes, + MCSectionWasm &DataSection, uint32_t &DataAlignment) { + DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); + DataAlignment = std::max(DataAlignment, DataSection.getAlignment()); + DEBUG(errs() << "addData: " << DataSection.getSectionName() << "\n"); + + 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()); + } + } + + DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); +} + uint32_t WasmObjectWriter::getRelocationIndexValue( const WasmRelocationEntry &RelEntry) { switch (RelEntry.Type) { @@ -773,9 +807,7 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, report_fatal_error(".size expression must be evaluatable"); encodeULEB128(Size, getStream()); - FuncSection.setSectionOffset(getStream().tell() - Section.ContentsOffset); - Asm.writeSectionData(&FuncSection, Layout); } @@ -1016,7 +1048,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, // In the special .global_variables section, we've encoded global // variables used by the function. Translate them into the Globals // list. - MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", 0, 0); + MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", wasm::WASM_SEC_DATA); if (!GlobalVars->getFragmentList().empty()) { if (GlobalVars->getFragmentList().size() != 1) report_fatal_error("only one .global_variables fragment supported"); @@ -1072,7 +1104,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, // In the special .stack_pointer section, we've encoded the stack pointer // index. - MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", 0, 0); + MCSectionWasm *StackPtr = Ctx.getWasmSection(".stack_pointer", wasm::WASM_SEC_DATA); if (!StackPtr->getFragmentList().empty()) { if (StackPtr->getFragmentList().size() != 1) report_fatal_error("only one .stack_pointer fragment supported"); @@ -1089,6 +1121,21 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, StackPointerGlobal = NumGlobalImports + *(const int32_t *)Contents.data(); } + for (MCSection &Sec : Asm) { + auto &Section = static_cast(Sec); + if (Section.getType() != wasm::WASM_SEC_DATA) + continue; + + DataSize = alignTo(DataSize, Section.getAlignment()); + DataSegments.emplace_back(); + WasmDataSegment &Segment = DataSegments.back(); + Segment.Offset = DataSize; + Segment.Section = &Section; + addData(Segment.Data, Section, DataAlignment); + DataSize += Segment.Data.size(); + Section.setMemoryOffset(Segment.Offset); + } + // Handle regular defined and undefined symbols. for (const MCSymbol &S : Asm.symbols()) { // Ignore unnamed temporary symbols, which aren't ever exported, imported, @@ -1151,9 +1198,6 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!WS.isDefined(/*SetUsed=*/false)) continue; - if (WS.getOffset() != 0) - report_fatal_error("data sections must contain one variable each: " + - WS.getName()); if (!WS.getSize()) report_fatal_error("data symbols must have a size set with .size: " + WS.getName()); @@ -1162,58 +1206,20 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) 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"); - - DataAlignment = std::max(DataAlignment, DataSection.getAlignment()); - - DataSegments.emplace_back(); - WasmDataSegment &Segment = DataSegments.back(); - - DataSize = alignTo(DataSize, DataSection.getAlignment()); - Segment.Offset = DataSize; - Segment.Section = &DataSection; - // For each global, prepare a corresponding wasm global holding its // address. For externals these will also be named exports. Index = NumGlobalImports + Globals.size(); + auto &DataSection = static_cast(WS.getSection()); WasmGlobal Global; Global.Type = PtrType; Global.IsMutable = false; Global.HasImport = false; - Global.InitialValue = DataSize; + Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS); Global.ImportIndex = 0; SymbolIndices[&WS] = Index; DEBUG(dbgs() << " -> global index: " << Index << "\n"); Globals.push_back(Global); - - 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(Segment.Data.size(), Align->getAlignment()), - Segment.Data.size() + Align->getMaxBytesToEmit()); - Segment.Data.resize(Size, Value); - } else if (auto *Fill = dyn_cast(&Frag)) { - Segment.Data.insert(Segment.Data.end(), Fill->getSize(), Fill->getValue()); - } else { - const auto &DataFrag = cast(Frag); - const SmallVectorImpl &Contents = DataFrag.getContents(); - - Segment.Data.insert(Segment.Data.end(), Contents.begin(), - Contents.end()); - } - } - DataSize += Segment.Data.size(); } // If the symbol is visible outside this translation unit, export it. diff --git a/test/MC/WebAssembly/explicit-sections.ll b/test/MC/WebAssembly/explicit-sections.ll new file mode 100644 index 00000000000..e9607242252 --- /dev/null +++ b/test/MC/WebAssembly/explicit-sections.ll @@ -0,0 +1,65 @@ +; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o - | obj2yaml | FileCheck %s + +%struct.bd = type { i32, i8 } + +@global0 = global i32 8, align 8 +@global1 = global %struct.bd { i32 1, i8 3 }, align 8, section ".sec1" +@global2 = global i64 7, align 8, section ".sec1" +@global3 = global i32 8, align 8, section ".sec2" + +; CHECK: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 8 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 16 +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 24 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: global0 +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: global1 +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: global2 +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: global3 +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 6 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 0 +; CHECK-NEXT: Content: '08000000' +; CHECK-NEXT: - SectionOffset: 15 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 8 +; CHECK-NEXT: Content: '01000000030000000700000000000000' +; CHECK-NEXT: - SectionOffset: 36 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 24 +; CHECK-NEXT: Content: '08000000'