Index: include/llvm/BinaryFormat/Wasm.h =================================================================== --- include/llvm/BinaryFormat/Wasm.h +++ include/llvm/BinaryFormat/Wasm.h @@ -201,11 +201,11 @@ // 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, + WASM_SYMBOL_TABLE = 0x8, }; // Kind codes used in the custom "linking" section in the WASM_COMDAT_INFO @@ -214,6 +214,13 @@ WASM_COMDAT_FUNCTION = 0x1, }; +// Kind codes used in the custom "linking" section in the WASM_SYMBOL_TABLE +enum : unsigned { + WASM_SYMTAB_FUNCTION = 0x0, + WASM_SYMTAB_DATA = 0x1, + WASM_SYMTAB_GLOBAL = 0x2, +}; + const unsigned WASM_SYMBOL_BINDING_MASK = 0x3; const unsigned WASM_SYMBOL_VISIBILITY_MASK = 0x4; Index: include/llvm/MC/MCSectionWasm.h =================================================================== --- include/llvm/MC/MCSectionWasm.h +++ include/llvm/MC/MCSectionWasm.h @@ -43,13 +43,13 @@ // For data sections, this is the offset of the corresponding wasm data // segment - uint64_t MemoryOffset; + uint32_t SegmentIndex; friend class MCContext; MCSectionWasm(StringRef Section, SectionKind K, const MCSymbolWasm *group, unsigned UniqueID, MCSymbol *Begin) : MCSection(SV_Wasm, K, Begin), SectionName(Section), UniqueID(UniqueID), - Group(group), SectionOffset(0) {} + Group(group), SectionOffset(0), SegmentIndex((uint32_t)-1) {} void setSectionName(StringRef Name) { SectionName = Name; } @@ -79,8 +79,8 @@ uint64_t getSectionOffset() const { return SectionOffset; } void setSectionOffset(uint64_t Offset) { SectionOffset = Offset; } - uint32_t getMemoryOffset() const { return MemoryOffset; } - void setMemoryOffset(uint32_t Offset) { MemoryOffset = Offset; } + uint32_t getSegmentIndex() const { return SegmentIndex; } + void setSegmentIndex(uint32_t Index) { SegmentIndex = Index; } static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; } }; Index: include/llvm/MC/MCSymbolWasm.h =================================================================== --- include/llvm/MC/MCSymbolWasm.h +++ include/llvm/MC/MCSymbolWasm.h @@ -15,22 +15,13 @@ namespace llvm { class MCSymbolWasm : public MCSymbol { -private: - bool IsFunction = false; - bool IsWeak = false; - bool IsHidden = false; - bool IsComdat = false; - std::string ModuleName; - SmallVector Returns; - SmallVector Params; - bool ParamsSet = false; - bool ReturnsSet = false; - - /// An expression describing how to calculate the size of a symbol. If a - /// symbol has no size this field will be NULL. - const MCExpr *SymbolSize = nullptr; - public: + enum class SymbolType { + FUNCTION, + DATA, + GLOBAL + }; + // Use a module name of "env" for now, for compatibility with existing tools. // This is temporary, and may change, as the ABI is not yet stable. MCSymbolWasm(const StringMapEntry *Name, bool isTemporary) @@ -41,8 +32,9 @@ const MCExpr *getSize() const { return SymbolSize; } void setSize(const MCExpr *SS) { SymbolSize = SS; } - bool isFunction() const { return IsFunction; } - void setIsFunction(bool isFunc) { IsFunction = isFunc; } + bool isFunction() const { return Type == SymbolType::FUNCTION; } + bool isData() const { return Type == SymbolType::DATA; } + void setType(SymbolType type) { Type = type; } bool isWeak() const { return IsWeak; } void setWeak(bool isWeak) { IsWeak = isWeak; } @@ -74,6 +66,21 @@ ParamsSet = true; Params = std::move(Pars); } + +private: + SymbolType Type = SymbolType::DATA; + bool IsWeak = false; + bool IsHidden = false; + bool IsComdat = false; + std::string ModuleName; + SmallVector Returns; + SmallVector Params; + bool ParamsSet = false; + bool ReturnsSet = false; + + /// An expression describing how to calculate the size of a symbol. If a + /// symbol has no size this field will be NULL. + const MCExpr *SymbolSize = nullptr; }; } // end namespace llvm Index: include/llvm/Object/Wasm.h =================================================================== --- include/llvm/Object/Wasm.h +++ include/llvm/Object/Wasm.h @@ -35,60 +35,56 @@ class WasmSymbol { public: enum class SymbolType { - FUNCTION_IMPORT, - FUNCTION_EXPORT, - GLOBAL_IMPORT, - GLOBAL_EXPORT, + FUNCTION, + DATA, + GLOBAL, }; - WasmSymbol(StringRef Name, SymbolType Type, uint32_t Section, - uint32_t SymbolIndex, uint32_t WasmIndex, - uint32_t FunctionType = 0) - : Name(Name), Type(Type), Section(Section), SymbolIndex(SymbolIndex), - WasmIndex(WasmIndex), FunctionType(FunctionType) {} + WasmSymbol(StringRef Name, SymbolType Type, uint32_t Section, uint32_t Flags, + uint32_t SymbolIndex, uint32_t WasmIndex = (uint32_t)-1, + uint32_t FunctionType = (uint32_t)-1, int32_t Segment = -1, + uint32_t DataOffset = 0, uint32_t DataSize = 0) + : Name(Name), Type(Type), Section(Section), Flags(Flags), + SymbolIndex(SymbolIndex), WasmIndex(WasmIndex), + FunctionType(FunctionType), Segment(Segment), DataOffset(DataOffset), + DataSize(DataSize) {} StringRef Name; SymbolType Type; uint32_t Section; - uint32_t Flags = 0; + uint32_t Flags; // Index into either the Symbol index space, which consists of all Symbols // together, in order of declaration. uint32_t SymbolIndex; - // Index into the the function or global Wasm index space. This is the - // index space used by the Wasm format for referring to a function or - // global, and consists of the imports followed by the function/global - // definitions. - // To be crystal clear, the following Wasm file has three linker symbols, - // and two Wasm callable items: - // (import "env" "externalFn" ...) - // (export "exportedFn" (func $exportedFnBody)) - // (export "exportedFnAlias" (func $exportedFnBody)) - // (func $exportedFnBody ...) - // Symbol index space = - // [ 0: import externalFn, 1: export exportedFn, 2: export exportedFnAlias ] - // Wasm function index space = - // [ 0: import externalFn, 1: definition exportedFnBody ] + // For function/global symbols, the index into the the function or global Wasm + // index space. This is the index space used by the Wasm format for referring + // to a function or global, and consists of the imports followed by the + // function/global definitions. uint32_t WasmIndex; // For function, the type index uint32_t FunctionType; + // For data symbols, the segment index (or -1 if undefined) + int32_t Segment; + uint32_t DataOffset; + uint32_t DataSize; + bool isFunction() const { - return Type == WasmSymbol::SymbolType::FUNCTION_IMPORT || - Type == WasmSymbol::SymbolType::FUNCTION_EXPORT; + return Type == WasmSymbol::SymbolType::FUNCTION; } - bool isWeak() const { + bool isBindingWeak() const { return getBinding() == wasm::WASM_SYMBOL_BINDING_WEAK; } - bool isGlobal() const { + bool isBindingGlobal() const { return getBinding() == wasm::WASM_SYMBOL_BINDING_GLOBAL; } - bool isLocal() const { + bool isBindingLocal() const { return getBinding() == wasm::WASM_SYMBOL_BINDING_LOCAL; } @@ -248,12 +244,11 @@ // Custom section types Error parseNameSection(const uint8_t *Ptr, const uint8_t *End); Error parseLinkingSection(const uint8_t *Ptr, const uint8_t *End); + Error parseLinkingSectionSymtab(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); - Error populateSymbolTable(); - wasm::WasmObjectHeader Header; std::vector Sections; std::vector Signatures; @@ -275,11 +270,9 @@ uint32_t NumImportedGlobals = 0; uint32_t NumImportedFunctions = 0; uint32_t ImportSection = 0; - uint32_t ExportSection = 0; - - // TODO: will get rid of this map in next commit, once we get replace the - // WASM_SYMBOL_INFO section with WASM_SYMBOL_TABLE - StringMap SymbolMap; + uint32_t GlobalSection = 0; + uint32_t CodeSection = 0; + uint32_t DataSection = 0; }; } // end namespace object Index: lib/MC/MCWasmStreamer.cpp =================================================================== --- lib/MC/MCWasmStreamer.cpp +++ lib/MC/MCWasmStreamer.cpp @@ -113,11 +113,11 @@ break; case MCSA_ELF_TypeFunction: - Symbol->setIsFunction(true); + Symbol->setType(MCSymbolWasm::SymbolType::FUNCTION); break; case MCSA_ELF_TypeObject: - Symbol->setIsFunction(false); + Symbol->setType(MCSymbolWasm::SymbolType::DATA); break; default: Index: lib/MC/WasmObjectWriter.cpp =================================================================== --- lib/MC/WasmObjectWriter.cpp +++ lib/MC/WasmObjectWriter.cpp @@ -111,6 +111,15 @@ SmallVector Data; }; +// Represents the location of a Wasm symbol within a WasmDataSegment, as the +// index of the segment (or -1 if the symbol is undefined), and the offset +// and size within the segment. +struct WasmDataSymbolSegment { + int32_t Index; + uint32_t Offset; + uint32_t Size; +}; + // A wasm import to be written into the import section. struct WasmImport { StringRef ModuleName; @@ -150,6 +159,16 @@ uint32_t Index; }; +// Information about a single entry to be written to the symbol table +struct WasmSymbolEntry { + StringRef Name; + unsigned Kind; + uint32_t Flags; + int32_t Index; // Wasm index for function/global kind; segment index for data + uint32_t DataOffset; + uint32_t DataSize; +}; + // Information about a single relocation. struct WasmRelocationEntry { uint64_t Offset; // Where is the relocation. @@ -213,11 +232,14 @@ DenseMap SymbolIndices; // Maps function/global symbols to the function/global Wasm index space. DenseMap WasmIndices; + // Maps data symbols to the Wasm segment and offset/size with the segment. + DenseMap SegmentIndices; DenseMap FunctionTypeIndices; SmallVector FunctionTypes; SmallVector Globals; + SmallVector DataSegments; unsigned NumFunctionImports = 0; unsigned NumGlobalImports = 0; @@ -247,9 +269,11 @@ SymbolIndices.clear(); WasmIndices.clear(); TableIndices.clear(); + SegmentIndices.clear(); FunctionTypeIndices.clear(); FunctionTypes.clear(); Globals.clear(); + DataSegments.clear(); MCObjectWriter::reset(); NumFunctionImports = 0; NumGlobalImports = 0; @@ -284,12 +308,11 @@ void writeElemSection(ArrayRef TableElems); void writeCodeSection(const MCAssembler &Asm, const MCAsmLayout &Layout, ArrayRef Functions); - void writeDataSection(ArrayRef Segments); + void writeDataSection(); void writeCodeRelocSection(); void writeDataRelocSection(); void writeLinkingMetaDataSection( - ArrayRef Segments, uint32_t DataSize, - ArrayRef> SymbolFlags, + uint32_t DataSize, ArrayRef SymbolInfos, ArrayRef> InitFuncs, const std::map>& Comdats); @@ -522,13 +545,10 @@ // For undefined symbols, use zero if (!Sym->isDefined()) return 0; - - uint32_t GlobalIndex = WasmIndices[Sym]; - const WasmGlobal& Global = Globals[GlobalIndex - NumGlobalImports]; - uint64_t Address = Global.InitialValue + RelEntry.Addend; - + auto &SI = SegmentIndices[Sym]; + const WasmDataSegment &Segment = DataSegments[SI.Index]; // Ignore overflow. LLVM allows address arithmetic to silently wrap. - return Address; + return Segment.Offset + SI.Offset + RelEntry.Addend; } default: llvm_unreachable("invalid relocation type"); @@ -541,7 +561,6 @@ 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"); @@ -566,16 +585,9 @@ const SmallVectorImpl &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"); } @@ -822,16 +834,16 @@ endSection(Section); } -void WasmObjectWriter::writeDataSection(ArrayRef 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 @@ -884,20 +896,41 @@ } void WasmObjectWriter::writeLinkingMetaDataSection( - ArrayRef Segments, uint32_t DataSize, - ArrayRef> SymbolFlags, + uint32_t DataSize, ArrayRef SymbolInfos, ArrayRef> InitFuncs, const std::map>& 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 (auto &Sym : SymbolInfos) { + encodeULEB128(Sym.Kind, getStream()); + encodeULEB128(Sym.Flags, getStream()); + switch (Sym.Kind) { + case wasm::WASM_SYMTAB_FUNCTION: + encodeULEB128(Sym.Index, getStream()); + if (static_cast(Sym.Index) >= NumFunctionImports) + writeString(Sym.Name); + break; + case wasm::WASM_SYMTAB_GLOBAL: + encodeULEB128(Sym.Index, getStream()); + if (static_cast(Sym.Index) >= NumGlobalImports) + writeString(Sym.Name); + break; + case wasm::WASM_SYMTAB_DATA: + writeString(Sym.Name); + encodeSLEB128(Sym.Index, getStream()); + if (Sym.Index >= 0) { + encodeULEB128(Sym.DataOffset, getStream()); + encodeULEB128(Sym.DataSize, getStream()); + } + break; + default: + llvm_unreachable("unexpected kind"); + } } endSection(SubSection); } @@ -908,10 +941,10 @@ 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()); @@ -972,16 +1005,6 @@ return Pair.first->second; } -static void addFlags(SmallVector, 4> &SymbolFlags, - const MCSymbolWasm &WS) { - uint32_t Flags = (WS.isWeak() ? wasm::WASM_SYMBOL_BINDING_WEAK : 0) | - (WS.isHidden() ? wasm::WASM_SYMBOL_VISIBILITY_HIDDEN : 0) | - (!WS.isExternal() && WS.isDefined() ? wasm::WASM_SYMBOL_BINDING_LOCAL : 0); - if (Flags != 0) { - SymbolFlags.emplace_back(WS.getName(), Flags); - } -} - void WasmObjectWriter::writeObject(MCAssembler &Asm, const MCAsmLayout &Layout) { DEBUG(dbgs() << "WasmObjectWriter::writeObject\n"); @@ -993,19 +1016,41 @@ SmallVector TableElems; SmallVector Imports; SmallVector Exports; - SmallVector, 4> SymbolFlags; + SmallVector SymbolInfos; SmallVector, 2> InitFuncs; std::map> Comdats; unsigned NumSymbols = 0; - SmallVector DataSegments; uint32_t DataSize = 0; + auto AddSymbol = [&](SmallVectorImpl &SymbolInfos, + const MCSymbolWasm &WS) { + uint32_t Flags = (WS.isWeak() ? wasm::WASM_SYMBOL_BINDING_WEAK : 0) | + (WS.isHidden() ? wasm::WASM_SYMBOL_VISIBILITY_HIDDEN : 0) | + (!WS.isExternal() && WS.isDefined() ? wasm::WASM_SYMBOL_BINDING_LOCAL : 0); + if (WS.isData()) { + auto &SI = SegmentIndices[&WS]; + SymbolInfos.emplace_back( + WasmSymbolEntry{WS.getName(), wasm::WASM_SYMTAB_DATA, Flags, SI.Index, + SI.Offset, SI.Size}); + } else { + unsigned Kind = WS.isFunction() ? wasm::WASM_SYMTAB_FUNCTION + : wasm::WASM_SYMTAB_GLOBAL; + SymbolInfos.emplace_back( + WasmSymbolEntry{WS.getName(), Kind, Flags, + static_cast(WasmIndices[&WS]), 0, 0}); + } + }; + // In the special .global_variables section, we've encoded global // variables used by the function. Translate them into the Globals // list. + //XXX This is constructed in emitGlobal() but it doesn't seem to be called anywhere!?! + // XXX this is therefore almost certainly wrong... :( Could try just deleting the code? MCSectionWasm *GlobalVars = Ctx.getWasmSection(".global_variables", SectionKind::getMetadata()); if (!GlobalVars->getFragmentList().empty()) { + assert(false); // XXX see if it's used... + if (GlobalVars->getFragmentList().size() != 1) report_fatal_error("only one .global_variables fragment supported"); const MCFragment &Frag = *GlobalVars->begin(); @@ -1104,6 +1149,8 @@ Import.Type = getFunctionType(WS); WasmIndices[&WS] = NumFunctionImports++; SymbolIndices[&WS] = NumSymbols++; + } else if (WS.isData()) { + continue; } else { Import.Kind = wasm::WASM_EXTERNAL_GLOBAL; Import.Type = int32_t(PtrType); @@ -1114,8 +1161,6 @@ // If this global is the stack pointer, make it mutable. if (WS.getName() == "__stack_pointer") Import.IsMutable = true; - - addFlags(SymbolFlags, WS); } Imports.push_back(Import); @@ -1131,6 +1176,7 @@ if (cast(Sec).getSectionName().startswith(".init_array")) continue; + uint32_t SegmentIndex = DataSegments.size(); DataSize = alignTo(DataSize, Section.getAlignment()); DataSegments.emplace_back(); WasmDataSegment &Segment = DataSegments.back(); @@ -1141,12 +1187,11 @@ 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( - WasmComdatEntry{wasm::WASM_COMDAT_DATA, - static_cast(DataSegments.size()) - 1}); + WasmComdatEntry{wasm::WASM_COMDAT_DATA, SegmentIndex}); } } @@ -1193,6 +1238,11 @@ SymbolIndices[&WS] = SymbolIndex; WasmIndices[&WS] = WasmIndex; Functions.push_back(Func); + + auto &Section = static_cast(WS.getSection()); + if (const MCSymbolWasm *C = Section.getGroup()) + Comdats[C->getName()].emplace_back( + WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, WasmIndex}); } else { // An import; the index was assigned above. WasmIndex = WasmIndices.find(&WS)->second; @@ -1200,61 +1250,42 @@ } DEBUG(dbgs() << " -> function index: " << WasmIndex << "\n"); - } else { + } else if (WS.isData()) { if (WS.isTemporary() && !WS.getSize()) continue; - if (!WS.isDefined()) - continue; - - if (!WS.getSize()) - report_fatal_error("data symbols must have a size set with .size: " + - WS.getName()); - - int64_t Size = 0; - 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. - WasmIndex = NumGlobalImports + Globals.size(); SymbolIndex = NumSymbols++; - auto &DataSection = static_cast(WS.getSection()); - assert(DataSection.isWasmData()); + WasmDataSymbolSegment SegmentInfo = { -1, 0, 0 }; + if (WS.isDefined()) { + if (!WS.getSize()) + report_fatal_error("data symbols must have a size set with .size: " + + WS.getName()); - WasmGlobal Global; - Global.Type = PtrType; - Global.IsMutable = false; - Global.HasImport = false; - Global.InitialValue = DataSection.getMemoryOffset() + Layout.getSymbolOffset(WS); - Global.ImportIndex = 0; - SymbolIndices[&WS] = SymbolIndex; - WasmIndices[&WS] = WasmIndex; - DEBUG(dbgs() << " -> global index: " << WasmIndex << "\n"); - Globals.push_back(Global); - } + int64_t Size = 0; + if (!WS.getSize()->evaluateAsAbsolute(Size, Layout)) + report_fatal_error(".size expression must be evaluatable"); + SegmentInfo.Size = Size; - addFlags(SymbolFlags, WS); - - // If the symbol is visible outside this translation unit, export it. - if (WS.isDefined()) { - WasmExport Export; - Export.FieldName = WS.getName(); - Export.Index = WasmIndex; - 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.isFunction()) { - auto &Section = static_cast(WS.getSection()); - if (const MCSymbolWasm *C = Section.getGroup()) - Comdats[C->getName()].emplace_back( - WasmComdatEntry{wasm::WASM_COMDAT_FUNCTION, WasmIndex}); + // For each data symbol, export it in the symtab as a reference to the + // corresponding Wasm data segment. + auto& DataSection = static_cast(WS.getSection()); + assert(DataSection.isWasmData()); + SegmentInfo.Index = DataSection.getSegmentIndex(); + SegmentInfo.Offset = Layout.getSymbolOffset(WS); } + SymbolIndices[&WS] = SymbolIndex; + SegmentIndices[&WS] = SegmentInfo; + DEBUG(dbgs() << " -> segment index: " << SegmentInfo.Index << "\n"); + } else { + // A "true" Wasm global (currently just __stack_pointer) + if (WS.isDefined()) + report_fatal_error("don't support defined globals"); + WasmIndex = WasmIndices.find(&WS)->second; + SymbolIndex = SymbolIndices.find(&WS)->second; + DEBUG(dbgs() << " -> global index: " << WasmIndex << "\n"); } + + AddSymbol(SymbolInfos, WS); } // Handle weak aliases. We need to process these in a separate pass because @@ -1270,24 +1301,23 @@ const auto &WS = static_cast(S); const MCSymbolWasm *ResolvedSym = ResolveSymbol(WS); DEBUG(dbgs() << WS.getName() << ": weak alias of '" << *ResolvedSym << "'\n"); - assert(WasmIndices.count(ResolvedSym) > 0); - uint32_t WasmIndex = WasmIndices.find(ResolvedSym)->second; - DEBUG(dbgs() << " -> index:" << WasmIndex << "\n"); + 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(SegmentIndices.count(ResolvedSym) > 0); + auto &SI = SegmentIndices.find(ResolvedSym)->second; + SegmentIndices[&WS] = SI; + DEBUG(dbgs() << " -> index:" << SI.Index << "\n"); + } else { + report_fatal_error("don't support global aliases"); + } SymbolIndices[&WS] = NumSymbols++; - WasmIndices[&WS] = WasmIndex; - addFlags(SymbolFlags, WS); - - WasmExport Export; - Export.FieldName = WS.getName(); - Export.Index = WasmIndex; - 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); + AddSymbol(SymbolInfos, WS); } { @@ -1376,11 +1406,10 @@ 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. Index: lib/Object/WasmObjectFile.cpp =================================================================== --- lib/Object/WasmObjectFile.cpp +++ lib/Object/WasmObjectFile.cpp @@ -317,82 +317,6 @@ return Error::success(); } -Error WasmObjectFile::populateSymbolTable() { - Symbols.reserve(NumImportedFunctions + NumImportedGlobals + Exports.size()); - - // Add imports to symbol table - for (const wasm::WasmImport& Import : Imports) { - WasmSymbol::SymbolType ImportType; - unsigned FunctionType = 0; - switch (Import.Kind) { - case wasm::WASM_EXTERNAL_GLOBAL: - assert(Import.Global.Type == wasm::WASM_TYPE_I32); - ImportType = WasmSymbol::SymbolType::GLOBAL_IMPORT; - break; - case wasm::WASM_EXTERNAL_FUNCTION: - ImportType = WasmSymbol::SymbolType::FUNCTION_IMPORT; - FunctionType = Import.SigIndex; - break; - default: - continue; - } - unsigned SymbolIndex = Symbols.size(); - if (!SymbolMap.try_emplace(Import.Field, SymbolIndex).second) - return make_error( - "Duplicate symbol name " + Import.Field, - object_error::parse_failed); - unsigned WasmIndex = SymbolIndex; - Symbols.emplace_back(Import.Field, ImportType, ImportSection, SymbolIndex, - WasmIndex, FunctionType); - DEBUG(dbgs() << "Adding import: " << Symbols.back() - << " sym index:" << SymbolIndex << "\n"); - } - - // Add exports to symbol table - for (const wasm::WasmExport& Export : Exports) { - WasmSymbol::SymbolType ExportType; - unsigned FunctionType = 0; - switch (Export.Kind) { - case wasm::WASM_EXTERNAL_GLOBAL: - assert(isValidGlobalIndex(Export.Index)); - if (!isDefinedGlobalIndex(Export.Index)) - return make_error("symbol cannot export an import", - object_error::parse_failed); - ExportType = WasmSymbol::SymbolType::GLOBAL_EXPORT; - break; - case wasm::WASM_EXTERNAL_FUNCTION: { - assert(isValidFunctionIndex(Export.Index)); - if (!isDefinedFunctionIndex(Export.Index)) - return make_error("symbol cannot export an import", - object_error::parse_failed); - ExportType = WasmSymbol::SymbolType::FUNCTION_EXPORT; - FunctionType = FunctionTypes[Export.Index - NumImportedFunctions]; - 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; - } - break; - } - default: - continue; - } - unsigned SymbolIndex = Symbols.size(); - if (!SymbolMap.try_emplace(Export.Name, SymbolIndex).second) - return make_error( - "Duplicate symbol name " + Export.Name, - object_error::parse_failed); - unsigned WasmIndex = Export.Index; - Symbols.emplace_back(Export.Name, ExportType, ExportSection, SymbolIndex, - WasmIndex, FunctionType); - DEBUG(dbgs() << "Adding export: " << Symbols.back() - << " sym index:" << SymbolIndex << "\n"); - } - - return Error::success(); -} - Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, const uint8_t *End) { HasLinkingSection = true; @@ -401,38 +325,15 @@ "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. - if (Error Err = populateSymbolTable()) - return Err; - 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( - "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; @@ -481,6 +382,112 @@ return Error::success(); } +Error WasmObjectFile::parseLinkingSectionSymtab(const uint8_t *&Ptr, + const uint8_t *End) { + uint32_t Count = readVaruint32(Ptr); + Symbols.reserve(Count); + StringSet<> SymbolNames; + + std::vector ImportedGlobals; + std::vector 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--) { + uint32_t Kind = readVaruint32(Ptr); + uint32_t Flags = readVaruint32(Ptr); + + StringRef Name; + WasmSymbol::SymbolType Type; + uint32_t Section; + uint32_t WasmIndex = (uint32_t)-1; + uint32_t FunctionType = (uint32_t)-1; + int32_t Segment = (uint32_t)-1; + uint32_t DataOffset = 0; + uint32_t DataSize = 0; + + switch (Kind) { + case wasm::WASM_SYMTAB_FUNCTION: + Type = WasmSymbol::SymbolType::FUNCTION; + WasmIndex = readVaruint32(Ptr); + if (!isValidFunctionIndex(WasmIndex)) + return make_error("invalid function symbol index", + object_error::parse_failed); + if (isDefinedFunctionIndex(WasmIndex)) { + Section = CodeSection; + Name = readString(Ptr); + FunctionType = FunctionTypes[WasmIndex - ImportedFunctions.size()]; + auto &Function = getDefinedFunction(WasmIndex); + 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 = Name; + } + } else { + Section = ImportSection; + wasm::WasmImport &Import = *ImportedFunctions[WasmIndex]; + FunctionType = Import.SigIndex; + Name = Import.Field; + } + break; + + case wasm::WASM_SYMTAB_GLOBAL: + Type = WasmSymbol::SymbolType::GLOBAL; + WasmIndex = readVaruint32(Ptr); + if (!isValidGlobalIndex(WasmIndex)) + return make_error("invalid global symbol index", + object_error::parse_failed); + if (isDefinedGlobalIndex(WasmIndex)) { + Section = GlobalSection; + Name = readString(Ptr); + } else { + Section = ImportSection; + wasm::WasmImport &Import = *ImportedGlobals[WasmIndex]; + Name = Import.Field; + } + break; + + case wasm::WASM_SYMTAB_DATA: + Type = WasmSymbol::SymbolType::DATA; + Section = DataSection; + Name = readString(Ptr); + Segment = readVarint32(Ptr); + assert(Segment >= -1); + if (Segment >= 0) { + if (Segment >= DataSegments.size()) + return make_error("invalid data symbol index", + object_error::parse_failed); + DataOffset = readVaruint32(Ptr); + DataSize = readVaruint32(Ptr); + if (DataOffset + DataSize > DataSegments[Segment].Data.Content.size()) + return make_error("invalid data symbol index", + object_error::parse_failed); + } + break; + + default: + return make_error("Invalid symbol kind", + object_error::parse_failed); + } + + unsigned SymbolIndex = Symbols.size(); + if (!SymbolNames.insert(Name).second) + return make_error("Duplicate symbol name " + Name, + object_error::parse_failed); + Symbols.emplace_back(Name, Type, Section, Flags, SymbolIndex, WasmIndex, + FunctionType, Segment, DataOffset, DataSize); + DEBUG(dbgs() << "Adding symbol: " << Symbols.back()); + } + + return Error::success(); +} + Error WasmObjectFile::parseLinkingSectionComdat(const uint8_t *&Ptr, const uint8_t *End) { @@ -721,6 +728,7 @@ } Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) { + GlobalSection = Sections.size(); uint32_t Count = readVaruint32(Ptr); Globals.reserve(Count); while (Count--) { @@ -739,7 +747,6 @@ } 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++) { @@ -807,6 +814,7 @@ } Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) { + CodeSection = Sections.size(); const uint8_t *CodeSectionStart = Ptr; uint32_t FunctionCount = readVaruint32(Ptr); if (FunctionCount != FunctionTypes.size()) { @@ -870,6 +878,7 @@ } Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) { + DataSection = Sections.size(); const uint8_t *Start = Ptr; uint32_t Count = readVaruint32(Ptr); DataSegments.reserve(Count); @@ -907,24 +916,26 @@ const WasmSymbol &Sym = getWasmSymbol(Symb); DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n"); - if (Sym.isWeak()) + if (Sym.isBindingWeak()) Result |= SymbolRef::SF_Weak; - if (!Sym.isLocal()) + if (!Sym.isBindingLocal()) 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: + case WasmSymbol::SymbolType::FUNCTION: Result |= SymbolRef::SF_Executable; + if (!isDefinedFunctionIndex(Sym.WasmIndex)) + Result |= SymbolRef::SF_Undefined; break; - case WasmSymbol::SymbolType::GLOBAL_IMPORT: - Result |= SymbolRef::SF_Undefined; + case WasmSymbol::SymbolType::GLOBAL: + if (!isDefinedGlobalIndex(Sym.WasmIndex)) + Result |= SymbolRef::SF_Undefined; break; - case WasmSymbol::SymbolType::GLOBAL_EXPORT: + case WasmSymbol::SymbolType::DATA: + if (Sym.Segment < 0) + Result |= SymbolRef::SF_Undefined; break; } @@ -961,17 +972,14 @@ 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: + case WasmSymbol::SymbolType::FUNCTION: + case WasmSymbol::SymbolType::GLOBAL: return Sym.WasmIndex; - case WasmSymbol::SymbolType::GLOBAL_EXPORT: { - uint32_t GlobalIndex = Sym.WasmIndex - 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; + case WasmSymbol::SymbolType::DATA: { + assert(Sym.Segment >= 0); + auto &SegmentOffset = DataSegments[Sym.Segment].Data.Offset; + assert(SegmentOffset.Opcode == wasm::WASM_OPCODE_I32_CONST); + return SegmentOffset.Value.Int32 + Sym.DataOffset; } } llvm_unreachable("invalid symbol type"); @@ -996,11 +1004,11 @@ const WasmSymbol &Sym = getWasmSymbol(Symb); switch (Sym.Type) { - case WasmSymbol::SymbolType::FUNCTION_IMPORT: - case WasmSymbol::SymbolType::FUNCTION_EXPORT: + case WasmSymbol::SymbolType::FUNCTION: return SymbolRef::ST_Function; - case WasmSymbol::SymbolType::GLOBAL_IMPORT: - case WasmSymbol::SymbolType::GLOBAL_EXPORT: + case WasmSymbol::SymbolType::GLOBAL: + return SymbolRef::ST_Other; + case WasmSymbol::SymbolType::DATA: return SymbolRef::ST_Data; } Index: lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp =================================================================== --- lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -256,7 +256,7 @@ WasmSym->setParams(std::move(ValParams)); WasmSym->setReturns(std::move(ValResults)); - WasmSym->setIsFunction(true); + WasmSym->setType(MCSymbolWasm::SymbolType::FUNCTION); } void WebAssemblyTargetWasmStreamer::emitGlobalImport(StringRef name) { Index: lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp =================================================================== --- lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp @@ -74,7 +74,7 @@ WasmSym->setReturns(std::move(Returns)); WasmSym->setParams(std::move(Params)); - WasmSym->setIsFunction(true); + WasmSym->setType(MCSymbolWasm::SymbolType::FUNCTION); } return WasmSym; @@ -92,8 +92,10 @@ // __stack_pointer is a global variable; all other external symbols used by // CodeGen are functions. - if (strcmp(Name, "__stack_pointer") == 0) + if (strcmp(Name, "__stack_pointer") == 0) { + WasmSym->setType(MCSymbolWasm::SymbolType::GLOBAL); return WasmSym; + } SmallVector Returns; SmallVector Params; @@ -101,7 +103,7 @@ WasmSym->setReturns(std::move(Returns)); WasmSym->setParams(std::move(Params)); - WasmSym->setIsFunction(true); + WasmSym->setType(MCSymbolWasm::SymbolType::FUNCTION); return WasmSym; } @@ -189,7 +191,7 @@ MCSymbolWasm *WasmSym = cast(Sym); WasmSym->setReturns(std::move(Returns)); WasmSym->setParams(std::move(Params)); - WasmSym->setIsFunction(true); + WasmSym->setType(MCSymbolWasm::SymbolType::FUNCTION); const MCExpr *Expr = MCSymbolRefExpr::create(WasmSym,