From 5ad4743ec695b0615bb16352060a716b2127e0ec Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 14 Dec 2017 21:10:03 +0000 Subject: [PATCH] [WebAssembly] Add support for init functions linking metadata Summary: This change lays the groundwork lowering of @llvm.global_ctors and @llvm.global_dtors for the wasm object format. Some parts of this patch are subset of: https://reviews.llvm.org/D40759 See https://github.com/WebAssembly/tool-conventions/issues/25 Subscribers: jfb, dschuff, jgravelle-google, aheejin, sunfish Differential Revision: https://reviews.llvm.org/D41208 llvm-svn=320742 --- llvm/include/llvm/BinaryFormat/Wasm.h | 7 +++++++ llvm/include/llvm/Object/Wasm.h | 1 + llvm/include/llvm/ObjectYAML/WasmYAML.h | 11 ++++++++++ llvm/lib/Object/WasmObjectFile.cpp | 21 ++++++++++++++++++- llvm/lib/ObjectYAML/WasmYAML.cpp | 7 +++++++ .../test/ObjectYAML/wasm/linking_section.yaml | 6 ++++++ llvm/tools/obj2yaml/wasm2yaml.cpp | 8 +++++-- llvm/tools/yaml2obj/yaml2wasm.cpp | 11 ++++++++++ 8 files changed, 69 insertions(+), 3 deletions(-) diff --git a/llvm/include/llvm/BinaryFormat/Wasm.h b/llvm/include/llvm/BinaryFormat/Wasm.h index f35c0852991..a21f28c4196 100644 --- a/llvm/include/llvm/BinaryFormat/Wasm.h +++ b/llvm/include/llvm/BinaryFormat/Wasm.h @@ -115,8 +115,14 @@ struct WasmRelocation { int64_t Addend; // A value to add to the symbol. }; +struct WasmInitFunc { + uint32_t Priority; + uint32_t FunctionIndex; +}; + struct WasmLinkingData { uint32_t DataSize; + std::vector InitFunctions; }; enum : unsigned { @@ -185,6 +191,7 @@ enum : unsigned { WASM_SYMBOL_INFO = 0x2, WASM_DATA_SIZE = 0x3, WASM_SEGMENT_INFO = 0x5, + WASM_INIT_FUNCS = 0x6, }; const unsigned WASM_SYMBOL_BINDING_MASK = 0x3; diff --git a/llvm/include/llvm/Object/Wasm.h b/llvm/include/llvm/Object/Wasm.h index 504f1b49031..e38b9437791 100644 --- a/llvm/include/llvm/Object/Wasm.h +++ b/llvm/include/llvm/Object/Wasm.h @@ -206,6 +206,7 @@ class WasmObjectFile : public ObjectFile { bool isRelocatableObject() const override; private: + bool isValidFunctionIndex(uint32_t Index) const; const WasmSection &getWasmSection(DataRefImpl Ref) const; const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; diff --git a/llvm/include/llvm/ObjectYAML/WasmYAML.h b/llvm/include/llvm/ObjectYAML/WasmYAML.h index cf796f156a9..188ce8e4449 100644 --- a/llvm/include/llvm/ObjectYAML/WasmYAML.h +++ b/llvm/include/llvm/ObjectYAML/WasmYAML.h @@ -131,6 +131,11 @@ struct SymbolInfo { SymbolFlags Flags; }; +struct InitFunction { + uint32_t Priority; + uint32_t FunctionIndex; +}; + struct Section { explicit Section(SectionType SecType) : Type(SecType) {} virtual ~Section(); @@ -173,6 +178,7 @@ struct LinkingSection : CustomSection { uint32_t DataSize; std::vector SymbolInfos; std::vector SegmentInfos; + std::vector InitFunctions; }; struct TypeSection : Section { @@ -309,6 +315,7 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::WasmYAML::Relocation) 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) namespace llvm { namespace yaml { @@ -401,6 +408,10 @@ template <> struct MappingTraits { static void mapping(IO &IO, WasmYAML::SymbolInfo &Info); }; +template <> struct MappingTraits { + static void mapping(IO &IO, WasmYAML::InitFunction &Init); +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, WasmYAML::ValueType &Type); }; diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 8d4c15abc7f..677fccc6299 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -398,6 +398,21 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, } break; } + case wasm::WASM_INIT_FUNCS: { + uint32_t Count = readVaruint32(Ptr); + LinkingData.InitFunctions.reserve(Count); + for (uint32_t i = 0; i < Count; i++) { + wasm::WasmInitFunc Init; + Init.Priority = readVaruint32(Ptr); + Init.FunctionIndex = readVaruint32(Ptr); + if (!isValidFunctionIndex(Init.FunctionIndex)) + return make_error("Invalid function index: " + + Twine(Init.FunctionIndex), + object_error::parse_failed); + LinkingData.InitFunctions.emplace_back(Init); + } + break; + } default: Ptr += Size; break; @@ -656,9 +671,13 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) return Error::success(); } +bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const { + return Index < FunctionTypes.size() + NumImportedFunctions; +} + Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) { StartFunction = readVaruint32(Ptr); - if (StartFunction >= FunctionTypes.size()) + if (!isValidFunctionIndex(StartFunction)) return make_error("Invalid start function", object_error::parse_failed); return Error::success(); diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index c206a682b83..8687f22949a 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -60,6 +60,7 @@ static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) { IO.mapRequired("DataSize", Section.DataSize); IO.mapOptional("SymbolInfo", Section.SymbolInfos); IO.mapOptional("SegmentInfo", Section.SegmentInfos); + IO.mapOptional("InitFunctions", Section.InitFunctions); } static void sectionMapping(IO &IO, WasmYAML::CustomSection &Section) { @@ -359,6 +360,12 @@ void MappingTraits::mapping( IO.mapRequired("Content", Segment.Content); } +void MappingTraits::mapping( + IO &IO, WasmYAML::InitFunction &Init) { + IO.mapRequired("Priority", Init.Priority); + IO.mapRequired("FunctionIndex", Init.FunctionIndex); +} + void MappingTraits::mapping(IO &IO, WasmYAML::SymbolInfo &Info) { IO.mapRequired("Name", Info.Name); diff --git a/llvm/test/ObjectYAML/wasm/linking_section.yaml b/llvm/test/ObjectYAML/wasm/linking_section.yaml index 3494a9adddc..e413bd3f1ea 100644 --- a/llvm/test/ObjectYAML/wasm/linking_section.yaml +++ b/llvm/test/ObjectYAML/wasm/linking_section.yaml @@ -41,6 +41,9 @@ Sections: Alignment: 2 Flags: [ ] Name: moredata + InitFunctions: + - Priority: 1 + FunctionIndex: 0 ... # CHECK: - Type: CUSTOM # CHECK-NEXT: Name: linking @@ -57,4 +60,7 @@ Sections: # CHECK-NEXT: Name: moredata # CHECK-NEXT: Alignment: 2 # CHECK-NEXT: Flags: [ ] +# CHECK-NEXT: InitFunctions: +# CHECK-NEXT: - Priority: 1 +# CHECK-NEXT: FunctionIndex: 0 # CHECK-NEXT: ... diff --git a/llvm/tools/obj2yaml/wasm2yaml.cpp b/llvm/tools/obj2yaml/wasm2yaml.cpp index 27398e5b00b..1bf8149493c 100644 --- a/llvm/tools/obj2yaml/wasm2yaml.cpp +++ b/llvm/tools/obj2yaml/wasm2yaml.cpp @@ -80,11 +80,15 @@ std::unique_ptr WasmDumper::dumpCustomSection(const Was for (const object::SymbolRef& Sym: Obj.symbols()) { const object::WasmSymbol Symbol = Obj.getWasmSymbol(Sym); if (Symbol.Flags != 0) { - WasmYAML::SymbolInfo Info = { Symbol.Name, Symbol.Flags }; - LinkingSec->SymbolInfos.push_back(Info); + WasmYAML::SymbolInfo Info{Symbol.Name, Symbol.Flags}; + LinkingSec->SymbolInfos.emplace_back(Info); } } LinkingSec->DataSize = Obj.linkingData().DataSize; + for (const wasm::WasmInitFunc &Func : Obj.linkingData().InitFunctions) { + WasmYAML::InitFunction F{Func.Priority, Func.FunctionIndex}; + LinkingSec->InitFunctions.emplace_back(F); + } CustomSec = std::move(LinkingSec); } else { CustomSec = make_unique(WasmSec.Name); diff --git a/llvm/tools/yaml2obj/yaml2wasm.cpp b/llvm/tools/yaml2obj/yaml2wasm.cpp index 3eae8727b60..792f7c108bc 100644 --- a/llvm/tools/yaml2obj/yaml2wasm.cpp +++ b/llvm/tools/yaml2obj/yaml2wasm.cpp @@ -162,6 +162,17 @@ int WasmWriter::writeSectionContent(raw_ostream &OS, WasmYAML::LinkingSection &S } SubSection.Done(); } + + // INIT_FUNCS subsection + if (Section.InitFunctions.size()) { + encodeULEB128(wasm::WASM_INIT_FUNCS, OS); + encodeULEB128(Section.InitFunctions.size(), SubSection.GetStream()); + for (const WasmYAML::InitFunction &Func : Section.InitFunctions) { + encodeULEB128(Func.Priority, SubSection.GetStream()); + encodeULEB128(Func.FunctionIndex, SubSection.GetStream()); + } + SubSection.Done(); + } return 0; }