Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -26,11 +26,13 @@ using llvm::object::WasmSection; using llvm::object::WasmSymbol; using llvm::wasm::WasmImport; +using llvm::wasm::WasmSignature; namespace lld { namespace wasm { class Symbol; +class InputFunction; class InputSegment; class InputFile { @@ -95,34 +97,27 @@ uint32_t relocateTableIndex(uint32_t Original) const; uint32_t getRelocatedAddress(uint32_t Index) const; - // Returns true if the given function index is an imported function, - // as opposed to the locally defined function. - bool isImportedFunction(uint32_t Index) const; + size_t getNumGlobalImports() const { return NumGlobalImports; } - size_t NumFunctionImports() const { return FunctionImports; } - size_t NumGlobalImports() const { return GlobalImports; } - - int32_t FunctionIndexOffset = 0; const WasmSection *CodeSection = nullptr; - std::vector CodeRelocations; - int32_t CodeOffset = 0; - const WasmSection *DataSection = nullptr; std::vector TypeMap; std::vector Segments; + std::vector Functions; ArrayRef getSymbols() { return Symbols; } ArrayRef getTableSymbols() { return TableSymbols; } private: Symbol *createDefined(const WasmSymbol &Sym, - const InputSegment *Segment = nullptr); - Symbol *createUndefined(const WasmSymbol &Sym); + const InputSegment *Segment = nullptr, + InputFunction *Function = nullptr); + Symbol *createUndefined(const WasmSymbol &Sym, + const WasmSignature *Signature = nullptr); void initializeSymbols(); - InputSegment *getSegment(const WasmSymbol &WasmSym); - Symbol *getFunctionSymbol(uint32_t FunctionIndex) const; - Symbol *getTableSymbol(uint32_t TableIndex) const; - Symbol *getGlobalSymbol(uint32_t GlobalIndex) const; + InputSegment *getSegment(const WasmSymbol &WasmSym) const; + const WasmSignature *getFunctionSig(const WasmSymbol &Sym) const; + InputFunction *getFunction(const WasmSymbol &Sym) const; // List of all symbols referenced or defined by this file. std::vector Symbols; @@ -136,8 +131,9 @@ // List of all indirect symbols indexed by table index space. std::vector TableSymbols; - uint32_t GlobalImports = 0; - uint32_t FunctionImports = 0; + const WasmSection *DataSection = nullptr; + uint32_t NumGlobalImports = 0; + uint32_t NumFunctionImports = 0; std::unique_ptr WasmObj; }; Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -10,6 +10,7 @@ #include "InputFiles.h" #include "Config.h" +#include "InputFunction.h" #include "InputSegment.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" @@ -43,34 +44,20 @@ } void ObjFile::dumpInfo() const { - log("reloc info for: " + getName() + "\n" + - " FunctionIndexOffset : " + Twine(FunctionIndexOffset) + "\n" + - " NumFunctionImports : " + Twine(NumFunctionImports()) + "\n" + - " NumGlobalImports : " + Twine(NumGlobalImports()) + "\n"); + log("info for: " + getName() + "\n" + + " Total Functions : " + Twine(FunctionSymbols.size()) + "\n" + + " Total Globals : " + Twine(GlobalSymbols.size()) + "\n" + + " Function Imports : " + Twine(NumFunctionImports) + "\n" + + " Global Imports : " + Twine(NumGlobalImports) + "\n" + + " Table Entries : " + Twine(TableSymbols.size()) + "\n"); } -bool ObjFile::isImportedFunction(uint32_t Index) const { - return Index < NumFunctionImports(); -} - -Symbol *ObjFile::getFunctionSymbol(uint32_t Index) const { - return FunctionSymbols[Index]; -} - -Symbol *ObjFile::getTableSymbol(uint32_t Index) const { - return TableSymbols[Index]; -} - -Symbol *ObjFile::getGlobalSymbol(uint32_t Index) const { - return GlobalSymbols[Index]; -} - -uint32_t ObjFile::getRelocatedAddress(uint32_t Index) const { - return getGlobalSymbol(Index)->getVirtualAddress(); +uint32_t ObjFile::getRelocatedAddress(uint32_t GlobalIndex) const { + return GlobalSymbols[GlobalIndex]->getVirtualAddress(); } uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const { - Symbol *Sym = getFunctionSymbol(Original); + Symbol *Sym = FunctionSymbols[Original]; uint32_t Index = Sym->getOutputIndex(); DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); @@ -82,7 +69,7 @@ } uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { - Symbol *Sym = getTableSymbol(Original); + Symbol *Sym = TableSymbols[Original]; uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0; DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); @@ -90,7 +77,7 @@ } uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const { - Symbol *Sym = getGlobalSymbol(Original); + Symbol *Sym = GlobalSymbols[Original]; uint32_t Index = Sym->hasOutputIndex() ? Sym->getOutputIndex() : 0; DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original << " -> " << Index << "\n"); @@ -125,7 +112,7 @@ } // Return the InputSegment in which a given symbol is defined. -InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) { +InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) const { uint32_t Address = WasmObj->getWasmSymbolValue(WasmSym); for (InputSegment *Segment : Segments) { if (Address >= Segment->startVA() && Address < Segment->endVA()) { @@ -141,37 +128,61 @@ static void copyRelocationsRange(std::vector &To, ArrayRef From, size_t Start, - size_t End) { + size_t Size) { for (const WasmRelocation &R : From) - if (R.Offset >= Start && R.Offset < End) + if (R.Offset >= Start && R.Offset < Start + Size) To.push_back(R); } +// Get the signature for a given function symbol, either by looking +// it up in function sections (for defined functions), of the imports section +// (for imported functions). +const WasmSignature *ObjFile::getFunctionSig(const WasmSymbol &Sym) const { + DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n"); + return &WasmObj->types()[Sym.FunctionType]; +} + +InputFunction *ObjFile::getFunction(const WasmSymbol &Sym) const { + uint32_t FunctionIndex = Sym.ElementIndex - NumFunctionImports; + return Functions[FunctionIndex]; +} + void ObjFile::initializeSymbols() { Symbols.reserve(WasmObj->getNumberOfSymbols()); for (const WasmImport &Import : WasmObj->imports()) { switch (Import.Kind) { case WASM_EXTERNAL_FUNCTION: - ++FunctionImports; + ++NumFunctionImports; break; case WASM_EXTERNAL_GLOBAL: - ++GlobalImports; + ++NumGlobalImports; break; } } - FunctionSymbols.resize(FunctionImports + WasmObj->functions().size()); - GlobalSymbols.resize(GlobalImports + WasmObj->globals().size()); + FunctionSymbols.resize(NumFunctionImports + WasmObj->functions().size()); + GlobalSymbols.resize(NumGlobalImports + WasmObj->globals().size()); for (const WasmSegment &S : WasmObj->dataSegments()) { - InputSegment *Seg = make(&S, this); + InputSegment *Seg = make(S, *this); copyRelocationsRange(Seg->Relocations, DataSection->Relocations, - Seg->getInputSectionOffset(), - Seg->getInputSectionOffset() + Seg->getSize()); + Seg->getInputSectionOffset(), Seg->getSize()); Segments.emplace_back(Seg); } + ArrayRef Funcs = WasmObj->functions(); + ArrayRef FuncTypes = WasmObj->functionTypes(); + ArrayRef Types = WasmObj->types(); + for (size_t I = 0; I < Funcs.size(); ++I) { + const WasmFunction &Func = Funcs[I]; + const WasmSignature &Sig = Types[FuncTypes[I]]; + InputFunction *Function = make(Sig, Func, *this); + copyRelocationsRange(Function->Relocations, CodeSection->Relocations, + Func.CodeSectionOffset, Func.Size); + Functions.emplace_back(Function); + } + // Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols // in the object for (const SymbolRef &Sym : WasmObj->symbols()) { @@ -179,14 +190,16 @@ Symbol *S; switch (WasmSym.Type) { case WasmSymbol::SymbolType::FUNCTION_IMPORT: + S = createUndefined(WasmSym, getFunctionSig(WasmSym)); + break; case WasmSymbol::SymbolType::GLOBAL_IMPORT: S = createUndefined(WasmSym); break; case WasmSymbol::SymbolType::GLOBAL_EXPORT: - S = createDefined(WasmSym, getSegment(WasmSym)); + S = createDefined(WasmSym, getSegment(WasmSym), nullptr); break; case WasmSymbol::SymbolType::FUNCTION_EXPORT: - S = createDefined(WasmSym); + S = createDefined(WasmSym, nullptr, getFunction(WasmSym)); break; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: // These are for debugging only, no need to create linker symbols for them @@ -228,7 +241,7 @@ fatal(getName() + ": unsupported element segment offset"); TableSymbols.reserve(Segment.Functions.size()); for (uint64_t FunctionIndex : Segment.Functions) - TableSymbols.push_back(getFunctionSymbol(FunctionIndex)); + TableSymbols.push_back(FunctionSymbols[FunctionIndex]); } DEBUG(dbgs() << "TableSymbols: " << TableSymbols.size() << "\n"); @@ -236,12 +249,14 @@ DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n"); } -Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { - return Symtab->addUndefined(this, &Sym); +Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, + const WasmSignature *Signature) { + return Symtab->addUndefined(this, &Sym, Signature); } Symbol *ObjFile::createDefined(const WasmSymbol &Sym, - const InputSegment *Segment) { + const InputSegment *Segment, + InputFunction *Function) { Symbol *S; if (Sym.isLocal()) { S = make(Sym.Name, true); @@ -252,10 +267,10 @@ Kind = Symbol::Kind::DefinedGlobalKind; else llvm_unreachable("invalid local symbol type"); - S->update(Kind, this, &Sym, Segment); + S->update(Kind, this, &Sym, Segment, Function); return S; } - return Symtab->addDefined(this, &Sym, Segment); + return Symtab->addDefined(this, &Sym, Segment, Function); } void ArchiveFile::parse() { Index: wasm/InputFunction.h =================================================================== --- wasm/InputFunction.h +++ wasm/InputFunction.h @@ -0,0 +1,57 @@ +//===- InpuFunction.h -------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Represents a WebAssembly function in an input file which could also be +// assigned a function index in the output. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_INPUT_FUNCTION_H +#define LLD_WASM_INPUT_FUNCTION_H + +#include "WriterUtils.h" +#include "llvm/Object/Wasm.h" + +using llvm::wasm::WasmRelocation; +using llvm::wasm::WasmFunction; + +namespace lld { +namespace wasm { + +class ObjFile; + +class InputFunction { +public: + InputFunction(const WasmSignature &S, const WasmFunction &Func, + const ObjFile &F) + : Signature(S), Function(Func), File(F) {} + + uint32_t getOutputIndex() const { return OutputIndex.getValue(); }; + bool hasOutputIndex() const { return OutputIndex.hasValue(); }; + + void setOutputIndex(uint32_t Index) { + assert(!hasOutputIndex()); + OutputIndex = Index; + }; + + const WasmSignature &Signature; + const WasmFunction &Function; + int32_t OutputOffset = 0; + std::vector Relocations; + std::vector OutRelocations; + const ObjFile &File; + +protected: + llvm::Optional OutputIndex; +}; + +} // namespace wasm +} // namespace lld + +#endif // LLD_WASM_INPUT_FUNCTION_H Index: wasm/InputSegment.h =================================================================== --- wasm/InputSegment.h +++ wasm/InputSegment.h @@ -36,7 +36,7 @@ class InputSegment { public: - InputSegment(const WasmSegment *Seg, const ObjFile *F) + InputSegment(const WasmSegment &Seg, const ObjFile &F) : Segment(Seg), File(F) {} // Translate an offset in the input segment to an offset in the output @@ -47,21 +47,21 @@ uint32_t getOutputSegmentOffset() const { return OutputSegmentOffset; } - uint32_t getInputSectionOffset() const { return Segment->SectionOffset; } + uint32_t getInputSectionOffset() const { return Segment.SectionOffset; } void setOutputSegment(const OutputSegment *Segment, uint32_t Offset) { OutputSeg = Segment; OutputSegmentOffset = Offset; } - uint32_t getSize() const { return Segment->Data.Content.size(); } - uint32_t getAlignment() const { return Segment->Data.Alignment; } - uint32_t startVA() const { return Segment->Data.Offset.Value.Int32; } + uint32_t getSize() const { return Segment.Data.Content.size(); } + uint32_t getAlignment() const { return Segment.Data.Alignment; } + uint32_t startVA() const { return Segment.Data.Offset.Value.Int32; } uint32_t endVA() const { return startVA() + getSize(); } - StringRef getName() const { return Segment->Data.Name; } + StringRef getName() const { return Segment.Data.Name; } - const WasmSegment *Segment; - const ObjFile *File; + const WasmSegment &Segment; + const ObjFile &File; std::vector Relocations; std::vector OutRelocations; Index: wasm/OutputSections.h =================================================================== --- wasm/OutputSections.h +++ wasm/OutputSections.h @@ -28,7 +28,7 @@ namespace wasm { class OutputSegment; -class ObjFile; +class InputFunction; class OutputSection { public: @@ -104,14 +104,14 @@ class CodeSection : public OutputSection { public: - explicit CodeSection(uint32_t NumFunctions, ArrayRef Objs); + explicit CodeSection(ArrayRef Functions); size_t getSize() const override { return Header.size() + BodySize; } void writeTo(uint8_t *Buf) override; uint32_t numRelocations() const override; void writeRelocations(raw_ostream &OS) const override; protected: - ArrayRef InputObjects; + ArrayRef Functions; std::string CodeSectionHeader; size_t BodySize = 0; }; Index: wasm/OutputSections.cpp =================================================================== --- wasm/OutputSections.cpp +++ wasm/OutputSections.cpp @@ -11,6 +11,7 @@ #include "Config.h" #include "InputFiles.h" +#include "InputFunction.h" #include "OutputSegment.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" @@ -150,6 +151,7 @@ for (const WasmRelocation &Reloc : Relocs) { OutputRelocation NewReloc; NewReloc.Reloc = Reloc; + assert(Reloc.Offset + OutputOffset > 0); NewReloc.Reloc.Offset += OutputOffset; DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index << " offset=" << Reloc.Offset @@ -191,27 +193,20 @@ " total=" + Twine(getSize())); } -CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef Objs) - : OutputSection(WASM_SEC_CODE), InputObjects(Objs) { +CodeSection::CodeSection(ArrayRef Functions) + : OutputSection(WASM_SEC_CODE), Functions(Functions) { + assert(Functions.size() > 0); + raw_string_ostream OS(CodeSectionHeader); - writeUleb128(OS, NumFunctions, "function count"); + writeUleb128(OS, Functions.size(), "function count"); OS.flush(); BodySize = CodeSectionHeader.size(); - for (ObjFile *File : InputObjects) { - if (!File->CodeSection) - continue; - - File->CodeOffset = BodySize; - ArrayRef Content = File->CodeSection->Content; - unsigned HeaderSize = 0; - decodeULEB128(Content.data(), &HeaderSize); - - calcRelocations(*File, File->CodeSection->Relocations, - File->CodeRelocations, BodySize - HeaderSize); - - size_t PayloadSize = Content.size() - HeaderSize; - BodySize += PayloadSize; + for (InputFunction *Func : Functions) { + Func->OutputOffset = BodySize; + calcRelocations(Func->File, Func->Relocations, Func->OutRelocations, + Func->OutputOffset - Func->Function.CodeSectionOffset); + BodySize += Func->Function.Size; } createHeader(BodySize); @@ -220,6 +215,8 @@ void CodeSection::writeTo(uint8_t *Buf) { log("writing " + toString(*this)); log(" size=" + Twine(getSize())); + log(" headersize=" + Twine(Header.size())); + log(" codeheadersize=" + Twine(CodeSectionHeader.size())); Buf += Offset; // Write section header @@ -233,35 +230,25 @@ Buf += CodeSectionHeader.size(); // Write code section bodies - parallelForEach(InputObjects, [ContentsStart](ObjFile *File) { - if (!File->CodeSection) - return; - - ArrayRef Content(File->CodeSection->Content); - - // Payload doesn't include the initial header (function count) - unsigned HeaderSize = 0; - decodeULEB128(Content.data(), &HeaderSize); - - size_t PayloadSize = Content.size() - HeaderSize; - memcpy(ContentsStart + File->CodeOffset, Content.data() + HeaderSize, - PayloadSize); - - log("applying relocations for: " + File->getName()); - applyRelocations(ContentsStart, File->CodeRelocations); + parallelForEach(Functions, [ContentsStart](InputFunction *Func) { + ArrayRef Content(Func->File.CodeSection->Content); + memcpy(ContentsStart + Func->OutputOffset, + Content.data() + Func->Function.CodeSectionOffset, + Func->Function.Size); + applyRelocations(ContentsStart, Func->OutRelocations); }); } uint32_t CodeSection::numRelocations() const { uint32_t Count = 0; - for (ObjFile *File : InputObjects) - Count += File->CodeRelocations.size(); + for (const InputFunction *Func : Functions) + Count += Func->OutRelocations.size(); return Count; } void CodeSection::writeRelocations(raw_ostream &OS) const { - for (ObjFile *File : InputObjects) - for (const OutputRelocation &Reloc : File->CodeRelocations) + for (const InputFunction *Func : Functions) + for (const OutputRelocation &Reloc : Func->OutRelocations) writeReloc(OS, Reloc); } @@ -289,7 +276,7 @@ uint32_t OutputOffset = Segment->getSectionOffset() + Segment->Header.size() + InputSeg->getOutputSegmentOffset(); - calcRelocations(*InputSeg->File, InputSeg->Relocations, + calcRelocations(InputSeg->File, InputSeg->Relocations, InputSeg->OutRelocations, OutputOffset - InputOffset); } BodySize += Segment->Size; @@ -319,7 +306,7 @@ // Write segment data payload for (const InputSegment *Input : Segment->InputSegments) { - ArrayRef Content(Input->Segment->Data.Content); + ArrayRef Content(Input->Segment.Data.Content); memcpy(SegStart + Segment->Header.size() + Input->getOutputSegmentOffset(), Content.data(), Content.size()); Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -50,8 +50,10 @@ Symbol *find(StringRef Name); Symbol *addDefined(InputFile *F, const WasmSymbol *Sym, - const InputSegment *Segment = nullptr); - Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym); + const InputSegment *Segment = nullptr, + InputFunction *Function = nullptr); + Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym, + const WasmSignature *Signature = nullptr); Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type); Symbol *addDefinedGlobal(StringRef Name); void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -10,6 +10,7 @@ #include "SymbolTable.h" #include "Config.h" +#include "InputFunction.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -76,16 +77,6 @@ toString(NewFile)); } -// Get the signature for a given function symbol, either by looking -// it up in function sections (for defined functions), of the imports section -// (for imported functions). -static const WasmSignature *getFunctionSig(const ObjFile &Obj, - const WasmSymbol &Sym) { - DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n"); - const WasmObjectFile *WasmObj = Obj.getWasmObj(); - return &WasmObj->types()[Sym.FunctionType]; -} - // Check the type of new symbol matches that of the symbol is replacing. // For functions this can also involve verifying that the signatures match. static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, @@ -140,32 +131,30 @@ } Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym, - const InputSegment *Segment) { + const InputSegment *Segment, + InputFunction *Function) { DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n"); Symbol *S; bool WasInserted; Symbol::Kind Kind = Symbol::DefinedFunctionKind; - const WasmSignature *NewSig = nullptr; if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT) Kind = Symbol::DefinedGlobalKind; - else - NewSig = getFunctionSig(*cast(F), *Sym); std::tie(S, WasInserted) = insert(Sym->Name); if (WasInserted) { - S->update(Kind, F, Sym, Segment, NewSig); + S->update(Kind, F, Sym, Segment, Function); } else if (S->isLazy()) { // The existing symbol is lazy. Replace it without checking types since // lazy symbols don't have any type information. DEBUG(dbgs() << "replacing existing lazy symbol: " << Sym->Name << "\n"); - S->update(Kind, F, Sym, Segment, NewSig); + S->update(Kind, F, Sym, Segment, Function); } else if (!S->isDefined()) { // The existing symbol table entry is undefined. The new symbol replaces // it, after checking the type matches DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name << "\n"); - checkSymbolTypes(*S, *F, *Sym, NewSig); - S->update(Kind, F, Sym, Segment, NewSig); + checkSymbolTypes(*S, *F, *Sym, Function ? &Function->Signature : nullptr); + S->update(Kind, F, Sym, Segment, Function); } else if (Sym->isWeak()) { // the new symbol is weak we can ignore it DEBUG(dbgs() << "existing symbol takes precedence\n"); @@ -173,8 +162,8 @@ // the new symbol is not weak and the existing symbol is, so we replace // it DEBUG(dbgs() << "replacing existing weak symbol\n"); - checkSymbolTypes(*S, *F, *Sym, NewSig); - S->update(Kind, F, Sym, Segment, NewSig); + checkSymbolTypes(*S, *F, *Sym, Function ? &Function->Signature : nullptr); + S->update(Kind, F, Sym, Segment, Function); } else { // neither symbol is week. They conflict. reportDuplicate(S, F); @@ -188,33 +177,34 @@ bool WasInserted; std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - S->update(Symbol::UndefinedFunctionKind, nullptr, nullptr, nullptr, Type); + S->update(Symbol::UndefinedFunctionKind); + S->setFunctionType(Type); } else if (!S->isFunction()) { error("symbol type mismatch: " + Name); } return S; } -Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) { +Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym, + const WasmSignature *Type) { DEBUG(dbgs() << "addUndefined: " << Sym->Name << "\n"); Symbol *S; bool WasInserted; Symbol::Kind Kind = Symbol::UndefinedFunctionKind; - const WasmSignature *NewSig = nullptr; if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT) Kind = Symbol::UndefinedGlobalKind; - else - NewSig = getFunctionSig(*cast(F), *Sym); std::tie(S, WasInserted) = insert(Sym->Name); if (WasInserted) { - S->update(Kind, F, Sym, nullptr, NewSig); + S->update(Kind, F, Sym); + if (Type) + S->setFunctionType(Type); } else if (S->isLazy()) { DEBUG(dbgs() << "resolved by existing lazy\n"); auto *AF = cast(S->getFile()); AF->addMember(&S->getArchiveSymbol()); } else if (S->isDefined()) { DEBUG(dbgs() << "resolved by existing\n"); - checkSymbolTypes(*S, *F, *Sym, NewSig); + checkSymbolTypes(*S, *F, *Sym, Type); } return S; } Index: wasm/Symbols.h =================================================================== --- wasm/Symbols.h +++ wasm/Symbols.h @@ -25,6 +25,7 @@ class InputFile; class InputSegment; +class InputFunction; class Symbol { public: @@ -66,16 +67,14 @@ // Returns the file from which this symbol was created. InputFile *getFile() const { return File; } - uint32_t getGlobalIndex() const; - uint32_t getFunctionIndex() const; - bool hasFunctionType() const { return FunctionType != nullptr; } const WasmSignature &getFunctionType() const; + void setFunctionType(const WasmSignature *Type); - uint32_t getOutputIndex() const { return OutputIndex.getValue(); } + uint32_t getOutputIndex() const; // Returns true if an output index has been set for this symbol - bool hasOutputIndex() const { return OutputIndex.hasValue(); } + bool hasOutputIndex() const; // Set the output index of the symbol (in the function or global index // space of the output object. @@ -97,7 +96,7 @@ void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr, const InputSegment *Segment = nullptr, - const WasmSignature *Sig = nullptr); + const InputFunction *Function = nullptr); void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; } const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; } @@ -116,10 +115,11 @@ InputFile *File = nullptr; const WasmSymbol *Sym = nullptr; const InputSegment *Segment = nullptr; + const InputFunction *Function = nullptr; llvm::Optional OutputIndex; llvm::Optional TableIndex; llvm::Optional VirtualAddress; - const WasmSignature *FunctionType; + const WasmSignature *FunctionType = nullptr; }; } // namespace wasm Index: wasm/Symbols.cpp =================================================================== --- wasm/Symbols.cpp +++ wasm/Symbols.cpp @@ -11,6 +11,7 @@ #include "Config.h" #include "InputFiles.h" +#include "InputFunction.h" #include "InputSegment.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" @@ -21,21 +22,20 @@ using namespace lld; using namespace lld::wasm; -uint32_t Symbol::getGlobalIndex() const { - assert(!Sym->isFunction()); - return Sym->ElementIndex; -} - -uint32_t Symbol::getFunctionIndex() const { - assert(Sym->isFunction()); - return Sym->ElementIndex; -} - const WasmSignature &Symbol::getFunctionType() const { + if (Function != nullptr) + return Function->Signature; + assert(FunctionType != nullptr); return *FunctionType; } +void Symbol::setFunctionType(const WasmSignature *Type) { + assert(FunctionType == nullptr); + assert(Function == nullptr); + FunctionType = Type; +} + uint32_t Symbol::getVirtualAddress() const { assert(isGlobal()); DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); @@ -44,15 +44,28 @@ if (VirtualAddress.hasValue()) return VirtualAddress.getValue(); - assert(Sym != nullptr); ObjFile *Obj = cast(File); + assert(Sym != nullptr); const WasmGlobal &Global = - Obj->getWasmObj()->globals()[getGlobalIndex() - Obj->NumGlobalImports()]; + Obj->getWasmObj() + ->globals()[Sym->ElementIndex - Obj->getNumGlobalImports()]; assert(Global.Type == llvm::wasm::WASM_TYPE_I32); assert(Segment); return Segment->translateVA(Global.InitExpr.Value.Int32); } +bool Symbol::hasOutputIndex() const { + if (Function) + return Function->hasOutputIndex(); + return OutputIndex.hasValue(); +} + +uint32_t Symbol::getOutputIndex() const { + if (Function) + return Function->getOutputIndex(); + return OutputIndex.getValue(); +} + void Symbol::setVirtualAddress(uint32_t Value) { DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); assert(!VirtualAddress.hasValue()); @@ -61,6 +74,7 @@ void Symbol::setOutputIndex(uint32_t Index) { DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n"); + assert(!Function); assert(!OutputIndex.hasValue()); OutputIndex = Index; } @@ -72,12 +86,12 @@ } void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym, - const InputSegment *Seg, const WasmSignature *Sig) { + const InputSegment *Seg, const InputFunction *Func) { SymbolKind = K; File = F; Sym = WasmSym; Segment = Seg; - FunctionType = Sig; + Function = Func; } bool Symbol::isWeak() const { return Sym && Sym->isWeak(); } Index: wasm/Writer.cpp =================================================================== --- wasm/Writer.cpp +++ wasm/Writer.cpp @@ -10,6 +10,7 @@ #include "Writer.h" #include "Config.h" +#include "InputFunction.h" #include "OutputSections.h" #include "OutputSegment.h" #include "SymbolTable.h" @@ -68,7 +69,7 @@ void openFile(); uint32_t getTypeIndex(const WasmSignature &Sig); - void assignSymbolIndexes(); + void assignIndexes(); void calculateImports(); void calculateOffsets(); void calculateTypes(); @@ -102,15 +103,15 @@ uint64_t FileSize = 0; uint32_t DataSize = 0; - uint32_t NumFunctions = 0; uint32_t NumMemoryPages = 0; uint32_t InitialTableOffset = 0; std::vector Types; DenseMap TypeIndices; - std::vector FunctionImports; - std::vector GlobalImports; + std::vector ImportedFunctions; + std::vector ImportedGlobals; std::vector DefinedGlobals; + std::vector DefinedFunctions; std::vector IndirectFunctions; // Elements that are used to construct the final output @@ -136,7 +137,7 @@ } void Writer::createImportSection() { - uint32_t NumImports = FunctionImports.size() + GlobalImports.size(); + uint32_t NumImports = ImportedFunctions.size() + ImportedGlobals.size(); if (Config->ImportMemory) ++NumImports; @@ -148,7 +149,7 @@ writeUleb128(OS, NumImports, "import count"); - for (const Symbol *Sym : FunctionImports) { + for (const Symbol *Sym : ImportedFunctions) { WasmImport Import; Import.Module = "env"; Import.Field = Sym->getName(); @@ -168,7 +169,7 @@ writeImport(OS, Import); } - for (const Symbol *Sym : GlobalImports) { + for (const Symbol *Sym : ImportedGlobals) { WasmImport Import; Import.Module = "env"; Import.Field = Sym->getName(); @@ -188,16 +189,15 @@ } void Writer::createFunctionSection() { - if (!NumFunctions) + if (DefinedFunctions.empty()) return; SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION); raw_ostream &OS = Section->getStream(); - writeUleb128(OS, NumFunctions, "function count"); - for (ObjFile *File : Symtab->ObjectFiles) - for (uint32_t Sig : File->getWasmObj()->functionTypes()) - writeUleb128(OS, File->relocateTypeIndex(Sig), "sig index"); + writeUleb128(OS, DefinedFunctions.size(), "function count"); + for (const InputFunction *Func : DefinedFunctions) + writeUleb128(OS, TypeIndices.lookup(Func->Signature), "sig index"); } void Writer::createMemorySection() { @@ -337,12 +337,12 @@ } void Writer::createCodeSection() { - if (!NumFunctions) + if (DefinedFunctions.empty()) return; log("createCodeSection"); - auto Section = make(NumFunctions, Symtab->ObjectFiles); + auto Section = make(DefinedFunctions); OutputSections.push_back(Section); } @@ -555,32 +555,17 @@ } } -void Writer::calculateOffsets() { - for (ObjFile *File : Symtab->ObjectFiles) { - const WasmObjectFile *WasmFile = File->getWasmObj(); - - // Function Index - File->FunctionIndexOffset = - FunctionImports.size() - File->NumFunctionImports() + NumFunctions; - NumFunctions += WasmFile->functions().size(); - - // Memory - if (WasmFile->memories().size() > 1) - fatal(File->getName() + ": contains more than one memory"); - } -} - void Writer::calculateImports() { for (Symbol *Sym : Symtab->getSymbols()) { if (!Sym->isUndefined() || Sym->isWeak()) continue; if (Sym->isFunction()) { - Sym->setOutputIndex(FunctionImports.size()); - FunctionImports.push_back(Sym); + Sym->setOutputIndex(ImportedFunctions.size()); + ImportedFunctions.push_back(Sym); } else { - Sym->setOutputIndex(GlobalImports.size()); - GlobalImports.push_back(Sym); + Sym->setOutputIndex(ImportedGlobals.size()); + ImportedGlobals.push_back(Sym); } } } @@ -600,8 +585,9 @@ } } -void Writer::assignSymbolIndexes() { - uint32_t GlobalIndex = GlobalImports.size(); +void Writer::assignIndexes() { + uint32_t GlobalIndex = ImportedGlobals.size(); + uint32_t FunctionIndex = ImportedFunctions.size(); if (Config->StackPointerSymbol) { DefinedGlobals.emplace_back(Config->StackPointerSymbol); @@ -614,17 +600,15 @@ uint32_t TableIndex = InitialTableOffset; for (ObjFile *File : Symtab->ObjectFiles) { - DEBUG(dbgs() << "assignSymbolIndexes: " << File->getName() << "\n"); + if (Config->EmitRelocs) { + DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); + for (Symbol *Sym : File->getSymbols()) { + // Create wasm globals for data symbols defined in this file + if (!Sym->isDefined() || File != Sym->getFile()) + continue; + if (Sym->isFunction()) + continue; - for (Symbol *Sym : File->getSymbols()) { - // Assign indexes for symbols defined with this file. - if (!Sym->isDefined() || File != Sym->getFile()) - continue; - if (Sym->isFunction()) { - auto *Obj = cast(Sym->getFile()); - Sym->setOutputIndex(Obj->FunctionIndexOffset + - Sym->getFunctionIndex()); - } else if (Config->EmitRelocs) { DefinedGlobals.emplace_back(Sym); Sym->setOutputIndex(GlobalIndex++); } @@ -632,6 +616,15 @@ } for (ObjFile *File : Symtab->ObjectFiles) { + DEBUG(dbgs() << "Functions: " << File->getName() << "\n"); + for (InputFunction *Func : File->Functions) { + DefinedFunctions.emplace_back(Func); + Func->setOutputIndex(FunctionIndex++); + } + } + + for (ObjFile *File : Symtab->ObjectFiles) { + DEBUG(dbgs() << "Table Indexes: " << File->getName() << "\n"); for (Symbol *Sym : File->getTableSymbols()) { if (Sym->hasTableIndex() || !Sym->hasOutputIndex()) continue; @@ -681,22 +674,20 @@ calculateTypes(); log("-- calculateImports"); calculateImports(); - log("-- calculateOffsets"); - calculateOffsets(); + log("-- assignIndexes"); + assignIndexes(); if (errorHandler().Verbose) { - log("Defined Functions: " + Twine(NumFunctions)); + log("Defined Functions: " + Twine(DefinedFunctions.size())); log("Defined Globals : " + Twine(DefinedGlobals.size())); - log("Function Imports : " + Twine(FunctionImports.size())); - log("Global Imports : " + Twine(GlobalImports.size())); + log("Function Imports : " + Twine(ImportedFunctions.size())); + log("Global Imports : " + Twine(ImportedGlobals.size())); log("Total Imports : " + - Twine(FunctionImports.size() + GlobalImports.size())); + Twine(ImportedFunctions.size() + ImportedGlobals.size())); for (ObjFile *File : Symtab->ObjectFiles) File->dumpInfo(); } - log("-- assignSymbolIndexes"); - assignSymbolIndexes(); log("-- layoutMemory"); layoutMemory();