Index: include/llvm/Object/Wasm.h =================================================================== --- include/llvm/Object/Wasm.h +++ include/llvm/Object/Wasm.h @@ -254,14 +254,14 @@ std::vector Symbols; std::vector Comdats; std::vector DebugNames; - uint32_t StartFunction = -1; + uint32_t StartFunction = (uint32_t)-1; bool HasLinkingSection = false; wasm::WasmLinkingData LinkingData; uint32_t NumImportedGlobals = 0; uint32_t NumImportedFunctions = 0; - uint32_t CodeSection = 0; - uint32_t DataSection = 0; - uint32_t GlobalSection = 0; + uint32_t CodeSection = (uint32_t)-1; + uint32_t DataSection = (uint32_t)-1; + uint32_t GlobalSection = (uint32_t)-1; }; } // end namespace object Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -1307,9 +1307,9 @@ writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); writeDataSection(); + writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); writeCodeRelocSection(); writeDataRelocSection(); - writeLinkingMetaDataSection(SymbolInfos, InitFuncs, Comdats); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. Index: lib/Object/WasmObjectFile.cpp =================================================================== --- lib/Object/WasmObjectFile.cpp +++ lib/Object/WasmObjectFile.cpp @@ -190,11 +190,102 @@ if (Ptr + Size > Eof) return make_error("Section too large", object_error::parse_failed); + if (Section.Type == wasm::WASM_SEC_CUSTOM) { + const uint8_t* NamePtr = Ptr; + Section.Name = readString(NamePtr); + if (NamePtr > Ptr + Size) + return make_error("Section name too large", + object_error::parse_failed); + } Section.Content = ArrayRef(Ptr, Size); Ptr += Size; return Error::success(); } +// For core Wasm sections, there is a defined order for all sections, and custom +// sections also (should) define where they fit into that order. We return -1 +// for custom sections whose order we don't know. +enum : unsigned { + // The order of standard sections is precisely given by the spec. + WASM_SEC_ORDER_TYPE = 10, + WASM_SEC_ORDER_IMPORT = 20, +// WASM_SEC_ORDER_EXCEPTION = 30, + WASM_SEC_ORDER_FUNCTION = 40, + WASM_SEC_ORDER_TABLE = 50, + WASM_SEC_ORDER_MEMORY = 60, + WASM_SEC_ORDER_GLOBAL = 70, + WASM_SEC_ORDER_EXPORT = 80, + WASM_SEC_ORDER_START = 90, + WASM_SEC_ORDER_ELEM = 100, + WASM_SEC_ORDER_CODE = 110, + WASM_SEC_ORDER_DATA = 120, + // "linking" requires DATA section in order to validate data symbols + WASM_SEC_ORDER_LINKING = 125, + // Spec: "name" MUST appear after DATA. Comes after "linking" to allow + // symbol table to set default function name. + WASM_SEC_ORDER_NAME = 130, + // Must come after "linking" in order to validate reloc indexes. + WASM_SEC_ORDER_RELOC = 135, +}; +static int getSectionOrder(const WasmSection &Sec) { + switch (Sec.Type) { + case wasm::WASM_SEC_CUSTOM: + if (Sec.Name == "linking") + return WASM_SEC_ORDER_LINKING; + if (Sec.Name.startswith("reloc.")) + return WASM_SEC_ORDER_RELOC; + if (Sec.Name == "name") + return WASM_SEC_ORDER_NAME; + return -1; + case wasm::WASM_SEC_TYPE: return WASM_SEC_ORDER_TYPE; + case wasm::WASM_SEC_IMPORT: return WASM_SEC_ORDER_IMPORT; +// case wasm::WASM_SEC_EXCEPTION: return WASM_SEC_ORDER_EXCEPTION; + case wasm::WASM_SEC_FUNCTION: return WASM_SEC_ORDER_FUNCTION; + case wasm::WASM_SEC_TABLE: return WASM_SEC_ORDER_TABLE; + case wasm::WASM_SEC_MEMORY: return WASM_SEC_ORDER_MEMORY; + case wasm::WASM_SEC_GLOBAL: return WASM_SEC_ORDER_GLOBAL; + case wasm::WASM_SEC_EXPORT: return WASM_SEC_ORDER_EXPORT; + case wasm::WASM_SEC_START: return WASM_SEC_ORDER_START; + case wasm::WASM_SEC_ELEM: return WASM_SEC_ORDER_ELEM; + case wasm::WASM_SEC_CODE: return WASM_SEC_ORDER_CODE; + case wasm::WASM_SEC_DATA: return WASM_SEC_ORDER_DATA; + default: + llvm_unreachable("invalid section"); + } +} + +static Error checkCodeSection(WasmObjectFile *Object) { + if (Object->functionTypes().size() != Object->functions().size()) + return make_error("Expected CODE section", + object_error::parse_failed); + return Error::success(); +} + +static Error checkSectionOrder(const WasmSection &Section, int &LastSecOrder, + WasmObjectFile *Object) { + int SecOrder = getSectionOrder(Section); + if (SecOrder != -1) { + // Disallow duplicate sections (except for "reloc.") as well as + // out-of-order sections. + if (SecOrder < LastSecOrder || + (SecOrder != (int)WASM_SEC_ORDER_RELOC && SecOrder == LastSecOrder)) + return make_error("Illegal section order", + object_error::parse_failed); + // If an empty FUNCTION section is present, there's no need for an empty + // CODE section to match, the vectors just have to be the same length. + // We must check the CODE section was present if required after skipping + // past it. + if (LastSecOrder < (int)WASM_SEC_ORDER_CODE && + SecOrder > (int)WASM_SEC_ORDER_CODE) { + if (Error Err = checkCodeSection(Object)) + return Err; + } + + LastSecOrder = SecOrder; + } + return Error::success(); +} + WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) : ObjectFile(Binary::ID_Wasm, Buffer) { ErrorAsOutParameter ErrAsOutParam(&Err); @@ -222,14 +313,20 @@ } WasmSection Sec; + int LastSecOrder = 0; while (Ptr < Eof) { if ((Err = readSection(Sec, Ptr, getPtr(0), Eof))) return; + if ((Err = checkSectionOrder(Sec, LastSecOrder, this))) + return; if ((Err = parseSection(Sec))) return; Sections.push_back(Sec); } + + if ((Err = checkCodeSection(this))) + return; } Error WasmObjectFile::parseSection(WasmSection &Sec) { @@ -268,11 +365,6 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { llvm::DenseSet Seen; - if (Functions.size() != FunctionTypes.size()) { - return make_error("Names must come after code section", - object_error::parse_failed); - } - while (Ptr < End) { uint8_t Type = readVarint7(Ptr); uint32_t Size = readVaruint32(Ptr); @@ -318,11 +410,6 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, const uint8_t *End) { HasLinkingSection = true; - if (Functions.size() != FunctionTypes.size()) { - return make_error( - "Linking data must come after code section", object_error::parse_failed); - } - while (Ptr < End) { uint8_t Type = readVarint7(Ptr); uint32_t Size = readVaruint32(Ptr); @@ -593,7 +680,7 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, const uint8_t *Ptr, const uint8_t *End) { - Sec.Name = readString(Ptr); + Ptr = Sec.Name.bytes_end(); if (Sec.Name == "name") { if (Error Err = parseNameSection(Ptr, End)) return Err; @@ -682,8 +769,13 @@ Error WasmObjectFile::parseFunctionSection(const uint8_t *Ptr, const uint8_t *End) { uint32_t Count = readVaruint32(Ptr); FunctionTypes.reserve(Count); + uint32_t MaxType = Signatures.size(); while (Count--) { - FunctionTypes.push_back(readVaruint32(Ptr)); + uint32_t Type = readVaruint32(Ptr); + if (Type >= MaxType) + return make_error("Invalid function type index", + object_error::parse_failed); + FunctionTypes.push_back(Type); } if (Ptr != End) return make_error("Function section ended prematurely", Index: test/ObjectYAML/wasm/export_section.yaml =================================================================== --- test/ObjectYAML/wasm/export_section.yaml +++ test/ObjectYAML/wasm/export_section.yaml @@ -3,6 +3,11 @@ FileHeader: Version: 0x00000001 Sections: + - Type: TYPE + Signatures: + - Index: 0 + ReturnType: NORESULT + ParamTypes: - Type: FUNCTION FunctionTypes: [ 0, 0 ] - Type: GLOBAL @@ -33,6 +38,14 @@ - Name: table_export Kind: TABLE Index: 0 + - Type: CODE + Functions: + - Index: 0 + Locals: + Body: 0B + - Index: 1 + Locals: + Body: 0B ... # CHECK: --- !WASM # CHECK: FileHeader: Index: test/ObjectYAML/wasm/function_section.yaml =================================================================== --- test/ObjectYAML/wasm/function_section.yaml +++ test/ObjectYAML/wasm/function_section.yaml @@ -3,8 +3,25 @@ FileHeader: Version: 0x00000001 Sections: + - Type: TYPE + Signatures: + - Index: 0 + ReturnType: NORESULT + ParamTypes: + - Index: 1 + ReturnType: NORESULT + ParamTypes: + - I32 - Type: FUNCTION FunctionTypes: [ 1, 0 ] + - Type: CODE + Functions: + - Index: 0 + Locals: + Body: 0B + - Index: 1 + Locals: + Body: 0B ... # CHECK: --- !WASM # CHECK: FileHeader: Index: test/ObjectYAML/wasm/start_section.yaml =================================================================== --- test/ObjectYAML/wasm/start_section.yaml +++ test/ObjectYAML/wasm/start_section.yaml @@ -7,14 +7,23 @@ - Type: TYPE Signatures: - Index: 0 - ReturnType: I32 + ReturnType: NORESULT ParamTypes: - - F32 - - F32 - Type: FUNCTION FunctionTypes: [ 0, 0, 0 ] - Type: START StartFunction: 1 + - Type: CODE + Functions: + - Index: 0 + Locals: + Body: 0B + - Index: 1 + Locals: + Body: 0B + - Index: 2 + Locals: + Body: 0B ... # CHECK: --- !WASM # CHECK: FileHeader: Index: test/tools/llvm-objdump/wasm.txt =================================================================== --- test/tools/llvm-objdump/wasm.txt +++ test/tools/llvm-objdump/wasm.txt @@ -7,8 +7,8 @@ # CHECK-NEXT: 2 FUNCTION 00000002 0000000000000000 # CHECK-NEXT: 3 CODE 00000019 0000000000000000 TEXT # CHECK-NEXT: 4 DATA 0000001c 0000000000000000 DATA -# CHECK-NEXT: 5 reloc.CODE 00000017 0000000000000000 -# CHECK-NEXT: 6 linking 00000055 0000000000000000 +# CHECK-NEXT: 5 linking 00000055 0000000000000000 +# CHECK-NEXT: 6 reloc.CODE 00000017 0000000000000000 # RUN: llvm-objdump -p %p/Inputs/trivial.obj.wasm | FileCheck %s -check-prefix CHECK-HEADER Index: test/tools/llvm-readobj/sections.test =================================================================== --- test/tools/llvm-readobj/sections.test +++ test/tools/llvm-readobj/sections.test @@ -528,14 +528,14 @@ WASM-NEXT: } WASM-NEXT: Section { WASM-NEXT: Type: CUSTOM (0x0) -WASM-NEXT: Size: 23 +WASM-NEXT: Size: 65 WASM-NEXT: Offset: 191 -WASM-NEXT: Name: reloc.CODE +WASM-NEXT: Name: linking WASM-NEXT: } WASM-NEXT: Section { WASM-NEXT: Type: CUSTOM (0x0) -WASM-NEXT: Size: 65 -WASM-NEXT: Offset: 220 -WASM-NEXT: Name: linking +WASM-NEXT: Size: 23 +WASM-NEXT: Offset: 262 +WASM-NEXT: Name: reloc.CODE WASM-NEXT: } WASM-NEXT: ]