Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -26,11 +26,14 @@ using llvm::object::WasmSection; using llvm::object::WasmSymbol; using llvm::wasm::WasmImport; +using llvm::wasm::WasmSignature; +using llvm::wasm::WasmFunction; namespace lld { namespace wasm { class Symbol; +class InputFunction; class InputSegment; class InputFile { @@ -95,31 +98,32 @@ 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 getNumFunctionImports() const { return NumFunctionImports; } + 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: + // Returns true if the given function index is an imported function, + // as opposed to the locally defined function. + bool isImportedFunction(uint32_t Index) const; + 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); + InputSegment *getSegment(const WasmSymbol &WasmSym) const; + const WasmSignature *getFunctionSig(const WasmSymbol &Sym) const; + InputFunction *getFunction(const WasmSymbol &Sym) const; Symbol *getFunctionSymbol(uint32_t FunctionIndex) const; Symbol *getTableSymbol(uint32_t TableIndex) const; Symbol *getGlobalSymbol(uint32_t GlobalIndex) const; @@ -136,8 +140,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" @@ -27,6 +28,8 @@ using namespace llvm::object; using namespace llvm::wasm; +using llvm::wasm::WasmFunction; + Optional lld::wasm::readFile(StringRef Path) { log("Loading: " + Path); @@ -43,14 +46,16 @@ } 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(); + return Index < NumFunctionImports; } Symbol *ObjFile::getFunctionSymbol(uint32_t Index) const { @@ -125,7 +130,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 +146,69 @@ 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"); + uint32_t FunctionType; + if (isImportedFunction(Sym.ElementIndex)) { + const WasmImport &Import = WasmObj->imports()[Sym.ImportIndex]; + FunctionType = Import.SigIndex; + } else { + uint32_t FuntionIndex = Sym.ElementIndex - NumFunctionImports; + FunctionType = WasmObj->functionTypes()[FuntionIndex]; + } + return &WasmObj->types()[FunctionType]; +} + +InputFunction *ObjFile::getFunction(const WasmSymbol &Sym) const { + uint32_t FuntionIndex = Sym.ElementIndex - NumFunctionImports; + return Functions[FuntionIndex]; +} + 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 +216,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 @@ -227,12 +266,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); @@ -243,10 +284,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 =================================================================== --- /dev/null +++ wasm/InputFunction.h @@ -0,0 +1,58 @@ +//===- 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 getSize() const { return 0; } + 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 @@ -35,7 +35,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 @@ -46,21 +46,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; protected: 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: @@ -38,7 +38,7 @@ virtual ~OutputSection() = default; void setOffset(size_t NewOffset) { - log("setOffset: " + toString(this) + " -> " + Twine(NewOffset)); + log("setOffset: " + toString(this) + ": " + Twine(NewOffset)); Offset = NewOffset; } @@ -105,14 +105,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 @@ -188,27 +190,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); @@ -217,6 +212,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 @@ -230,36 +227,26 @@ 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()); - if (File->CodeRelocations.size()) - 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); + if (Func->OutRelocations.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); } @@ -287,7 +274,7 @@ uint32_t OutputOffset = Segment->getSectionOffset() + Segment->Header.size() + InputSeg->getOutputSegmentOffset(); - calcRelocations(*InputSeg->File, InputSeg->Relocations, Relocations, + calcRelocations(InputSeg->File, InputSeg->Relocations, Relocations, OutputOffset - InputOffset); } BodySize += Segment->Size; @@ -317,7 +304,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 @@ -51,8 +51,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,24 +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(); - uint32_t FunctionType; - if (Obj.isImportedFunction(Sym.ElementIndex)) { - const WasmImport &Import = WasmObj->imports()[Sym.ImportIndex]; - FunctionType = Import.SigIndex; - } else { - uint32_t FuntionIndex = Sym.ElementIndex - Obj.NumFunctionImports(); - FunctionType = WasmObj->functionTypes()[FuntionIndex]; - } - return &WasmObj->types()[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, @@ -148,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"); @@ -181,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); @@ -196,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: @@ -71,6 +72,7 @@ bool hasFunctionType() const { return FunctionType != nullptr; } const WasmSignature &getFunctionType() const; + void setFunctionType(const WasmSignature *Type); uint32_t getOutputIndex() const; uint32_t getTableIndex() const { return TableIndex.getValue(); } @@ -92,7 +94,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; } @@ -111,10 +113,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" @@ -32,10 +33,19 @@ } 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"); @@ -47,7 +57,8 @@ assert(Sym != nullptr); ObjFile *Obj = cast(File); const WasmGlobal &Global = - Obj->getWasmObj()->globals()[getGlobalIndex() - Obj->NumGlobalImports()]; + Obj->getWasmObj() + ->globals()[getGlobalIndex() - Obj->getNumGlobalImports()]; assert(Global.Type == llvm::wasm::WASM_TYPE_I32); assert(Segment); return Segment->translateVA(Global.InitExpr.Value.Int32); @@ -56,6 +67,8 @@ uint32_t Symbol::getOutputIndex() const { if (isUndefined() && isWeak()) return 0; + if (Function) + return Function->getOutputIndex(); return OutputIndex.getValue(); } @@ -67,6 +80,7 @@ void Symbol::setOutputIndex(uint32_t Index) { DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n"); + assert(!Function); assert(!OutputIndex.hasValue()); OutputIndex = Index; } @@ -78,12 +92,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(); @@ -189,17 +190,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"); } } @@ -340,12 +339,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); } @@ -534,32 +533,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); } } } @@ -579,8 +563,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); @@ -593,22 +578,26 @@ uint32_t TableIndex = InitialTableOffset; for (ObjFile *File : Symtab->ObjectFiles) { - DEBUG(dbgs() << "assignSymbolIndexes: " << File->getName() << "\n"); + DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); 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++); - } + if (Sym->isFunction() || !Config->EmitRelocs) + continue; + + DefinedGlobals.emplace_back(Sym); + Sym->setOutputIndex(GlobalIndex++); + } + + DEBUG(dbgs() << "Functions: " << File->getName() << "\n"); + for (InputFunction *Func : File->Functions) { + DefinedFunctions.emplace_back(Func); + Func->setOutputIndex(FunctionIndex++); } + DEBUG(dbgs() << "Table Indexes: " << File->getName() << "\n"); for (Symbol *Sym : File->getTableSymbols()) { if (!Sym->hasTableIndex()) { Sym->setTableIndex(TableIndex++); @@ -658,22 +647,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();