From e92250ac8f379ddde51190e059a9b0257178a992 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Tue, 9 Jan 2018 23:43:14 +0000 Subject: [PATCH] [WebAssembly] Add COMDAT support This adds COMDAT support to the Wasm object-file format. Spec: https://github.com/WebAssembly/tool-conventions/pull/31 Corresponding LLD change: https://bugs.llvm.org/show_bug.cgi?id=35533, and D40845 Patch by Nicholas Wilson Differential Revision: https://reviews.llvm.org/D40844 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@322135 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.rst | 4 +- include/llvm/ADT/Triple.h | 4 +- include/llvm/BinaryFormat/Wasm.h | 22 +++++-- include/llvm/Object/Wasm.h | 3 + include/llvm/ObjectYAML/WasmYAML.h | 26 ++++++++ lib/CodeGen/TargetLoweringObjectFileImpl.cpp | 29 +++++--- lib/MC/WasmObjectWriter.cpp | 51 ++++++++++++-- lib/Object/WasmObjectFile.cpp | 54 +++++++++++++++ lib/ObjectYAML/WasmYAML.cpp | 21 ++++++ test/CodeGen/WebAssembly/comdat.ll | 5 -- test/MC/WebAssembly/comdat.ll | 99 ++++++++++++++++++++++++++++ tools/obj2yaml/wasm2yaml.cpp | 23 ++++++- tools/yaml2obj/yaml2wasm.cpp | 17 +++++ 13 files changed, 326 insertions(+), 32 deletions(-) delete mode 100644 test/CodeGen/WebAssembly/comdat.ll create mode 100644 test/MC/WebAssembly/comdat.ll diff --git a/docs/LangRef.rst b/docs/LangRef.rst index 589786255af..462fbccdb8f 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -883,8 +883,8 @@ The selection kind must be one of the following: The linker may choose any COMDAT key but the sections must contain the same amount of data. -Note that the Mach-O platform doesn't support COMDATs and ELF only supports -``any`` as a selection kind. +Note that the Mach-O platform doesn't support COMDATs, and ELF and WebAssembly +only support ``any`` as a selection kind. Here is an example of a COMDAT group where a function will only be selected if the COMDAT key's section is the largest: diff --git a/include/llvm/ADT/Triple.h b/include/llvm/ADT/Triple.h index 74fc8eb8ccb..13b63738db3 100644 --- a/include/llvm/ADT/Triple.h +++ b/include/llvm/ADT/Triple.h @@ -660,9 +660,9 @@ public: return getArch() == Triple::aarch64 || getArch() == Triple::aarch64_be; } - /// Tests wether the target supports comdat + /// Tests whether the target supports comdat bool supportsCOMDAT() const { - return !isOSBinFormatMachO() && !isOSBinFormatWasm(); + return !isOSBinFormatMachO(); } /// @} diff --git a/include/llvm/BinaryFormat/Wasm.h b/include/llvm/BinaryFormat/Wasm.h index 7d436180f03..80fd9a47a8d 100644 --- a/include/llvm/BinaryFormat/Wasm.h +++ b/include/llvm/BinaryFormat/Wasm.h @@ -95,6 +95,7 @@ struct WasmFunction { ArrayRef Body; uint32_t CodeSectionOffset; uint32_t Size; + StringRef Comdat; }; struct WasmDataSegment { @@ -104,6 +105,7 @@ struct WasmDataSegment { StringRef Name; uint32_t Alignment; uint32_t Flags; + StringRef Comdat; }; struct WasmElemSegment { @@ -174,11 +176,6 @@ enum : unsigned { }; enum : unsigned { - WASM_NAMES_FUNCTION = 0x1, - WASM_NAMES_LOCAL = 0x2, -}; - -enum : unsigned { WASM_LIMITS_FLAG_HAS_MAX = 0x1, }; @@ -190,12 +187,25 @@ enum class ValType { F64 = WASM_TYPE_F64, }; -// Linking metadata kinds. +// Kind codes used in the custom "name" section +enum : unsigned { + WASM_NAMES_FUNCTION = 0x1, + WASM_NAMES_LOCAL = 0x2, +}; + +// Kind codes used in the custom "linking" section enum : unsigned { WASM_SYMBOL_INFO = 0x2, WASM_DATA_SIZE = 0x3, WASM_SEGMENT_INFO = 0x5, WASM_INIT_FUNCS = 0x6, + WASM_COMDAT_INFO = 0x7, +}; + +// Kind codes used in the custom "linking" section in the WASM_COMDAT_INFO +enum : unsigned { + WASM_COMDAT_DATA = 0x0, + WASM_COMDAT_FUNCTION = 0x1, }; const unsigned WASM_SYMBOL_BINDING_MASK = 0x3; diff --git a/include/llvm/Object/Wasm.h b/include/llvm/Object/Wasm.h index 71951d83f3c..fce8603ac59 100644 --- a/include/llvm/Object/Wasm.h +++ b/include/llvm/Object/Wasm.h @@ -149,6 +149,7 @@ public: ArrayRef elements() const { return ElemSegments; } ArrayRef dataSegments() const { return DataSegments; } ArrayRef functions() const { return Functions; } + ArrayRef comdats() const { return Comdats; } uint32_t startFunction() const { return StartFunction; } void moveSymbolNext(DataRefImpl &Symb) const override; @@ -232,6 +233,7 @@ private: // Custom section types Error parseNameSection(const uint8_t *Ptr, const uint8_t *End); Error parseLinkingSection(const uint8_t *Ptr, const uint8_t *End); + Error parseLinkingSectionComdat(const uint8_t *&Ptr, const uint8_t *End); Error parseRelocSection(StringRef Name, const uint8_t *Ptr, const uint8_t *End); @@ -250,6 +252,7 @@ private: std::vector DataSegments; std::vector Functions; std::vector Symbols; + std::vector Comdats; uint32_t StartFunction = -1; bool HasLinkingSection = false; wasm::WasmLinkingData LinkingData; diff --git a/include/llvm/ObjectYAML/WasmYAML.h b/include/llvm/ObjectYAML/WasmYAML.h index dcc31fc1137..83040aa99a1 100644 --- a/include/llvm/ObjectYAML/WasmYAML.h +++ b/include/llvm/ObjectYAML/WasmYAML.h @@ -37,6 +37,7 @@ LLVM_YAML_STRONG_TYPEDEF(uint32_t, RelocType) LLVM_YAML_STRONG_TYPEDEF(uint32_t, SymbolFlags) LLVM_YAML_STRONG_TYPEDEF(uint32_t, SegmentFlags) LLVM_YAML_STRONG_TYPEDEF(uint32_t, LimitFlags) +LLVM_YAML_STRONG_TYPEDEF(uint32_t, ComdatKind) struct FileHeader { yaml::Hex32 Version; @@ -138,6 +139,16 @@ struct InitFunction { uint32_t FunctionIndex; }; +struct ComdatEntry { + ComdatKind Kind; + uint32_t Index; +}; + +struct Comdat { + StringRef Name; + std::vector Entries; +}; + struct Section { explicit Section(SectionType SecType) : Type(SecType) {} virtual ~Section(); @@ -181,6 +192,7 @@ struct LinkingSection : CustomSection { std::vector SymbolInfos; std::vector SegmentInfos; std::vector InitFunctions; + std::vector Comdats; }; struct TypeSection : Section { @@ -318,6 +330,8 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::NameEntry) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SegmentInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::SymbolInfo) LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::InitFunction) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::ComdatEntry) +LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Comdat) namespace llvm { namespace yaml { @@ -414,6 +428,18 @@ template <> struct MappingTraits { static void mapping(IO &IO, WasmYAML::InitFunction &Init); }; +template <> struct ScalarEnumerationTraits { + static void enumeration(IO &IO, WasmYAML::ComdatKind &Kind); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::ComdatEntry &ComdatEntry); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::Comdat &Comdat); +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, WasmYAML::ValueType &Type); }; diff --git a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp index 24d4baa31e1..bdc4bc0302b 100644 --- a/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ b/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -1254,15 +1254,17 @@ void TargetLoweringObjectFileCOFF::emitLinkerFlagsForGlobal( // Wasm //===----------------------------------------------------------------------===// -static void checkWasmComdat(const GlobalValue *GV) { +static const Comdat *getWasmComdat(const GlobalValue *GV) { const Comdat *C = GV->getComdat(); if (!C) - return; + return nullptr; - // TODO(sbc): At some point we may need COMDAT support but currently - // they are not supported. - report_fatal_error("WebAssembly doesn't support COMDATs, '" + C->getName() + - "' cannot be lowered."); + if (C->getSelectionKind() != Comdat::Any) + report_fatal_error("WebAssembly COMDATs only support " + "SelectionKind::Any, '" + C->getName() + "' cannot be " + "lowered."); + + return C; } static SectionKind getWasmKindForNamedSection(StringRef Name, SectionKind K) { @@ -1278,16 +1280,25 @@ static SectionKind getWasmKindForNamedSection(StringRef Name, SectionKind K) { MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal( const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const { StringRef Name = GO->getSection(); - checkWasmComdat(GO); + Kind = getWasmKindForNamedSection(Name, Kind); - return getContext().getWasmSection(Name, Kind); + + StringRef Group = ""; + if (const Comdat *C = getWasmComdat(GO)) { + Group = C->getName(); + } + + return getContext().getWasmSection(Name, Kind, Group, + MCContext::GenericSectionID); } static MCSectionWasm *selectWasmSectionForGlobal( MCContext &Ctx, const GlobalObject *GO, SectionKind Kind, Mangler &Mang, const TargetMachine &TM, bool EmitUniqueSection, unsigned *NextUniqueID) { StringRef Group = ""; - checkWasmComdat(GO); + if (const Comdat *C = getWasmComdat(GO)) { + Group = C->getName(); + } bool UniqueSectionNames = TM.getUniqueSectionNames(); SmallString<128> Name = getSectionPrefixForGlobal(Kind); diff --git a/lib/MC/WasmObjectWriter.cpp b/lib/MC/WasmObjectWriter.cpp index 37b12c63be4..e5099a83b6f 100644 --- a/lib/MC/WasmObjectWriter.cpp +++ b/lib/MC/WasmObjectWriter.cpp @@ -138,6 +138,14 @@ struct WasmGlobal { uint32_t ImportIndex; }; +// Information about a single item which is part of a COMDAT. For each data +// segment or function which is in the COMDAT, there is a corresponding +// WasmComdatEntry. +struct WasmComdatEntry { + unsigned Kind; + uint32_t Index; +}; + // Information about a single relocation. struct WasmRelocationEntry { uint64_t Offset; // Where is the relocation. @@ -284,8 +292,9 @@ private: void writeDataRelocSection(); void writeLinkingMetaDataSection( ArrayRef Segments, uint32_t DataSize, - const SmallVector, 4> &SymbolFlags, - const SmallVector, 2> &InitFuncs); + ArrayRef> SymbolFlags, + ArrayRef> InitFuncs, + const std::map>& Comdats); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef Relocations, @@ -913,8 +922,9 @@ void WasmObjectWriter::writeDataRelocSection() { void WasmObjectWriter::writeLinkingMetaDataSection( ArrayRef Segments, uint32_t DataSize, - const SmallVector, 4> &SymbolFlags, - const SmallVector, 2> &InitFuncs) { + ArrayRef> SymbolFlags, + ArrayRef> InitFuncs, + const std::map>& Comdats) { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); SectionBookkeeping SubSection; @@ -956,6 +966,21 @@ void WasmObjectWriter::writeLinkingMetaDataSection( endSection(SubSection); } + if (Comdats.size()) { + startSection(SubSection, wasm::WASM_COMDAT_INFO); + encodeULEB128(Comdats.size(), getStream()); + for (const auto &C : Comdats) { + writeString(C.first); + encodeULEB128(0, getStream()); // flags for future use + encodeULEB128(C.second.size(), getStream()); + for (const WasmComdatEntry &Entry : C.second) { + encodeULEB128(Entry.Kind, getStream()); + encodeULEB128(Entry.Index, getStream()); + } + } + endSection(SubSection); + } + endSection(Section); } @@ -997,6 +1022,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, SmallVector Exports; SmallVector, 4> SymbolFlags; SmallVector, 2> InitFuncs; + std::map> Comdats; unsigned NumFuncImports = 0; SmallVector DataSegments; uint32_t DataSize = 0; @@ -1143,6 +1169,12 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, Segment.Flags = 0; DataSize += Segment.Data.size(); Section.setMemoryOffset(Segment.Offset); + + if (const MCSymbolWasm *C = Section.getGroup()) { + Comdats[C->getName()].emplace_back( + WasmComdatEntry{wasm::WASM_COMDAT_DATA, + static_cast(DataSegments.size()) - 1}); + } } // Handle regular defined and undefined symbols. @@ -1216,6 +1248,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, // address. For externals these will also be named exports. Index = NumGlobalImports + Globals.size(); auto &DataSection = static_cast(WS.getSection()); + assert(DataSection.isWasmData()); WasmGlobal Global; Global.Type = PtrType; @@ -1239,8 +1272,16 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, Export.Kind = wasm::WASM_EXTERNAL_GLOBAL; DEBUG(dbgs() << " -> export " << Exports.size() << "\n"); Exports.push_back(Export); + if (!WS.isExternal()) SymbolFlags.emplace_back(WS.getName(), wasm::WASM_SYMBOL_BINDING_LOCAL); + + if (WS.isFunction()) { + auto &Section = static_cast(WS.getSection(false)); + if (const MCSymbolWasm *C = Section.getGroup()) + Comdats[C->getName()].emplace_back( + WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index}); + } } } @@ -1372,7 +1413,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, writeCodeRelocSection(); writeDataRelocSection(); writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags, - InitFuncs); + InitFuncs, Comdats); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp index c33f4f68694..ec2e2bfbb4d 100644 --- a/lib/Object/WasmObjectFile.cpp +++ b/lib/Object/WasmObjectFile.cpp @@ -10,6 +10,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" #include "llvm/BinaryFormat/Wasm.h" #include "llvm/MC/SubtargetFeature.h" @@ -422,6 +423,10 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, } break; } + case wasm::WASM_COMDAT_INFO: + if (Error Err = parseLinkingSectionComdat(Ptr, SubSectionEnd)) + return Err; + break; default: Ptr += Size; break; @@ -436,6 +441,55 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, return Error::success(); } +Error WasmObjectFile::parseLinkingSectionComdat(const uint8_t *&Ptr, + const uint8_t *End) +{ + uint32_t ComdatCount = readVaruint32(Ptr); + StringSet<> ComdatSet; + while (ComdatCount--) { + StringRef Name = readString(Ptr); + if (Name.empty() || !ComdatSet.insert(Name).second) + return make_error("Bad/duplicate COMDAT name " + Twine(Name), + object_error::parse_failed); + Comdats.emplace_back(Name); + uint32_t Flags = readVaruint32(Ptr); + if (Flags != 0) + return make_error("Unsupported COMDAT flags", + object_error::parse_failed); + + uint32_t EntryCount = readVaruint32(Ptr); + while (EntryCount--) { + unsigned Kind = readVaruint32(Ptr); + unsigned Index = readVaruint32(Ptr); + switch (Kind) { + default: + return make_error("Invalid COMDAT entry type", + object_error::parse_failed); + case wasm::WASM_COMDAT_DATA: + if (Index >= DataSegments.size()) + return make_error("COMDAT data index out of range", + object_error::parse_failed); + if (!DataSegments[Index].Data.Comdat.empty()) + return make_error("Data segment in two COMDATs", + object_error::parse_failed); + DataSegments[Index].Data.Comdat = Name; + break; + case wasm::WASM_COMDAT_FUNCTION: + if (Index < NumImportedFunctions || !isValidFunctionIndex(Index)) + return make_error("COMDAT function index out of range", + object_error::parse_failed); + Index -= NumImportedFunctions; + if (!Functions[Index].Comdat.empty()) + return make_error("Function in two COMDATs", + object_error::parse_failed); + Functions[Index].Comdat = Name; + break; + } + } + } + return Error::success(); +} + WasmSection* WasmObjectFile::findCustomSectionByName(StringRef Name) { for (WasmSection& Section : Sections) { if (Section.Type == wasm::WASM_SEC_CUSTOM && Section.Name == Name) diff --git a/lib/ObjectYAML/WasmYAML.cpp b/lib/ObjectYAML/WasmYAML.cpp index 70721e006da..4ae6dccccb1 100644 --- a/lib/ObjectYAML/WasmYAML.cpp +++ b/lib/ObjectYAML/WasmYAML.cpp @@ -61,6 +61,7 @@ static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) { IO.mapOptional("SymbolInfo", Section.SymbolInfos); IO.mapOptional("SegmentInfo", Section.SegmentInfos); IO.mapOptional("InitFunctions", Section.InitFunctions); + IO.mapOptional("Comdats", Section.Comdats); } static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) { @@ -368,6 +369,26 @@ void MappingTraits::mapping( IO.mapRequired("FunctionIndex", Init.FunctionIndex); } +void ScalarEnumerationTraits::enumeration( + IO &IO, WasmYAML::ComdatKind &Kind) { +#define ECase(X) IO.enumCase(Kind, #X, wasm::WASM_COMDAT_##X); + ECase(FUNCTION); + ECase(DATA); +#undef ECase +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::ComdatEntry &ComdatEntry) { + IO.mapRequired("Kind", ComdatEntry.Kind); + IO.mapRequired("Index", ComdatEntry.Index); +} + +void MappingTraits::mapping( + IO &IO, WasmYAML::Comdat &Comdat) { + IO.mapRequired("Name", Comdat.Name); + IO.mapRequired("Entries", Comdat.Entries); +} + void MappingTraits::mapping(IO &IO, WasmYAML::SymbolInfo &Info) { IO.mapRequired("Name", Info.Name); diff --git a/test/CodeGen/WebAssembly/comdat.ll b/test/CodeGen/WebAssembly/comdat.ll deleted file mode 100644 index 8aa1af8667a..00000000000 --- a/test/CodeGen/WebAssembly/comdat.ll +++ /dev/null @@ -1,5 +0,0 @@ -; RUN: not llc < %s -mtriple wasm32-unknown-unknown-wasm 2>&1 | FileCheck %s - -$f = comdat any -@f = global i32 0, comdat -; CHECK: LLVM ERROR: WebAssembly doesn't support COMDATs, 'f' cannot be lowered. diff --git a/test/MC/WebAssembly/comdat.ll b/test/MC/WebAssembly/comdat.ll new file mode 100644 index 00000000000..30ae9cadb2e --- /dev/null +++ b/test/MC/WebAssembly/comdat.ll @@ -0,0 +1,99 @@ +; RUN: llc -mtriple wasm32-unknown-unknown-wasm -filetype=obj %s -o - | obj2yaml | FileCheck %s + +; Import a function just so we can check the index arithmetic for +; WASM_COMDAT_FUNCTION entries is performed correctly +declare i32 @funcImport() +define i32 @callImport() { +entry: + %call = call i32 @funcImport() + ret i32 %call +} + +; Function in its own COMDAT +$basicInlineFn = comdat any +define linkonce_odr i32 @basicInlineFn() #1 comdat { + ret i32 0 +} + +; Global, data, and function in same COMDAT +$sharedComdat = comdat any +@constantData = weak_odr constant [3 x i8] c"abc", comdat($sharedComdat) +define linkonce_odr i32 @sharedFn() #1 comdat($sharedComdat) { + ret i32 0 +} + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: callImport +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: basicInlineFn +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: sharedFn +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: constantData +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Relocations: +; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x00000004 +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1080808080000B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41000B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41000B +; 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: '616263' +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: funcImport +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: callImport +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: basicInlineFn +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: sharedFn +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: linking +; CHECK-NEXT: DataSize: 3 +; CHECK-NEXT: SymbolInfo: +; CHECK-NEXT: - Name: basicInlineFn +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: - Name: sharedFn +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: - Name: constantData +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: SegmentInfo: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: .rodata.constantData +; CHECK-NEXT: Alignment: 1 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Comdats: +; CHECK-NEXT: - Name: basicInlineFn +; CHECK-NEXT: Entries: +; CHECK-NEXT: - Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: sharedComdat +; CHECK-NEXT: Entries: +; CHECK-NEXT: - Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Kind: DATA +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: ... diff --git a/tools/obj2yaml/wasm2yaml.cpp b/tools/obj2yaml/wasm2yaml.cpp index 476fb6c1de2..e3577d4ef4f 100644 --- a/tools/obj2yaml/wasm2yaml.cpp +++ b/tools/obj2yaml/wasm2yaml.cpp @@ -65,17 +65,34 @@ std::unique_ptr WasmDumper::dumpCustomSection(const Was CustomSec = std::move(NameSec); } else if (WasmSec.Name == "linking") { std::unique_ptr LinkingSec = make_unique(); - size_t Index = 0; + std::map ComdatIndexes; + for (StringRef ComdatName : Obj.comdats()) { + ComdatIndexes[ComdatName] = LinkingSec->Comdats.size(); + LinkingSec->Comdats.emplace_back(WasmYAML::Comdat{ComdatName, {}}); + } + for (auto &Func : Obj.functions()) { + if (!Func.Comdat.empty()) { + auto &Comdat = LinkingSec->Comdats[ComdatIndexes[Func.Comdat]]; + Comdat.Entries.emplace_back( + WasmYAML::ComdatEntry{wasm::WASM_COMDAT_FUNCTION, Func.Index}); + } + } + uint32_t SegmentIndex = 0; for (const object::WasmSegment &Segment : Obj.dataSegments()) { if (!Segment.Data.Name.empty()) { WasmYAML::SegmentInfo SegmentInfo; SegmentInfo.Name = Segment.Data.Name; - SegmentInfo.Index = Index; + SegmentInfo.Index = SegmentIndex; SegmentInfo.Alignment = Segment.Data.Alignment; SegmentInfo.Flags = Segment.Data.Flags; LinkingSec->SegmentInfos.push_back(SegmentInfo); } - Index++; + if (!Segment.Data.Comdat.empty()) { + auto &Comdat = LinkingSec->Comdats[ComdatIndexes[Segment.Data.Comdat]]; + Comdat.Entries.emplace_back( + WasmYAML::ComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex}); + } + SegmentIndex++; } for (const object::SymbolRef& Sym: Obj.symbols()) { const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym); diff --git a/tools/yaml2obj/yaml2wasm.cpp b/tools/yaml2obj/yaml2wasm.cpp index 7770622149c..5c3b2b996ba 100644 --- a/tools/yaml2obj/yaml2wasm.cpp +++ b/tools/yaml2obj/yaml2wasm.cpp @@ -175,6 +175,23 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &S } SubSection.Done(); } + + // COMDAT_INFO subsection + if (Section.Comdats.size()) { + encodeULEB128(wasm::WASM_COMDAT_INFO, OS); + encodeULEB128(Section.Comdats.size(), SubSection.GetStream()); + for (const auto &C : Section.Comdats) { + writeStringRef(C.Name, SubSection.GetStream()); + encodeULEB128(0, SubSection.GetStream()); // flags for future use + encodeULEB128(C.Entries.size(), SubSection.GetStream()); + for (const WasmYAML::ComdatEntry &Entry : C.Entries) { + encodeULEB128(Entry.Kind, SubSection.GetStream()); + encodeULEB128(Entry.Index, SubSection.GetStream()); + } + } + SubSection.Done(); + } + return 0; } -- 2.11.0