diff options
Diffstat (limited to 'lld/wasm/Writer.cpp')
-rw-r--r-- | lld/wasm/Writer.cpp | 127 |
1 files changed, 94 insertions, 33 deletions
diff --git a/lld/wasm/Writer.cpp b/lld/wasm/Writer.cpp index 14fc90e9751..4cefe3a473e 100644 --- a/lld/wasm/Writer.cpp +++ b/lld/wasm/Writer.cpp @@ -62,6 +62,12 @@ struct WasmSignatureDenseMapInfo { } }; +// A Wasm export to be written into the export section. +struct WasmExportEntry { + const Symbol *Symbol; + StringRef FieldName; // may not match the Symbol name +}; + // The writer writes a SymbolTable result to a file. class Writer { public: @@ -76,6 +82,7 @@ private: void calculateInitFunctions(); void assignIndexes(); void calculateImports(); + void calculateExports(); void calculateTypes(); void createOutputSegments(); void layoutMemory(); @@ -114,6 +121,7 @@ private: DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices; std::vector<const Symbol *> ImportedFunctions; std::vector<const Symbol *> ImportedGlobals; + std::vector<WasmExportEntry> ExportedSymbols; std::vector<const Symbol *> DefinedGlobals; std::vector<InputFunction *> DefinedFunctions; std::vector<const Symbol *> IndirectFunctions; @@ -259,35 +267,8 @@ void Writer::createTableSection() { void Writer::createExportSection() { bool ExportMemory = !Config->Relocatable && !Config->ImportMemory; - Symbol *EntrySym = Symtab->find(Config->Entry); - bool ExportEntry = !Config->Relocatable && EntrySym && EntrySym->isDefined(); - bool ExportHidden = Config->EmitRelocs; - - uint32_t NumExports = ExportMemory ? 1 : 0; - - std::vector<const Symbol *> SymbolExports; - if (ExportEntry) - SymbolExports.emplace_back(EntrySym); - - for (const Symbol *Sym : Symtab->getSymbols()) { - if (Sym->isUndefined() || Sym->isGlobal()) - continue; - if (Sym->isHidden() && !ExportHidden) - continue; - if (ExportEntry && Sym == EntrySym) - continue; - SymbolExports.emplace_back(Sym); - } - for (const Symbol *Sym : DefinedGlobals) { - // Can't export the SP right now because it mutable and mutable globals - // connot be exported. - if (Sym == Config->StackPointerSymbol) - continue; - SymbolExports.emplace_back(Sym); - } - - NumExports += SymbolExports.size(); + uint32_t NumExports = (ExportMemory ? 1 : 0) + ExportedSymbols.size(); if (!NumExports) return; @@ -304,12 +285,12 @@ void Writer::createExportSection() { writeExport(OS, MemoryExport); } - for (const Symbol *Sym : SymbolExports) { - DEBUG(dbgs() << "Export: " << Sym->getName() << "\n"); + for (const WasmExportEntry &E : ExportedSymbols) { + DEBUG(dbgs() << "Export: " << E.Symbol->getName() << "\n"); WasmExport Export; - Export.Name = Sym->getName(); - Export.Index = Sym->getOutputIndex(); - if (Sym->isFunction()) + Export.Name = E.FieldName; + Export.Index = E.Symbol->getOutputIndex(); + if (E.Symbol->isFunction()) Export.Kind = WASM_EXTERNAL_FUNCTION; else Export.Kind = WASM_EXTERNAL_GLOBAL; @@ -404,6 +385,26 @@ void Writer::createLinkingSection() { if (!Config->Relocatable) return; + std::vector<std::pair<StringRef, uint32_t>> SymbolInfo; + for (const WasmExportEntry &E : ExportedSymbols) { + uint32_t Flags = + (E.Symbol->isLocal() ? WASM_SYMBOL_BINDING_LOCAL : + E.Symbol->isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0) | + (E.Symbol->isHidden() ? WASM_SYMBOL_VISIBILITY_HIDDEN : 0); + if (Flags) + SymbolInfo.emplace_back(E.FieldName, Flags); + } + if (!SymbolInfo.empty()) { + SubSection SubSection(WASM_SYMBOL_INFO); + writeUleb128(SubSection.getStream(), SymbolInfo.size(), "num sym info"); + for (auto Pair: SymbolInfo) { + writeStr(SubSection.getStream(), Pair.first, "sym name"); + writeUleb128(SubSection.getStream(), Pair.second, "sym flags"); + } + SubSection.finalizeContents(); + SubSection.writeToStream(OS); + } + if (Segments.size()) { SubSection SubSection(WASM_SEGMENT_INFO); writeUleb128(SubSection.getStream(), Segments.size(), "num data segments"); @@ -608,6 +609,64 @@ void Writer::calculateImports() { } } +void Writer::calculateExports() { + Symbol *EntrySym = Symtab->find(Config->Entry); + bool ExportEntry = !Config->Relocatable && EntrySym && EntrySym->isDefined(); + bool ExportHidden = Config->EmitRelocs; + StringSet<> UsedNames; + auto BudgeLocalName = [&](const Symbol *Sym) { + StringRef SymName = Sym->getName(); + // We can't budge non-local names. + if (!Sym->isLocal()) + return SymName; + // We must budge local names that have a collision with a symbol that we + // haven't yet processed. + if (!Symtab->find(SymName) && UsedNames.insert(SymName).second) + return SymName; + for (unsigned I = 1; ; ++I) { + std::string NameBuf = (SymName + "." + Twine(I)).str(); + if (!UsedNames.count(NameBuf)) { + StringRef Name = Saver.save(NameBuf); + UsedNames.insert(Name); // Insert must use safe StringRef from save() + return Name; + } + } + }; + + if (ExportEntry) + ExportedSymbols.emplace_back(WasmExportEntry{EntrySym, EntrySym->getName()}); + + if (Config->CtorSymbol && ExportHidden && + !(ExportEntry && Config->CtorSymbol == EntrySym)) + ExportedSymbols.emplace_back( + WasmExportEntry{Config->CtorSymbol, Config->CtorSymbol->getName()}); + + for (ObjFile *File : Symtab->ObjectFiles) { + for (Symbol *Sym : File->getSymbols()) { + if (!Sym->isDefined() || File != Sym->getFile()) + continue; + if (Sym->isGlobal()) + continue; + if (Sym->getFunction()->Discarded) + continue; + + if ((Sym->isHidden() || Sym->isLocal()) && !ExportHidden) + continue; + if (ExportEntry && Sym == EntrySym) + continue; + ExportedSymbols.emplace_back(WasmExportEntry{Sym, BudgeLocalName(Sym)}); + } + } + + for (const Symbol *Sym : DefinedGlobals) { + // Can't export the SP right now because it's mutable and mutable globals + // cannot be exported. + if (Sym == Config->StackPointerSymbol) + continue; + ExportedSymbols.emplace_back(WasmExportEntry{Sym, BudgeLocalName(Sym)}); + } +} + uint32_t Writer::lookupType(const WasmSignature &Sig) { auto It = TypeIndices.find(Sig); if (It == TypeIndices.end()) { @@ -793,6 +852,8 @@ void Writer::run() { calculateImports(); log("-- assignIndexes"); assignIndexes(); + log("-- calculateExports"); + calculateExports(); log("-- calculateInitFunctions"); calculateInitFunctions(); if (!Config->Relocatable) |