[WebAssembly] Output functions individually

The code section is now written out one function
at a time rather than all the functions in a given
objects being serialized at once.

This change lays the groundwork for supporting
--gc-sections.

Differential Revision: https://reviews.llvm.org/D41315

llvm-svn: 322138
This commit is contained in:
Sam Clegg 2018-01-09 23:56:44 +00:00
parent 1f562176e9
commit 8d146bbc0c
11 changed files with 266 additions and 214 deletions

View File

@ -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 @@ Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) {
}
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::relocateTypeIndex(uint32_t Original) const {
}
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::relocateTableIndex(uint32_t Original) const {
}
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 @@ void ObjFile::parse() {
}
// 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 @@ InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) {
static void copyRelocationsRange(std::vector<WasmRelocation> &To,
ArrayRef<WasmRelocation> 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<InputSegment>(&S, this);
InputSegment *Seg = make<InputSegment>(S, *this);
copyRelocationsRange(Seg->Relocations, DataSection->Relocations,
Seg->getInputSectionOffset(),
Seg->getInputSectionOffset() + Seg->getSize());
Seg->getInputSectionOffset(), Seg->getSize());
Segments.emplace_back(Seg);
}
ArrayRef<WasmFunction> Funcs = WasmObj->functions();
ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes();
ArrayRef<WasmSignature> 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<InputFunction>(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 @@ void ObjFile::initializeSymbols() {
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 @@ void ObjFile::initializeSymbols() {
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 @@ void ObjFile::initializeSymbols() {
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<Symbol>(Sym.Name, true);
@ -252,10 +267,10 @@ Symbol *ObjFile::createDefined(const WasmSymbol &Sym,
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() {

View File

@ -26,11 +26,13 @@ using llvm::object::WasmObjectFile;
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 @@ public:
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<OutputRelocation> CodeRelocations;
int32_t CodeOffset = 0;
const WasmSection *DataSection = nullptr;
std::vector<uint32_t> TypeMap;
std::vector<InputSegment *> Segments;
std::vector<InputFunction *> Functions;
ArrayRef<Symbol *> getSymbols() { return Symbols; }
ArrayRef<Symbol *> 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<Symbol *> Symbols;
@ -136,8 +131,9 @@ private:
// List of all indirect symbols indexed by table index space.
std::vector<Symbol *> TableSymbols;
uint32_t GlobalImports = 0;
uint32_t FunctionImports = 0;
const WasmSection *DataSection = nullptr;
uint32_t NumGlobalImports = 0;
uint32_t NumFunctionImports = 0;
std::unique_ptr<WasmObjectFile> WasmObj;
};

57
lld/wasm/InputFunction.h Normal file
View File

@ -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<WasmRelocation> Relocations;
std::vector<OutputRelocation> OutRelocations;
const ObjFile &File;
protected:
llvm::Optional<uint32_t> OutputIndex;
};
} // namespace wasm
} // namespace lld
#endif // LLD_WASM_INPUT_FUNCTION_H

View File

@ -36,7 +36,7 @@ class OutputSegment;
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 @@ public:
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<WasmRelocation> Relocations;
std::vector<OutputRelocation> OutRelocations;

View File

@ -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 @@ static void calcRelocations(const ObjFile &File,
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 @@ void OutputSection::createHeader(size_t BodySize) {
" total=" + Twine(getSize()));
}
CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs)
: OutputSection(WASM_SEC_CODE), InputObjects(Objs) {
CodeSection::CodeSection(ArrayRef<InputFunction *> 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<uint8_t> 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 @@ CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs)
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 @@ void CodeSection::writeTo(uint8_t *Buf) {
Buf += CodeSectionHeader.size();
// Write code section bodies
parallelForEach(InputObjects, [ContentsStart](ObjFile *File) {
if (!File->CodeSection)
return;
ArrayRef<uint8_t> 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<uint8_t> 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 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments)
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 @@ void DataSection::writeTo(uint8_t *Buf) {
// Write segment data payload
for (const InputSegment *Input : Segment->InputSegments) {
ArrayRef<uint8_t> Content(Input->Segment->Data.Content);
ArrayRef<uint8_t> Content(Input->Segment.Data.Content);
memcpy(SegStart + Segment->Header.size() +
Input->getOutputSegmentOffset(),
Content.data(), Content.size());

View File

@ -28,7 +28,7 @@ std::string toString(const wasm::OutputSection &Section);
namespace wasm {
class OutputSegment;
class ObjFile;
class InputFunction;
class OutputSection {
public:
@ -104,14 +104,14 @@ public:
class CodeSection : public OutputSection {
public:
explicit CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs);
explicit CodeSection(ArrayRef<InputFunction *> 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<ObjFile *> InputObjects;
ArrayRef<InputFunction *> Functions;
std::string CodeSectionHeader;
size_t BodySize = 0;
};

View File

@ -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 @@ void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
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::addDefinedGlobal(StringRef Name) {
}
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<ObjFile>(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 @@ Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym,
// 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 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef Name,
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<ObjFile>(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<ArchiveFile>(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;
}

View File

@ -50,8 +50,10 @@ public:
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);

View File

@ -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 llvm;
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 @@ uint32_t Symbol::getVirtualAddress() const {
if (VirtualAddress.hasValue())
return VirtualAddress.getValue();
assert(Sym != nullptr);
ObjFile *Obj = cast<ObjFile>(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::setVirtualAddress(uint32_t Value) {
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::setTableIndex(uint32_t Index) {
}
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(); }

View File

@ -25,6 +25,7 @@ namespace wasm {
class InputFile;
class InputSegment;
class InputFunction;
class Symbol {
public:
@ -66,16 +67,14 @@ public:
// 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 @@ public:
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 @@ protected:
InputFile *File = nullptr;
const WasmSymbol *Sym = nullptr;
const InputSegment *Segment = nullptr;
const InputFunction *Function = nullptr;
llvm::Optional<uint32_t> OutputIndex;
llvm::Optional<uint32_t> TableIndex;
llvm::Optional<uint32_t> VirtualAddress;
const WasmSignature *FunctionType;
const WasmSignature *FunctionType = nullptr;
};
} // namespace wasm

View File

@ -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 @@ private:
void openFile();
uint32_t getTypeIndex(const WasmSignature &Sig);
void assignSymbolIndexes();
void assignIndexes();
void calculateImports();
void calculateOffsets();
void calculateTypes();
@ -102,15 +103,15 @@ private:
uint64_t FileSize = 0;
uint32_t DataSize = 0;
uint32_t NumFunctions = 0;
uint32_t NumMemoryPages = 0;
uint32_t InitialTableOffset = 0;
std::vector<const WasmSignature *> Types;
DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices;
std::vector<const Symbol *> FunctionImports;
std::vector<const Symbol *> GlobalImports;
std::vector<const Symbol *> ImportedFunctions;
std::vector<const Symbol *> ImportedGlobals;
std::vector<const Symbol *> DefinedGlobals;
std::vector<InputFunction *> DefinedFunctions;
std::vector<const Symbol *> IndirectFunctions;
// Elements that are used to construct the final output
@ -136,7 +137,7 @@ static void debugPrint(const char *fmt, ...) {
}
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 @@ void Writer::createImportSection() {
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 @@ void Writer::createImportSection() {
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::createTypeSection() {
}
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::createElemSection() {
}
void Writer::createCodeSection() {
if (!NumFunctions)
if (DefinedFunctions.empty())
return;
log("createCodeSection");
auto Section = make<CodeSection>(NumFunctions, Symtab->ObjectFiles);
auto Section = make<CodeSection>(DefinedFunctions);
OutputSections.push_back(Section);
}
@ -555,32 +555,17 @@ void Writer::createSections() {
}
}
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::calculateTypes() {
}
}
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 @@ void Writer::assignSymbolIndexes() {
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()) {
// Assign indexes for symbols defined with this file.
// Create wasm globals for data symbols defined in this file
if (!Sym->isDefined() || File != Sym->getFile())
continue;
if (Sym->isFunction()) {
auto *Obj = cast<ObjFile>(Sym->getFile());
Sym->setOutputIndex(Obj->FunctionIndexOffset +
Sym->getFunctionIndex());
} else if (Config->EmitRelocs) {
if (Sym->isFunction())
continue;
DefinedGlobals.emplace_back(Sym);
Sym->setOutputIndex(GlobalIndex++);
}
@ -632,6 +616,15 @@ void Writer::assignSymbolIndexes() {
}
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 @@ void Writer::run() {
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();