diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/MC/MCWasmStreamer.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/MC/WasmObjectWriter.cpp | 292 | ||||
-rw-r--r-- | llvm/lib/Object/WasmObjectFile.cpp | 304 | ||||
-rw-r--r-- | llvm/lib/ObjectYAML/WasmYAML.cpp | 29 | ||||
-rw-r--r-- | llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp | 17 |
6 files changed, 371 insertions, 277 deletions
diff --git a/llvm/lib/MC/MCWasmStreamer.cpp b/llvm/lib/MC/MCWasmStreamer.cpp index 611e29c7214..2c77624b685 100644 --- a/llvm/lib/MC/MCWasmStreamer.cpp +++ b/llvm/lib/MC/MCWasmStreamer.cpp @@ -113,11 +113,11 @@ bool MCWasmStreamer::EmitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) { break; case MCSA_ELF_TypeFunction: - Symbol->setIsFunction(true); + Symbol->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); break; case MCSA_ELF_TypeObject: - Symbol->setIsFunction(false); + Symbol->setType(wasm::WASM_SYMBOL_TYPE_DATA); break; default: diff --git a/llvm/lib/MC/WasmObjectWriter.cpp b/llvm/lib/MC/WasmObjectWriter.cpp index c47c014467a..1f1132aae49 100644 --- a/llvm/lib/MC/WasmObjectWriter.cpp +++ b/llvm/lib/MC/WasmObjectWriter.cpp @@ -190,13 +190,18 @@ class WasmObjectWriter : public MCObjectWriter { // Maps function symbols to the table element index space. Used // for TABLE_INDEX relocation types (i.e. address taken functions). DenseMap<const MCSymbolWasm *, uint32_t> TableIndices; - // Maps function/global symbols to the function/global index space. + // Maps function/global symbols to the (shared) Symbol index space. DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices; + // Maps function/global symbols to the function/global Wasm index space. + DenseMap<const MCSymbolWasm *, uint32_t> WasmIndices; + // Maps data symbols to the Wasm segment and offset/size with the segment. + DenseMap<const MCSymbolWasm *, wasm::WasmDataReference> DataLocations; DenseMap<WasmFunctionType, int32_t, WasmFunctionTypeDenseMapInfo> FunctionTypeIndices; SmallVector<WasmFunctionType, 4> FunctionTypes; SmallVector<WasmGlobal, 4> Globals; + SmallVector<WasmDataSegment, 4> DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; @@ -224,10 +229,13 @@ private: DataRelocations.clear(); TypeIndices.clear(); SymbolIndices.clear(); + WasmIndices.clear(); TableIndices.clear(); + DataLocations.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); Globals.clear(); + DataSegments.clear(); MCObjectWriter::reset(); NumFunctionImports = 0; NumGlobalImports = 0; @@ -262,14 +270,13 @@ private: void writeElemSection(ArrayRef<uint32_t> TableElems); void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef<WasmFunction> Functions); - void writeDataSection(ArrayRef<WasmDataSegment> Segments); + void writeDataSection(); void writeCodeRelocSection(); void writeDataRelocSection(); void writeLinkingMetaDataSection( - ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, - ArrayRef<std::pair<StringRef, uint32_t>> SymbolFlags, + uint32_t DataSize, ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, - const std::map<StringRef, std::vector<WasmComdatEntry>>& Comdats); + const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats); uint32_t getProvisionalValue(const WasmRelocationEntry &RelEntry); void applyRelocations(ArrayRef<WasmRelocationEntry> Relocations, @@ -494,11 +501,16 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { assert(Sym->isFunction()); return TableIndices[Sym]; } - case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - // Provisional value is function/type/global index itself + // Provisional value is same as the index return getRelocationIndexValue(RelEntry); + case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + // Provisional value is function/global Wasm index + if (!WasmIndices.count(RelEntry.Symbol)) + report_fatal_error("symbol not found in wasm index space: " + + RelEntry.Symbol->getName()); + return WasmIndices[RelEntry.Symbol]; case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: { @@ -507,16 +519,10 @@ WasmObjectWriter::getProvisionalValue(const WasmRelocationEntry &RelEntry) { // For undefined symbols, use zero if (!Sym->isDefined()) return 0; - - if (!SymbolIndices.count(Sym)) - report_fatal_error("symbol not found in function/global index space: " + - Sym->getName()); - uint32_t GlobalIndex = SymbolIndices[Sym]; - const WasmGlobal& Global = Globals[GlobalIndex - NumGlobalImports]; - uint64_t Address = Global.InitialValue + RelEntry.Addend; - + const wasm::WasmDataReference &Ref = DataLocations[Sym]; + const WasmDataSegment &Segment = DataSegments[Ref.Segment]; // Ignore overflow. LLVM allows address arithmetic to silently wrap. - return Address; + return Segment.Offset + Ref.Offset + RelEntry.Addend; } default: llvm_unreachable("invalid relocation type"); @@ -529,7 +535,6 @@ static void addData(SmallVectorImpl<char> &DataBytes, DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment())); - size_t LastFragmentSize = 0; for (const MCFragment &Frag : DataSection) { if (Frag.hasInstructions()) report_fatal_error("only data supported in data sections"); @@ -554,16 +559,9 @@ static void addData(SmallVectorImpl<char> &DataBytes, const SmallVectorImpl<char> &Contents = DataFrag.getContents(); DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end()); - LastFragmentSize = Contents.size(); } } - // Don't allow empty segments, or segments that end with zero-sized - // fragment, otherwise the linker cannot map symbols to a unique - // data segment. This can be triggered by zero-sized structs - // See: test/MC/WebAssembly/bss.ll - if (LastFragmentSize == 0) - DataBytes.resize(DataBytes.size() + 1); DEBUG(dbgs() << "addData -> " << DataBytes.size() << "\n"); } @@ -577,7 +575,7 @@ WasmObjectWriter::getRelocationIndexValue(const WasmRelocationEntry &RelEntry) { } if (!SymbolIndices.count(RelEntry.Symbol)) - report_fatal_error("symbol not found in function/global index space: " + + report_fatal_error("symbol not found in symbol index space: " + RelEntry.Symbol->getName()); return SymbolIndices[RelEntry.Symbol]; } @@ -802,16 +800,16 @@ void WasmObjectWriter::writeCodeSection(const MCAssembler &Asm, endSection(Section); } -void WasmObjectWriter::writeDataSection(ArrayRef<WasmDataSegment> Segments) { - if (Segments.empty()) +void WasmObjectWriter::writeDataSection() { + if (DataSegments.empty()) return; SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_DATA); - encodeULEB128(Segments.size(), getStream()); // count + encodeULEB128(DataSegments.size(), getStream()); // count - for (const WasmDataSegment & Segment : Segments) { + for (const WasmDataSegment &Segment : DataSegments) { encodeULEB128(0, getStream()); // memory index write8(wasm::WASM_OPCODE_I32_CONST); encodeSLEB128(Segment.Offset, getStream()); // offset @@ -864,20 +862,37 @@ void WasmObjectWriter::writeDataRelocSection() { } void WasmObjectWriter::writeLinkingMetaDataSection( - ArrayRef<WasmDataSegment> Segments, uint32_t DataSize, - ArrayRef<std::pair<StringRef, uint32_t>> SymbolFlags, + uint32_t DataSize, ArrayRef<wasm::WasmSymbolInfo> SymbolInfos, ArrayRef<std::pair<uint16_t, uint32_t>> InitFuncs, - const std::map<StringRef, std::vector<WasmComdatEntry>>& Comdats) { + const std::map<StringRef, std::vector<WasmComdatEntry>> &Comdats) { SectionBookkeeping Section; startSection(Section, wasm::WASM_SEC_CUSTOM, "linking"); SectionBookkeeping SubSection; - if (SymbolFlags.size() != 0) { - startSection(SubSection, wasm::WASM_SYMBOL_INFO); - encodeULEB128(SymbolFlags.size(), getStream()); - for (auto Pair: SymbolFlags) { - writeString(Pair.first); - encodeULEB128(Pair.second, getStream()); + if (SymbolInfos.size() != 0) { + startSection(SubSection, wasm::WASM_SYMBOL_TABLE); + encodeULEB128(SymbolInfos.size(), getStream()); + for (const wasm::WasmSymbolInfo &Sym : SymbolInfos) { + encodeULEB128(Sym.Kind, getStream()); + encodeULEB128(Sym.Flags, getStream()); + switch (Sym.Kind) { + case wasm::WASM_SYMBOL_TYPE_FUNCTION: + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + encodeULEB128(Sym.ElementIndex, getStream()); + if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) + writeString(Sym.Name); + break; + case wasm::WASM_SYMBOL_TYPE_DATA: + writeString(Sym.Name); + if ((Sym.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { + encodeULEB128(Sym.DataRef.Segment, getStream()); + encodeULEB128(Sym.DataRef.Offset, getStream()); + encodeULEB128(Sym.DataRef.Size, getStream()); + } + break; + default: + llvm_unreachable("unexpected kind"); + } } endSection(SubSection); } @@ -888,10 +903,10 @@ void WasmObjectWriter::writeLinkingMetaDataSection( endSection(SubSection); } - if (Segments.size()) { + if (DataSegments.size()) { startSection(SubSection, wasm::WASM_SEGMENT_INFO); - encodeULEB128(Segments.size(), getStream()); - for (const WasmDataSegment &Segment : Segments) { + encodeULEB128(DataSegments.size(), getStream()); + for (const WasmDataSegment &Segment : DataSegments) { writeString(Segment.Name); encodeULEB128(Segment.Alignment, getStream()); encodeULEB128(Segment.Flags, getStream()); @@ -956,19 +971,41 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); MCContext &Ctx = Asm.getContext(); - int32_t PtrType = is64Bit() ? wasm::WASM_TYPE_I64 : wasm::WASM_TYPE_I32; // Collect information from the available symbols. SmallVector<WasmFunction, 4> Functions; SmallVector<uint32_t, 4> TableElems; SmallVector<wasm::WasmImport, 4> Imports; SmallVector<wasm::WasmExport, 4> Exports; - SmallVector<std::pair<StringRef, uint32_t>, 4> SymbolFlags; + SmallVector<wasm::WasmSymbolInfo, 4> SymbolInfos; SmallVector<std::pair<uint16_t, uint32_t>, 2> InitFuncs; std::map<StringRef, std::vector<WasmComdatEntry>> Comdats; - SmallVector<WasmDataSegment, 4> DataSegments; + unsigned NumSymbols = 0; uint32_t DataSize = 0; + auto AddSymbol = [&](const MCSymbolWasm &WS) { + uint32_t Flags = 0; + if (WS.isWeak()) + Flags |= wasm::WASM_SYMBOL_BINDING_WEAK; + if (WS.isHidden()) + Flags |= wasm::WASM_SYMBOL_VISIBILITY_HIDDEN; + if (!WS.isExternal() && WS.isDefined()) + Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; + if (WS.isUndefined()) + Flags |= wasm::WASM_SYMBOL_UNDEFINED; + + wasm::WasmSymbolInfo Info; + Info.Name = WS.getName(); + Info.Kind = WS.getType(); + Info.Flags = Flags; + if (!WS.isData()) + Info.ElementIndex = WasmIndices[&WS]; + else if (WS.isDefined()) + Info.DataRef = DataLocations[&WS]; + SymbolInfos.emplace_back(Info); + SymbolIndices[&WS] = NumSymbols++; + }; + // For now, always emit the memory import, since loads and stores are not // valid without it. In the future, we could perhaps be more clever and omit // it if there are no loads or stores. @@ -1005,31 +1042,32 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, continue; // If the symbol is not defined in this translation unit, import it. - if ((!WS.isDefined() && !WS.isComdat()) || - WS.isVariable()) { - wasm::WasmImport Import; - Import.Module = WS.getModuleName(); - Import.Field = WS.getName(); - + if (!WS.isDefined() && !WS.isComdat()) { if (WS.isFunction()) { + wasm::WasmImport Import; + Import.Module = WS.getModuleName(); + Import.Field = WS.getName(); Import.Kind = wasm::WASM_EXTERNAL_FUNCTION; Import.SigIndex = getFunctionType(WS); - SymbolIndices[&WS] = NumFunctionImports; - ++NumFunctionImports; - } else { + Imports.push_back(Import); + WasmIndices[&WS] = NumFunctionImports++; + } else if (WS.isGlobal()) { + wasm::WasmImport Import; + Import.Module = WS.getModuleName(); + Import.Field = WS.getName(); Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; - Import.Global.Type = PtrType; - // If this global is the stack pointer, make it mutable. - if (WS.getName() == "__stack_pointer") - Import.Global.Mutable = true; - else - Import.Global.Mutable = false; - - SymbolIndices[&WS] = NumGlobalImports; - ++NumGlobalImports; + Import.Global = WS.getGlobalType(); + Imports.push_back(Import); + WasmIndices[&WS] = NumGlobalImports++; } - Imports.push_back(Import); + // TODO(ncw) We shouldn't be adding the symbol to the symbol table here! + // Instead it should be done by removing the "if (WS.isDefined())" block + // in the big loop below (line ~1284). However - that would reorder all + // the symbols and thus require all the tests to be updated. I think it's + // better to make that change therefore in a future commit, to isolate + // each test update from the change that caused it. + AddSymbol(WS); } } @@ -1053,7 +1091,7 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, Segment.Alignment = Section.getAlignment(); Segment.Flags = 0; DataSize += Segment.Data.size(); - Section.setMemoryOffset(Segment.Offset); + Section.setSegmentIndex(SegmentIndex); if (const MCSymbolWasm *C = Section.getGroup()) { Comdats[C->getName()].emplace_back( @@ -1078,18 +1116,13 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, << " isHidden=" << WS.isHidden() << " isVariable=" << WS.isVariable() << "\n"); - if (WS.isWeak() || WS.isHidden()) { - uint32_t Flags = (WS.isWeak() ? wasm::WASM_SYMBOL_BINDING_WEAK : 0) | - (WS.isHidden() ? wasm::WASM_SYMBOL_VISIBILITY_HIDDEN : 0); - SymbolFlags.emplace_back(WS.getName(), Flags); - } - if (WS.isVariable()) continue; - - unsigned Index; + if (WS.isComdat() && !WS.isDefined()) + continue; if (WS.isFunction()) { + unsigned Index; if (WS.isDefined()) { if (WS.getOffset() != 0) report_fatal_error( @@ -1099,27 +1132,33 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, report_fatal_error( "function symbols must have a size set with .size"); - // A definition. Take the next available index. + // A definition. Write out the function body. Index = NumFunctionImports + Functions.size(); - - // Prepare the function. WasmFunction Func; Func.Type = getFunctionType(WS); Func.Sym = &WS; - SymbolIndices[&WS] = Index; + WasmIndices[&WS] = Index; Functions.push_back(Func); + + auto &Section = static_cast<MCSectionWasm &>(WS.getSection()); + if (const MCSymbolWasm *C = Section.getGroup()) { + Comdats[C->getName()].emplace_back( + WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index}); + } } else { // An import; the index was assigned above. - Index = SymbolIndices.find(&WS)->second; + Index = WasmIndices.find(&WS)->second; } DEBUG(dbgs() << " -> function index: " << Index << "\n"); - } else { + } else if (WS.isData()) { if (WS.isTemporary() && !WS.getSize()) continue; - if (!WS.isDefined()) + if (!WS.isDefined()) { + DEBUG(dbgs() << " -> segment index: -1"); continue; + } if (!WS.getSize()) report_fatal_error("data symbols must have a size set with .size: " + @@ -1129,43 +1168,32 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) report_fatal_error(".size expression must be evaluatable"); - // 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<MCSectionWasm &>(WS.getSection()); assert(DataSection.isWasmData()); - WasmGlobal Global; - Global.Type.Type = PtrType; - Global.Type.Mutable = false; - Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS); - SymbolIndices[&WS] = Index; - DEBUG(dbgs() << " -> global index: " << Index << "\n"); - Globals.push_back(Global); - } - - // If the symbol is visible outside this translation unit, export it. - if (WS.isDefined()) { - wasm::WasmExport Export; - Export.Name = WS.getName(); - Export.Index = Index; - if (WS.isFunction()) - Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; - else - 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<MCSectionWasm &>(WS.getSection()); - if (const MCSymbolWasm *C = Section.getGroup()) - Comdats[C->getName()].emplace_back( - WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, Index}); + // For each data symbol, export it in the symtab as a reference to the + // corresponding Wasm data segment. + wasm::WasmDataReference Ref = wasm::WasmDataReference{ + DataSection.getSegmentIndex(), + static_cast<uint32_t>(Layout.getSymbolOffset(WS)), + static_cast<uint32_t>(Size)}; + DataLocations[&WS] = Ref; + DEBUG(dbgs() << " -> segment index: " << Ref.Segment); + } else { + // A "true" Wasm global (currently just __stack_pointer) + unsigned WasmIndex; + if (WS.isDefined()) { + report_fatal_error("don't yet support defined globals"); + } else { + // An import; the index was assigned above + WasmIndex = WasmIndices.find(&WS)->second; } + + DEBUG(dbgs() << " -> global index: " << WasmIndex << "\n"); } + + if (WS.isDefined()) + AddSymbol(WS); } // Handle weak aliases. We need to process these in a separate pass because @@ -1181,22 +1209,23 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, const auto &WS = static_cast<const MCSymbolWasm &>(S); const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); - assert(SymbolIndices.count(ResolvedSym) > 0); - uint32_t Index = SymbolIndices.find(ResolvedSym)->second; - DEBUG(dbgs() << " -> index:" << Index << "\n"); - wasm::WasmExport Export; - Export.Name = WS.getName(); - Export.Index = Index; - if (WS.isFunction()) - Export.Kind = wasm::WASM_EXTERNAL_FUNCTION; - else - 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()) { + assert(WasmIndices.count(ResolvedSym) > 0); + uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; + WasmIndices[&WS] = WasmIndex; + DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); + } else if (WS.isData()) { + assert(DataLocations.count(ResolvedSym) > 0); + const wasm::WasmDataReference &Ref = + DataLocations.find(ResolvedSym)->second; + DataLocations[&WS] = Ref; + DEBUG(dbgs() << " -> index:" << Ref.Segment << "\n"); + } else { + report_fatal_error("don't yet support global aliases"); + } + + AddSymbol(WS); } { @@ -1209,12 +1238,12 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, return; assert(Rel.Symbol->isFunction()); const MCSymbolWasm &WS = *ResolveSymbol(*Rel.Symbol); - uint32_t SymbolIndex = SymbolIndices.find(&WS)->second; + uint32_t FunctionIndex = WasmIndices.find(&WS)->second; uint32_t TableIndex = TableElems.size() + kInitialTableOffset; if (TableIndices.try_emplace(&WS, TableIndex).second) { DEBUG(dbgs() << " -> adding " << WS.getName() << " to table: " << TableIndex << "\n"); - TableElems.push_back(SymbolIndex); + TableElems.push_back(FunctionIndex); registerFunctionType(WS); } }; @@ -1287,11 +1316,10 @@ void WasmObjectWriter::writeObject(MCAssembler &Asm, writeExportSection(Exports); writeElemSection(TableElems); writeCodeSection(Asm, Layout, Functions); - writeDataSection(DataSegments); + writeDataSection(); writeCodeRelocSection(); writeDataRelocSection(); - writeLinkingMetaDataSection(DataSegments, DataSize, SymbolFlags, - InitFuncs, Comdats); + writeLinkingMetaDataSection(DataSize, SymbolInfos, InitFuncs, Comdats); // TODO: Translate the .comment section to the output. // TODO: Translate debug sections to the output. diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp index 82adc35076d..4483dae809d 100644 --- a/llvm/lib/Object/WasmObjectFile.cpp +++ b/llvm/lib/Object/WasmObjectFile.cpp @@ -317,69 +317,6 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { return Error::success(); } -void WasmObjectFile::populateSymbolTable() { - // Add imports to symbol table - 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, - GlobalIndex++); - 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, - FunctionIndex++, Import.SigIndex); - DEBUG(dbgs() << "Adding import: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); - break; - default: - break; - } - } - - // 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; - auto Pair = SymbolMap.try_emplace(Export.Name, Symbols.size()); - if (Pair.second) { - Symbols.emplace_back(Export.Name, ExportType, Export.Index); - DEBUG(dbgs() << "Adding export: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); - } else { - uint32_t SymIndex = Pair.first->second; - const WasmSymbol &OldSym = Symbols[SymIndex]; - WasmSymbol NewSym(Export.Name, ExportType, Export.Index); - NewSym.setAltIndex(OldSym.ElementIndex); - Symbols[SymIndex] = NewSym; - - DEBUG(dbgs() << "Replacing existing symbol: " << NewSym - << " sym index:" << SymIndex << "\n"); - } - } - if (Export.Kind == wasm::WASM_EXTERNAL_FUNCTION && - isDefinedFunctionIndex(Export.Index)) { - auto &Function = getDefinedFunction(Export.Index); - if (Function.Name.empty()) { - // Use the export's name to set a name for the Function, but only if one - // hasn't already been set. - Function.Name = Export.Name; - } - } - } -} - Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, const uint8_t *End) { HasLinkingSection = true; @@ -388,37 +325,15 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, "Linking data must come after code section", object_error::parse_failed); } - // 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); const uint8_t *SubSectionEnd = Ptr + Size; switch (Type) { - case wasm::WASM_SYMBOL_INFO: { - uint32_t Count = readVaruint32(Ptr); - while (Count--) { - StringRef Symbol = readString(Ptr); - uint32_t Flags = readVaruint32(Ptr); - auto iter = SymbolMap.find(Symbol); - if (iter == SymbolMap.end()) { - return make_error<GenericBinaryError>( - "Invalid symbol name in linking section: " + Symbol, - object_error::parse_failed); - } - uint32_t SymIndex = iter->second; - assert(SymIndex < Symbols.size()); - Symbols[SymIndex].Flags = Flags; - DEBUG(dbgs() << "Set symbol flags index:" - << SymIndex << " name:" - << Symbols[SymIndex].Name << " expected:" - << Symbol << " flags: " << Flags << "\n"); - } + case wasm::WASM_SYMBOL_TABLE: + if (Error Err = parseLinkingSectionSymtab(Ptr, SubSectionEnd)) + return Err; break; - } case wasm::WASM_DATA_SIZE: LinkingData.DataSize = readVaruint32(Ptr); break; @@ -440,10 +355,10 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, 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), + Init.Symbol = readVaruint32(Ptr); + if (!isValidFunctionSymbolIndex(Init.Symbol)) + return make_error<GenericBinaryError>("Invalid function symbol: " + + Twine(Init.Symbol), object_error::parse_failed); LinkingData.InitFunctions.emplace_back(Init); } @@ -467,6 +382,110 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, return Error::success(); } +Error WasmObjectFile::parseLinkingSectionSymtab(const uint8_t *&Ptr, + const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + LinkingData.SymbolTable.reserve(Count); + Symbols.reserve(Count); + StringSet<> SymbolNames; + + std::vector<wasm::WasmImport *> ImportedGlobals; + std::vector<wasm::WasmImport *> ImportedFunctions; + ImportedGlobals.reserve(Imports.size()); + ImportedFunctions.reserve(Imports.size()); + for (auto &I : Imports) { + if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION) + ImportedFunctions.emplace_back(&I); + else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL) + ImportedGlobals.emplace_back(&I); + } + + while (Count--) { + wasm::WasmSymbolInfo Info; + const wasm::WasmSignature *FunctionType = nullptr; + const wasm::WasmGlobalType *GlobalType = nullptr; + + Info.Kind = readUint8(Ptr); + Info.Flags = readVaruint32(Ptr); + bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0; + + switch (Info.Kind) { + case wasm::WASM_SYMBOL_TYPE_FUNCTION: + Info.ElementIndex = readVaruint32(Ptr); + if (!isValidFunctionIndex(Info.ElementIndex) || + IsDefined != isDefinedFunctionIndex(Info.ElementIndex)) + return make_error<GenericBinaryError>("invalid function symbol index", + object_error::parse_failed); + if (IsDefined) { + Info.Name = readString(Ptr); + unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions; + FunctionType = &Signatures[FunctionTypes[FuncIndex]]; + auto &Function = Functions[FuncIndex]; + if (Function.Name.empty()) { + // Use the symbol's name to set a name for the Function, but only if + // one hasn't already been set. + Function.Name = Info.Name; + } + } else { + wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex]; + FunctionType = &Signatures[Import.SigIndex]; + Info.Name = Import.Field; + } + break; + + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + Info.ElementIndex = readVaruint32(Ptr); + if (!isValidGlobalIndex(Info.ElementIndex) || + IsDefined != isDefinedGlobalIndex(Info.ElementIndex)) + return make_error<GenericBinaryError>("invalid global symbol index", + object_error::parse_failed); + if (IsDefined) { + Info.Name = readString(Ptr); + unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals; + GlobalType = &Globals[GlobalIndex].Type; + } else { + wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex]; + Info.Name = Import.Field; + GlobalType = &Import.Global; + } + break; + + case wasm::WASM_SYMBOL_TYPE_DATA: + Info.Name = readString(Ptr); + if (IsDefined) { + uint32_t Index = readVaruint32(Ptr); + if (Index >= DataSegments.size()) + return make_error<GenericBinaryError>("invalid data symbol index", + object_error::parse_failed); + uint32_t Offset = readVaruint32(Ptr); + uint32_t Size = readVaruint32(Ptr); + if (Offset + Size > DataSegments[Index].Data.Content.size()) + return make_error<GenericBinaryError>("invalid data symbol index", + object_error::parse_failed); + Info.DataRef = wasm::WasmDataReference{Index, Offset, Size}; + } + break; + + default: + return make_error<GenericBinaryError>("Invalid symbol type", + object_error::parse_failed); + } + + if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) != + wasm::WASM_SYMBOL_BINDING_LOCAL && + !SymbolNames.insert(Info.Name).second) + return make_error<GenericBinaryError>("Duplicate symbol name " + + Twine(Info.Name), + object_error::parse_failed); + LinkingData.SymbolTable.emplace_back(Info); + Symbols.emplace_back(LinkingData.SymbolTable.back(), FunctionType, + GlobalType); + DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n"); + } + + return Error::success(); +} + Error WasmObjectFile::parseLinkingSectionComdat(const uint8_t *&Ptr, const uint8_t *End) { @@ -706,6 +725,7 @@ Error WasmObjectFile::parseMemorySection(const uint8_t *Ptr, const uint8_t *End) } Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) { + GlobalSection = Sections.size(); uint32_t Count = readVaruint32(Ptr); Globals.reserve(Count); while (Count--) { @@ -737,12 +757,11 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) return make_error<GenericBinaryError>("Invalid function export", object_error::parse_failed); break; - case wasm::WASM_EXTERNAL_GLOBAL: { - if (Ex.Index >= Globals.size() + NumImportedGlobals) + case wasm::WASM_EXTERNAL_GLOBAL: + if (!isValidGlobalIndex(Ex.Index)) return make_error<GenericBinaryError>("Invalid global export", object_error::parse_failed); break; - } case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_TABLE: break; @@ -759,18 +778,35 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) } bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const { - return Index < FunctionTypes.size() + NumImportedFunctions; + return Index < NumImportedFunctions + FunctionTypes.size(); } bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const { return Index >= NumImportedFunctions && isValidFunctionIndex(Index); } -wasm::WasmFunction& WasmObjectFile::getDefinedFunction(uint32_t Index) { +bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const { + return Index < NumImportedGlobals + Globals.size(); +} + +bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const { + return Index >= NumImportedGlobals && isValidGlobalIndex(Index); +} + +bool WasmObjectFile::isValidFunctionSymbolIndex(uint32_t Index) const { + return Index < Symbols.size() && Symbols[Index].isTypeFunction(); +} + +wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) { assert(isDefinedFunctionIndex(Index)); return Functions[Index - NumImportedFunctions]; } +wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) { + assert(isDefinedGlobalIndex(Index)); + return Globals[Index - NumImportedGlobals]; +} + Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) { StartFunction = readVaruint32(Ptr); if (!isValidFunctionIndex(StartFunction)) @@ -888,21 +924,10 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { 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_Executable; - break; - case WasmSymbol::SymbolType::GLOBAL_IMPORT: + if (!Sym.isDefined()) Result |= SymbolRef::SF_Undefined; - break; - case WasmSymbol::SymbolType::GLOBAL_EXPORT: - break; - } - + if (Sym.isTypeFunction()) + Result |= SymbolRef::SF_Executable; return Result; } @@ -927,7 +952,7 @@ const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const { } Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const { - return getWasmSymbol(Symb).Name; + return getWasmSymbol(Symb).Info.Name; } Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { @@ -935,18 +960,17 @@ Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { } uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const { - switch (Sym.Type) { - case WasmSymbol::SymbolType::FUNCTION_IMPORT: - case WasmSymbol::SymbolType::GLOBAL_IMPORT: - case WasmSymbol::SymbolType::FUNCTION_EXPORT: - 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; + switch (Sym.Info.Kind) { + case wasm::WASM_SYMBOL_TYPE_FUNCTION: + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + return Sym.Info.ElementIndex; + case wasm::WASM_SYMBOL_TYPE_DATA: { + // The value of a data symbol is the segment offset, plus the symbol + // offset within the segment. + uint32_t SegmentIndex = Sym.Info.DataRef.Segment; + const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data; + assert(Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST); + return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset; } } llvm_unreachable("invalid symbol type"); @@ -970,12 +994,12 @@ Expected<SymbolRef::Type> WasmObjectFile::getSymbolType(DataRefImpl Symb) const { const WasmSymbol &Sym = getWasmSymbol(Symb); - switch (Sym.Type) { - case WasmSymbol::SymbolType::FUNCTION_IMPORT: - case WasmSymbol::SymbolType::FUNCTION_EXPORT: + switch (Sym.Info.Kind) { + case wasm::WASM_SYMBOL_TYPE_FUNCTION: return SymbolRef::ST_Function; - case WasmSymbol::SymbolType::GLOBAL_IMPORT: - case WasmSymbol::SymbolType::GLOBAL_EXPORT: + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + return SymbolRef::ST_Other; + case wasm::WASM_SYMBOL_TYPE_DATA: return SymbolRef::ST_Data; } @@ -985,14 +1009,24 @@ WasmObjectFile::getSymbolType(DataRefImpl Symb) const { Expected<section_iterator> WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { - DataRefImpl Ref; const WasmSymbol& Sym = getWasmSymbol(Symb); - if (Sym.Type == WasmSymbol::SymbolType::GLOBAL_EXPORT) - Ref.d.a = DataSection; - else if (Sym.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT) - Ref.d.a = CodeSection; - else + if (Sym.isUndefined()) return section_end(); + + DataRefImpl Ref; + switch (Sym.Info.Kind) { + case wasm::WASM_SYMBOL_TYPE_FUNCTION: + Ref.d.a = CodeSection; + break; + case wasm::WASM_SYMBOL_TYPE_GLOBAL: + Ref.d.a = GlobalSection; + break; + case wasm::WASM_SYMBOL_TYPE_DATA: + Ref.d.a = DataSection; + break; + default: + llvm_unreachable("Unknown WasmSymbol::SymbolType"); + } return section_iterator(SectionRef(Ref, this)); } diff --git a/llvm/lib/ObjectYAML/WasmYAML.cpp b/llvm/lib/ObjectYAML/WasmYAML.cpp index 4ae6dccccb1..9433cf6a783 100644 --- a/llvm/lib/ObjectYAML/WasmYAML.cpp +++ b/llvm/lib/ObjectYAML/WasmYAML.cpp @@ -58,7 +58,7 @@ static void sectionMapping(IO &IO, WasmYAML::LinkingSection &Section) { commonSectionMapping(IO, Section); IO.mapRequired("Name", Section.Name); IO.mapRequired("DataSize", Section.DataSize); - IO.mapOptional("SymbolInfo", Section.SymbolInfos); + IO.mapOptional("SymbolTable", Section.SymbolTable); IO.mapOptional("SegmentInfo", Section.SegmentInfos); IO.mapOptional("InitFunctions", Section.InitFunctions); IO.mapOptional("Comdats", Section.Comdats); @@ -366,7 +366,7 @@ void MappingTraits<WasmYAML::DataSegment>::mapping( void MappingTraits<WasmYAML::InitFunction>::mapping( IO &IO, WasmYAML::InitFunction &Init) { IO.mapRequired("Priority", Init.Priority); - IO.mapRequired("FunctionIndex", Init.FunctionIndex); + IO.mapRequired("Symbol", Init.Symbol); } void ScalarEnumerationTraits<WasmYAML::ComdatKind>::enumeration( @@ -391,8 +391,23 @@ void MappingTraits<WasmYAML::Comdat>::mapping( void MappingTraits<WasmYAML::SymbolInfo>::mapping(IO &IO, WasmYAML::SymbolInfo &Info) { + IO.mapRequired("Index", Info.Index); + IO.mapRequired("Kind", Info.Kind); IO.mapRequired("Name", Info.Name); IO.mapRequired("Flags", Info.Flags); + if (Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION) { + IO.mapRequired("Function", Info.ElementIndex); + } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL) { + IO.mapRequired("Global", Info.ElementIndex); + } else if (Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA) { + if ((Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0) { + IO.mapRequired("Segment", Info.DataRef.Segment); + IO.mapOptional("Offset", Info.DataRef.Offset, 0u); + IO.mapRequired("Size", Info.DataRef.Size); + } + } else { + llvm_unreachable("unsupported symbol kind"); + } } void ScalarBitSetTraits<WasmYAML::LimitFlags>::bitset( @@ -414,9 +429,19 @@ void ScalarBitSetTraits<WasmYAML::SymbolFlags>::bitset( BCaseMask(BINDING_MASK, BINDING_LOCAL); //BCaseMask(VISIBILITY_MASK, VISIBILITY_DEFAULT); BCaseMask(VISIBILITY_MASK, VISIBILITY_HIDDEN); + BCaseMask(UNDEFINED, UNDEFINED); #undef BCaseMask } +void ScalarEnumerationTraits<WasmYAML::SymbolKind>::enumeration( + IO &IO, WasmYAML::SymbolKind &Kind) { +#define ECase(X) IO.enumCase(Kind, #X, wasm::WASM_SYMBOL_TYPE_##X); + ECase(FUNCTION); + ECase(DATA); + ECase(GLOBAL); +#undef ECase +} + void ScalarEnumerationTraits<WasmYAML::ValueType>::enumeration( IO &IO, WasmYAML::ValueType &Type) { #define ECase(X) IO.enumCase(Type, #X, wasm::WASM_TYPE_##X); diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index 739044f6c40..9d4f308ca3c 100644 --- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -215,7 +215,7 @@ void WebAssemblyTargetWasmStreamer::emitIndirectFunctionType( WasmSym->setParams(std::move(ValParams)); WasmSym->setReturns(std::move(ValResults)); - WasmSym->setIsFunction(true); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); } void WebAssemblyTargetWasmStreamer::emitGlobalImport(StringRef name) { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp index 4a93d4810c7..c8afa39e6e9 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -74,7 +74,7 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const { WasmSym->setReturns(std::move(Returns)); WasmSym->setParams(std::move(Params)); - WasmSym->setIsFunction(true); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); } return WasmSym; @@ -91,9 +91,16 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol( const WebAssemblySubtarget &Subtarget = Printer.getSubtarget(); // __stack_pointer is a global variable; all other external symbols used by - // CodeGen are functions. - if (strcmp(Name, "__stack_pointer") == 0) + // CodeGen are functions. It's OK to hardcode knowledge of specific symbols + // here; this method is precisely there for fetching the signatures of known + // Clang-provided symbols. + if (strcmp(Name, "__stack_pointer") == 0) { + wasm::ValType iPTR = + Subtarget.hasAddr64() ? wasm::ValType::I64 : wasm::ValType::I32; + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL); + WasmSym->setGlobalType(wasm::WasmGlobalType{int32_t(iPTR), true}); return WasmSym; + } SmallVector<wasm::ValType, 4> Returns; SmallVector<wasm::ValType, 4> Params; @@ -101,7 +108,7 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol( WasmSym->setReturns(std::move(Returns)); WasmSym->setParams(std::move(Params)); - WasmSym->setIsFunction(true); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); return WasmSym; } @@ -189,7 +196,7 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI, MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym); WasmSym->setReturns(std::move(Returns)); WasmSym->setParams(std::move(Params)); - WasmSym->setIsFunction(true); + WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION); const MCExpr *Expr = MCSymbolRefExpr::create(WasmSym, |