diff options
Diffstat (limited to 'lib/Object/WasmObjectFile.cpp')
-rw-r--r-- | lib/Object/WasmObjectFile.cpp | 202 |
1 files changed, 143 insertions, 59 deletions
diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp index 7f80bf0b83a0..7a0c05ed8a15 100644 --- a/lib/Object/WasmObjectFile.cpp +++ b/lib/Object/WasmObjectFile.cpp @@ -178,14 +178,16 @@ static wasm::WasmTable readTable(const uint8_t *&Ptr) { } static Error readSection(WasmSection &Section, const uint8_t *&Ptr, - const uint8_t *Start) { - // TODO(sbc): Avoid reading past EOF in the case of malformed files. + const uint8_t *Start, const uint8_t *Eof) { Section.Offset = Ptr - Start; Section.Type = readVaruint7(Ptr); uint32_t Size = readVaruint32(Ptr); if (Size == 0) return make_error<StringError>("Zero length section", object_error::parse_failed); + if (Ptr + Size > Eof) + return make_error<StringError>("Section too large", + object_error::parse_failed); Section.Content = ArrayRef<uint8_t>(Ptr, Size); Ptr += Size; return Error::success(); @@ -193,7 +195,6 @@ static Error readSection(WasmSection &Section, const uint8_t *&Ptr, WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) : ObjectFile(Binary::ID_Wasm, Buffer) { - LinkingData.DataAlignment = 0; LinkingData.DataSize = 0; ErrorAsOutParameter ErrAsOutParam(&Err); @@ -203,7 +204,16 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) object_error::parse_failed); return; } + + const uint8_t *Eof = getPtr(getData().size()); const uint8_t *Ptr = getPtr(4); + + if (Ptr + 4 > Eof) { + Err = make_error<StringError>("Missing version number", + object_error::parse_failed); + return; + } + Header.Version = readUint32(Ptr); if (Header.Version != wasm::WasmVersion) { Err = make_error<StringError>("Bad version number", @@ -211,10 +221,9 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) return; } - const uint8_t *Eof = getPtr(getData().size()); WasmSection Sec; while (Ptr < Eof) { - if ((Err = readSection(Sec, Ptr, getPtr(0)))) + if ((Err = readSection(Sec, Ptr, getPtr(0), Eof))) return; if ((Err = parseSection(Sec))) return; @@ -292,9 +301,61 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { return Error::success(); } +void WasmObjectFile::populateSymbolTable() { + // Add imports to symbol table + size_t ImportIndex = 0; + size_t GlobalIndex = 0; + size_t FunctionIndex = 0; + for (const wasm::WasmImport& Import : Imports) { + switch (Import.Kind) { + case wasm::WASM_EXTERNAL_GLOBAL: + assert(Import.Global.Type == wasm::WASM_TYPE_I32); + SymbolMap.try_emplace(Import.Field, Symbols.size()); + Symbols.emplace_back(Import.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT, + ImportSection, GlobalIndex++, ImportIndex); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); + break; + case wasm::WASM_EXTERNAL_FUNCTION: + SymbolMap.try_emplace(Import.Field, Symbols.size()); + Symbols.emplace_back(Import.Field, + WasmSymbol::SymbolType::FUNCTION_IMPORT, + ImportSection, FunctionIndex++, ImportIndex); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); + break; + default: + break; + } + ImportIndex++; + } + + // Add exports to symbol table + for (const wasm::WasmExport& Export : Exports) { + if (Export.Kind == wasm::WASM_EXTERNAL_FUNCTION || + Export.Kind == wasm::WASM_EXTERNAL_GLOBAL) { + WasmSymbol::SymbolType ExportType = + Export.Kind == wasm::WASM_EXTERNAL_FUNCTION + ? WasmSymbol::SymbolType::FUNCTION_EXPORT + : WasmSymbol::SymbolType::GLOBAL_EXPORT; + SymbolMap.try_emplace(Export.Name, Symbols.size()); + Symbols.emplace_back(Export.Name, ExportType, + ExportSection, Export.Index); + DEBUG(dbgs() << "Adding export: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); + } + } +} + Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, const uint8_t *End) { HasLinkingSection = true; + + // Only populate the symbol table with imports and exports if the object + // has a linking section (i.e. its a relocatable object file). Otherwise + // the global might not represent symbols at all. + populateSymbolTable(); + while (Ptr < End) { uint8_t Type = readVarint7(Ptr); uint32_t Size = readVaruint32(Ptr); @@ -317,7 +378,7 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, Symbols[SymIndex].Flags = Flags; DEBUG(dbgs() << "Set symbol flags index:" << SymIndex << " name:" - << Symbols[SymIndex].Name << " exptected:" + << Symbols[SymIndex].Name << " expected:" << Symbol << " flags: " << Flags << "\n"); } break; @@ -325,10 +386,33 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, case wasm::WASM_DATA_SIZE: LinkingData.DataSize = readVaruint32(Ptr); break; - case wasm::WASM_DATA_ALIGNMENT: - LinkingData.DataAlignment = readVaruint32(Ptr); + case wasm::WASM_SEGMENT_INFO: { + uint32_t Count = readVaruint32(Ptr); + if (Count > DataSegments.size()) + return make_error<GenericBinaryError>("Too many segment names", + object_error::parse_failed); + for (uint32_t i = 0; i < Count; i++) { + DataSegments[i].Data.Name = readString(Ptr); + DataSegments[i].Data.Alignment = readVaruint32(Ptr); + DataSegments[i].Data.Flags = readVaruint32(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<GenericBinaryError>("Invalid function index: " + + Twine(Init.FunctionIndex), + object_error::parse_failed); + LinkingData.InitFunctions.emplace_back(Init); + } break; - case wasm::WASM_STACK_POINTER: + } default: Ptr += Size; break; @@ -387,9 +471,9 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: break; - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: Reloc.Addend = readVarint32(Ptr); break; default: @@ -455,6 +539,7 @@ Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, const uint8_t *End) { } Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) { + ImportSection = Sections.size(); uint32_t Count = readVaruint32(Ptr); Imports.reserve(Count); for (uint32_t i = 0; i < Count; i++) { @@ -464,31 +549,22 @@ Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) Im.Kind = readUint8(Ptr); switch (Im.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: + NumImportedFunctions++; Im.SigIndex = readVaruint32(Ptr); - SymbolMap.try_emplace(Im.Field, Symbols.size()); - Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::FUNCTION_IMPORT, - Sections.size(), i); - DEBUG(dbgs() << "Adding import: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_GLOBAL: + NumImportedGlobals++; Im.Global.Type = readVarint7(Ptr); Im.Global.Mutable = readVaruint1(Ptr); - SymbolMap.try_emplace(Im.Field, Symbols.size()); - Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT, - Sections.size(), i); - DEBUG(dbgs() << "Adding import: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_MEMORY: Im.Memory = readLimits(Ptr); break; case wasm::WASM_EXTERNAL_TABLE: Im.Table = readTable(Ptr); - if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC) { + if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC) return make_error<GenericBinaryError>("Invalid table element type", object_error::parse_failed); - } break; default: return make_error<GenericBinaryError>( @@ -560,6 +636,7 @@ Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) } Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) { + ExportSection = Sections.size(); uint32_t Count = readVaruint32(Ptr); Exports.reserve(Count); for (uint32_t i = 0; i < Count; i++) { @@ -567,17 +644,18 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) Ex.Name = readString(Ptr); Ex.Kind = readUint8(Ptr); Ex.Index = readVaruint32(Ptr); - WasmSymbol::SymbolType ExportType; - bool MakeSymbol = false; switch (Ex.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: - ExportType = WasmSymbol::SymbolType::FUNCTION_EXPORT; - MakeSymbol = true; + if (Ex.Index >= FunctionTypes.size() + NumImportedFunctions) + return make_error<GenericBinaryError>("Invalid function export", + object_error::parse_failed); break; - case wasm::WASM_EXTERNAL_GLOBAL: - ExportType = WasmSymbol::SymbolType::GLOBAL_EXPORT; - MakeSymbol = true; + case wasm::WASM_EXTERNAL_GLOBAL: { + if (Ex.Index >= Globals.size() + NumImportedGlobals) + return make_error<GenericBinaryError>("Invalid global export", + object_error::parse_failed); break; + } case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_TABLE: break; @@ -585,20 +663,6 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) return make_error<GenericBinaryError>( "Unexpected export kind", object_error::parse_failed); } - if (MakeSymbol) { - auto Pair = SymbolMap.try_emplace(Ex.Name, Symbols.size()); - if (Pair.second) { - Symbols.emplace_back(Ex.Name, ExportType, - Sections.size(), i); - DEBUG(dbgs() << "Adding export: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); - } else { - uint32_t SymIndex = Pair.first->second; - Symbols[SymIndex] = WasmSymbol(Ex.Name, ExportType, Sections.size(), i); - DEBUG(dbgs() << "Replacing existing symbol: " << Symbols[SymIndex] - << " sym index:" << SymIndex << "\n"); - } - } Exports.push_back(Ex); } if (Ptr != End) @@ -607,27 +671,34 @@ 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<GenericBinaryError>("Invalid start function", object_error::parse_failed); return Error::success(); } Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) { + const uint8_t *CodeSectionStart = Ptr; uint32_t FunctionCount = readVaruint32(Ptr); if (FunctionCount != FunctionTypes.size()) { return make_error<GenericBinaryError>("Invalid function count", object_error::parse_failed); } - CodeSection = ArrayRef<uint8_t>(Ptr, End - Ptr); - while (FunctionCount--) { wasm::WasmFunction Function; - uint32_t FunctionSize = readVaruint32(Ptr); - const uint8_t *FunctionEnd = Ptr + FunctionSize; + const uint8_t *FunctionStart = Ptr; + uint32_t Size = readVaruint32(Ptr); + const uint8_t *FunctionEnd = Ptr + Size; + + Function.CodeSectionOffset = FunctionStart - CodeSectionStart; + Function.Size = FunctionEnd - FunctionStart; uint32_t NumLocalDecls = readVaruint32(Ptr); Function.Locals.reserve(NumLocalDecls); @@ -685,6 +756,8 @@ Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) { return Err; uint32_t Size = readVaruint32(Ptr); Segment.Data.Content = ArrayRef<uint8_t>(Ptr, Size); + Segment.Data.Alignment = 0; + Segment.Data.Flags = 0; Segment.SectionOffset = Ptr - Start; Ptr += Size; DataSegments.push_back(Segment); @@ -710,15 +783,19 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { const WasmSymbol &Sym = getWasmSymbol(Symb); DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n"); - if (Sym.Flags & wasm::WASM_SYMBOL_FLAG_WEAK) + if (Sym.isWeak()) Result |= SymbolRef::SF_Weak; + if (!Sym.isLocal()) + Result |= SymbolRef::SF_Global; + if (Sym.isHidden()) + Result |= SymbolRef::SF_Hidden; switch (Sym.Type) { case WasmSymbol::SymbolType::FUNCTION_IMPORT: Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable; break; case WasmSymbol::SymbolType::FUNCTION_EXPORT: - Result |= SymbolRef::SF_Global | SymbolRef::SF_Executable; + Result |= SymbolRef::SF_Executable; break; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: Result |= SymbolRef::SF_Executable; @@ -728,7 +805,6 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { Result |= SymbolRef::SF_Undefined; break; case WasmSymbol::SymbolType::GLOBAL_EXPORT: - Result |= SymbolRef::SF_Global; break; } @@ -763,21 +839,29 @@ Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { return getSymbolValue(Symb); } -uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { - const WasmSymbol& Sym = getWasmSymbol(Symb); +uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const { switch (Sym.Type) { case WasmSymbol::SymbolType::FUNCTION_IMPORT: case WasmSymbol::SymbolType::GLOBAL_IMPORT: - return 0; case WasmSymbol::SymbolType::FUNCTION_EXPORT: - case WasmSymbol::SymbolType::GLOBAL_EXPORT: - return Exports[Sym.ElementIndex].Index; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: return Sym.ElementIndex; + case WasmSymbol::SymbolType::GLOBAL_EXPORT: { + uint32_t GlobalIndex = Sym.ElementIndex - NumImportedGlobals; + assert(GlobalIndex < Globals.size()); + const wasm::WasmGlobal& Global = Globals[GlobalIndex]; + // WasmSymbols correspond only to I32_CONST globals + assert(Global.InitExpr.Opcode == wasm::WASM_OPCODE_I32_CONST); + return Global.InitExpr.Value.Int32; + } } llvm_unreachable("invalid symbol type"); } +uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + return getWasmSymbolValue(getWasmSymbol(Symb)); +} + uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { llvm_unreachable("not yet implemented"); return 0; @@ -957,7 +1041,7 @@ uint8_t WasmObjectFile::getBytesInAddress() const { return 4; } StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; } -unsigned WasmObjectFile::getArch() const { return Triple::wasm32; } +Triple::ArchType WasmObjectFile::getArch() const { return Triple::wasm32; } SubtargetFeatures WasmObjectFile::getFeatures() const { return SubtargetFeatures(); |