Index: test/wasm/archive.ll =================================================================== --- test/wasm/archive.ll +++ test/wasm/archive.ll @@ -29,6 +29,7 @@ ; CHECK: 00000003 T _start ; CHECK-NEXT: 00000001 T bar ; CHECK-NEXT: 00000002 T foo +; CHECK-NEXT: U missing_func ; Verify that symbols from unused objects don't appear in the symbol table ; CHECK-NOT: hello Index: test/wasm/weak-alias.ll =================================================================== --- test/wasm/weak-alias.ll +++ test/wasm/weak-alias.ll @@ -60,9 +60,6 @@ ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: alias_fn -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: direct_fn ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 @@ -78,6 +75,9 @@ ; CHECK-NEXT: - Name: call_direct_ptr ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 5 +; CHECK-NEXT: - Name: alias_fn +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: __heap_base ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 1 Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -93,7 +93,6 @@ void dumpInfo() const; - uint32_t relocateFunctionIndex(uint32_t Original) const; uint32_t calcNewIndex(const WasmRelocation &Reloc) const; uint32_t calcNewValue(const WasmRelocation &Reloc) const; @@ -110,7 +109,10 @@ private: uint32_t relocateVirtualAddress(uint32_t Index) const; uint32_t relocateTypeIndex(uint32_t Original) const; - uint32_t relocateGlobalIndex(uint32_t Original) const; + uint32_t relocateFunctionSymbolIndex(uint32_t Original) const; + uint32_t relocateGlobalSymbolIndex(uint32_t Original) const; + uint32_t relocateFunctionWasmIndex(uint32_t Original) const; + uint32_t relocateGlobalWasmIndex(uint32_t Original) const; uint32_t relocateTableIndex(uint32_t Original) const; Symbol *createDefined(const WasmSymbol &Sym, Symbol::Kind Kind, @@ -129,14 +131,22 @@ // List of all symbols referenced or defined by this file. std::vector Symbols; - // List of all function symbols indexed by the function index space + // List of all function symbols indexed by the function Symbol index space, + // that is, function imports followed by function exports (not the Wasm + // function definition index space, function imports followed by function + // bodies). std::vector FunctionSymbols; - // List of all global symbols indexed by the global index space + // List of all global symbols indexed by the global Symbol index space, + // that is, global imports followed by global exports (not the Wasm + // global definition index space, global imports followed by global + // definitions). std::vector GlobalSymbols; uint32_t NumGlobalImports = 0; uint32_t NumFunctionImports = 0; + uint32_t NumGlobalExports = 0; + uint32_t NumFunctionExports = 0; std::unique_ptr WasmObj; }; Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -54,30 +54,48 @@ return GlobalSymbols[GlobalIndex]->getVirtualAddress(); } -uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const { - Symbol *Sym = FunctionSymbols[Original]; - uint32_t Index = Sym->getOutputIndex(); - DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": " - << Original << " -> " << Index << "\n"); - return Index; -} - uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const { return TypeMap[Original]; } -uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { +uint32_t ObjFile::relocateFunctionSymbolIndex(uint32_t Original) const { Symbol *Sym = FunctionSymbols[Original]; - uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0; - DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original + uint32_t Index = Sym->getOutputSymbolIndex(); + DEBUG(dbgs() << "relocateFunctionSymbolIndex: " << toString(*Sym) << ": " + << Original << " -> " << Index << "\n"); + return Index; +} + +uint32_t ObjFile::relocateGlobalSymbolIndex(uint32_t Original) const { + Symbol *Sym = GlobalSymbols[Original]; + uint32_t Index = Sym->getOutputSymbolIndex(); + DEBUG(dbgs() << "relocateGlobalSymbolIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); return Index; } -uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const { - Symbol *Sym = GlobalSymbols[Original]; +uint32_t ObjFile::relocateFunctionWasmIndex(uint32_t Original) const { + Symbol *Sym = FunctionSymbols[Original]; uint32_t Index = Sym->hasOutputIndex() ? Sym->getOutputIndex() : 0; - DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original + DEBUG(dbgs() << "relocateFunctionWasmIndex: " << toString(*Sym) << ": " + << Original << " -> " << Index << "\n"); + return Index; +} + +uint32_t ObjFile::relocateGlobalWasmIndex(uint32_t Original) const { + Symbol *Sym = GlobalSymbols[Original]; + uint32_t Index = Sym->hasTableIndex() ? Sym->getOutputIndex() : 0; + DEBUG(dbgs() << "relocateGlobalWasmIndex: " << toString(*Sym) << ": " << Original + << " -> " << Index << "\n"); + return Index; +} + +uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { + Symbol *Sym = FunctionSymbols[Original]; + // The null case is possible, if you take the address of a weak function + // that's simply not supplied. + uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0; + DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); return Index; } @@ -93,12 +111,12 @@ case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: case R_WEBASSEMBLY_TABLE_INDEX_I32: case R_WEBASSEMBLY_TABLE_INDEX_SLEB: - return relocateFunctionIndex(Reloc.Index); + return relocateFunctionSymbolIndex(Reloc.Index); case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_LEB: case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: case R_WEBASSEMBLY_MEMORY_ADDR_I32: - return relocateGlobalIndex(Reloc.Index); + return relocateGlobalSymbolIndex(Reloc.Index); default: llvm_unreachable("unknown relocation type"); } @@ -117,9 +135,9 @@ case R_WEBASSEMBLY_TYPE_INDEX_LEB: return relocateTypeIndex(Reloc.Index); case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - return relocateFunctionIndex(Reloc.Index); + return relocateFunctionWasmIndex(Reloc.Index); case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - return relocateGlobalIndex(Reloc.Index); + return relocateGlobalWasmIndex(Reloc.Index); default: llvm_unreachable("unknown relocation type"); } @@ -170,8 +188,9 @@ // Get the value stored in the wasm global represented by this symbol. // This represents the virtual address of the symbol in the input file. uint32_t ObjFile::getGlobalValue(const WasmSymbol &Sym) const { + assert(Sym.WasmIndex >= getWasmObj()->getNumImportedGlobals()); const WasmGlobal &Global = - getWasmObj()->globals()[Sym.ElementIndex - NumGlobalImports]; + getWasmObj()->globals()[Sym.WasmIndex - NumGlobalImports]; assert(Global.Type == llvm::wasm::WASM_TYPE_I32); return Global.InitExpr.Value.Int32; } @@ -185,7 +204,8 @@ } InputFunction *ObjFile::getFunction(const WasmSymbol &Sym) const { - uint32_t FunctionIndex = Sym.ElementIndex - NumFunctionImports; + assert(Sym.WasmIndex >= NumFunctionImports); + uint32_t FunctionIndex = Sym.WasmIndex - NumFunctionImports; return Functions[FunctionIndex]; } @@ -197,16 +217,10 @@ void ObjFile::initializeSymbols() { Symbols.reserve(WasmObj->getNumberOfSymbols()); - for (const WasmImport &Import : WasmObj->imports()) { - switch (Import.Kind) { - case WASM_EXTERNAL_FUNCTION: - ++NumFunctionImports; - break; - case WASM_EXTERNAL_GLOBAL: - ++NumGlobalImports; - break; - } - } + NumFunctionImports = WasmObj->getNumImportedFunctions(); + NumGlobalImports = WasmObj->getNumImportedGlobals(); + NumFunctionExports = WasmObj->getNumExportedFunctions(); + NumGlobalExports = WasmObj->getNumExportedGlobals(); FunctionSymbols.resize(NumFunctionImports + WasmObj->functions().size()); GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size()); @@ -214,13 +228,12 @@ ArrayRef Funcs = WasmObj->functions(); ArrayRef FuncTypes = WasmObj->functionTypes(); ArrayRef Types = WasmObj->types(); - ArrayRef Globals = WasmObj->globals(); for (const auto &C : WasmObj->comdats()) Symtab->addComdat(C, this); - FunctionSymbols.resize(NumFunctionImports + Funcs.size()); - GlobalSymbols.resize(NumGlobalImports + Globals.size()); + FunctionSymbols.resize(NumFunctionImports + NumFunctionExports); + GlobalSymbols.resize(NumGlobalImports + NumGlobalExports); for (const WasmSegment &S : WasmObj->dataSegments()) { InputSegment *Seg = make(S, this); @@ -275,13 +288,9 @@ Symbols.push_back(S); if (WasmSym.isFunction()) { - FunctionSymbols[WasmSym.ElementIndex] = S; - if (WasmSym.HasAltIndex) - FunctionSymbols[WasmSym.AltIndex] = S; + FunctionSymbols[WasmSym.SymbolIndex] = S; } else { - GlobalSymbols[WasmSym.ElementIndex] = S; - if (WasmSym.HasAltIndex) - GlobalSymbols[WasmSym.AltIndex] = S; + GlobalSymbols[WasmSym.SymbolIndex] = S; } } Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -73,10 +73,17 @@ // Returns true if an output index has been set for this symbol bool hasOutputIndex() const; - // Set the output index of the symbol (in the function or global index - // space of the output object. + // Set the output index of the symbol, in the function or global Wasm + // index space of the output object - that is, for defined symbols only, + // its position in the list of defined function bodies / global decls. void setOutputIndex(uint32_t Index); + // Get/set the output symbol index, in the function or global Symbol index + // space - that is, the position in the list of imports+exports. This is + // only used for relocatable output. + uint32_t getOutputSymbolIndex() const; + void setOutputSymbolIndex(uint32_t Index); + uint32_t getTableIndex() const { return TableIndex.getValue(); } // Returns true if a table index has been set for this symbol @@ -110,6 +117,7 @@ const InputSegment *Segment = nullptr; InputFunction *Function = nullptr; llvm::Optional OutputIndex; + llvm::Optional OutputSymbolIndex; llvm::Optional TableIndex; const WasmSignature *FunctionType = nullptr; }; Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -54,6 +54,10 @@ return OutputIndex.getValue(); } +uint32_t Symbol::getOutputSymbolIndex() const { + return OutputSymbolIndex.getValue(); +} + void Symbol::setVirtualAddress(uint32_t Value) { DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); assert(isGlobal()); @@ -67,6 +71,12 @@ OutputIndex = Index; } +void Symbol::setOutputSymbolIndex(uint32_t Index) { + DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index << "\n"); + assert(!OutputSymbolIndex.hasValue()); + OutputSymbolIndex = Index; +} + void Symbol::setTableIndex(uint32_t Index) { DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n"); assert(!TableIndex.hasValue()); Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -70,6 +70,13 @@ std::string FieldName; // may not match the Symbol name }; +// An init entry to be written to either the synthentic init func or the +// linking metadata. +struct WasmInitEntry { + const Symbol *Symbol; + uint32_t Priority; +}; + // The writer writes a SymbolTable result to a file. class Writer { public: @@ -123,10 +130,10 @@ std::vector ImportedFunctions; std::vector ImportedGlobals; std::vector ExportedSymbols; - std::vector DefinedGlobals; + std::vector DefinedGlobals; std::vector DefinedFunctions; std::vector IndirectFunctions; - std::vector InitFunctions; + std::vector InitFunctions; // Elements that are used to construct the final output std::string Header; @@ -422,9 +429,10 @@ SubSection SubSection(WASM_INIT_FUNCS); writeUleb128(SubSection.getStream(), InitFunctions.size(), "num init functions"); - for (const WasmInitFunc &F : InitFunctions) { + for (const WasmInitEntry &F : InitFunctions) { writeUleb128(SubSection.getStream(), F.Priority, "priority"); - writeUleb128(SubSection.getStream(), F.FunctionIndex, "function index"); + writeUleb128(SubSection.getStream(), F.Symbol->getOutputSymbolIndex(), + "function index"); } SubSection.finalizeContents(); SubSection.writeToStream(OS); @@ -602,9 +610,11 @@ if (Sym->isFunction()) { Sym->setOutputIndex(ImportedFunctions.size()); + Sym->setOutputSymbolIndex(ImportedFunctions.size()); ImportedFunctions.push_back(Sym); } else { Sym->setOutputIndex(ImportedGlobals.size()); + Sym->setOutputSymbolIndex(ImportedGlobals.size()); ImportedGlobals.push_back(Sym); } } @@ -631,13 +641,18 @@ } }; - if (ExportEntry) + unsigned FunctionIndex = ImportedFunctions.size(); + if (ExportEntry) { + EntrySym->setOutputSymbolIndex(FunctionIndex++); ExportedSymbols.emplace_back(WasmExportEntry{EntrySym, EntrySym->getName()}); + } if (Config->CtorSymbol && ExportHidden && - !(ExportEntry && Config->CtorSymbol == EntrySym)) + !(ExportEntry && Config->CtorSymbol == EntrySym)) { + Config->CtorSymbol->setOutputSymbolIndex(FunctionIndex++); ExportedSymbols.emplace_back( WasmExportEntry{Config->CtorSymbol, Config->CtorSymbol->getName()}); + } for (ObjFile *File : Symtab->ObjectFiles) { for (Symbol *Sym : File->getSymbols()) { @@ -652,17 +667,20 @@ continue; if (ExportEntry && Sym == EntrySym) continue; + Sym->setOutputSymbolIndex(FunctionIndex++); ExportedSymbols.emplace_back(WasmExportEntry{Sym, BudgeName(Sym)}); } } - for (const Symbol *Sym : DefinedGlobals) { + unsigned GlobalIndex = ImportedGlobals.size(); + for (Symbol *Sym : DefinedGlobals) { // Can't export the SP right now because it's mutable and mutable globals // cannot be exported. However, for output that's intended for processing // by downstream tools, we can rely on the "mutable global" proposal // being present. if (Sym == Config->StackPointerSymbol && !Config->EmitRelocs) continue; + Sym->setOutputSymbolIndex(GlobalIndex++); ExportedSymbols.emplace_back(WasmExportEntry{Sym, BudgeName(Sym)}); } } @@ -814,9 +832,9 @@ { raw_string_ostream OS(FunctionBody); writeUleb128(OS, 0, "num locals"); - for (const WasmInitFunc &F : InitFunctions) { + for (const WasmInitEntry &F : InitFunctions) { writeU8(OS, OPCODE_CALL, "CALL"); - writeUleb128(OS, F.FunctionIndex, "function index"); + writeUleb128(OS, F.Symbol->getOutputIndex(), "function index"); } writeU8(OS, OPCODE_END, "END"); } @@ -843,15 +861,15 @@ const WasmLinkingData &L = File->getWasmObj()->linkingData(); InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size()); for (const WasmInitFunc &F : L.InitFunctions) - InitFunctions.emplace_back(WasmInitFunc{ - F.Priority, File->relocateFunctionIndex(F.FunctionIndex)}); + InitFunctions.emplace_back(WasmInitEntry{ + File->getFunctionSymbols()[F.FunctionIndex], F.Priority}); } // Sort in order of priority (lowest first) so that they are called // in the correct order. - std::sort(InitFunctions.begin(), InitFunctions.end(), - [](const WasmInitFunc &L, const WasmInitFunc &R) { - return L.Priority < R.Priority; - }); + std::stable_sort(InitFunctions.begin(), InitFunctions.end(), + [](const WasmInitEntry &L, const WasmInitEntry &R) { + return L.Priority < R.Priority; + }); } void Writer::run() {