[WebAssembly] Use a Symbol class heirarchy. NFC.

This brings wasm into line with ELF and COFF in terms of
symbol types are represented.

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

llvm-svn: 325150
This commit is contained in:
Sam Clegg 2018-02-14 18:27:59 +00:00
parent 2ec8373633
commit dfb0b2c78f
7 changed files with 300 additions and 199 deletions

View File

@ -51,11 +51,14 @@ void ObjFile::dumpInfo() const {
}
uint32_t ObjFile::relocateVirtualAddress(uint32_t GlobalIndex) const {
return getGlobalSymbol(GlobalIndex)->getVirtualAddress();
if (auto *DG = dyn_cast<DefinedGlobal>(getGlobalSymbol(GlobalIndex)))
return DG->getVirtualAddress();
else
return 0;
}
uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const {
const Symbol *Sym = getFunctionSymbol(Original);
const FunctionSymbol *Sym = getFunctionSymbol(Original);
uint32_t Index = Sym->getOutputIndex();
DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": "
<< Original << " -> " << Index << "\n");
@ -68,7 +71,7 @@ uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const {
}
uint32_t ObjFile::relocateTableIndex(uint32_t Original) const {
const Symbol *Sym = getFunctionSymbol(Original);
const FunctionSymbol *Sym = getFunctionSymbol(Original);
uint32_t Index = Sym->hasTableIndex() ? Sym->getTableIndex() : 0;
DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original
<< " -> " << Index << "\n");
@ -249,7 +252,7 @@ void ObjFile::initializeSymbols() {
case WasmSymbol::SymbolType::FUNCTION_EXPORT: {
InputFunction *Function = getFunction(WasmSym);
if (!isExcludedByComdat(Function)) {
S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, Function);
S = createDefinedFunction(WasmSym, Function);
break;
} else {
Function->Live = false;
@ -263,8 +266,7 @@ void ObjFile::initializeSymbols() {
case WasmSymbol::SymbolType::GLOBAL_EXPORT: {
InputSegment *Segment = getSegment(WasmSym);
if (!isExcludedByComdat(Segment)) {
S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind, Segment,
getGlobalValue(WasmSym));
S = createDefinedGlobal(WasmSym, Segment, getGlobalValue(WasmSym));
break;
} else {
Segment->Live = false;
@ -302,15 +304,18 @@ Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature);
}
Symbol *ObjFile::createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,
InputChunk *Chunk, uint32_t Address) {
Symbol *S;
if (Sym.isBindingLocal()) {
S = make<Symbol>(Sym.Name, true);
S->update(Kind, this, Sym.Flags, Chunk, Address);
return S;
}
return Symtab->addDefined(Sym.Name, Kind, Sym.Flags, this, Chunk, Address);
Symbol *ObjFile::createDefinedFunction(const WasmSymbol &Sym,
InputChunk *Chunk) {
if (Sym.isBindingLocal())
return make<DefinedFunction>(Sym.Name, Sym.Flags, this, Chunk);
return Symtab->addDefined(true, Sym.Name, Sym.Flags, this, Chunk);
}
Symbol *ObjFile::createDefinedGlobal(const WasmSymbol &Sym, InputChunk *Chunk,
uint32_t Address) {
if (Sym.isBindingLocal())
return make<DefinedGlobal>(Sym.Name, Sym.Flags, this, Chunk, Address);
return Symtab->addDefined(false, Sym.Name, Sym.Flags, this, Chunk, Address);
}
void ArchiveFile::parse() {

View File

@ -107,11 +107,13 @@ public:
ArrayRef<Symbol *> getSymbols() const { return Symbols; }
Symbol *getFunctionSymbol(uint32_t Index) const {
return FunctionSymbols[Index];
FunctionSymbol *getFunctionSymbol(uint32_t Index) const {
return cast<FunctionSymbol>(FunctionSymbols[Index]);
}
Symbol *getGlobalSymbol(uint32_t Index) const { return GlobalSymbols[Index]; }
GlobalSymbol *getGlobalSymbol(uint32_t Index) const {
return cast<GlobalSymbol>(GlobalSymbols[Index]);
}
private:
uint32_t relocateVirtualAddress(uint32_t Index) const;
@ -119,9 +121,9 @@ private:
uint32_t relocateGlobalIndex(uint32_t Original) const;
uint32_t relocateTableIndex(uint32_t Original) const;
Symbol *createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,
InputChunk *Chunk = nullptr,
uint32_t Address = UINT32_MAX);
Symbol *createDefinedGlobal(const WasmSymbol &Sym, InputChunk *Chunk,
uint32_t Address);
Symbol *createDefinedFunction(const WasmSymbol &Sym, InputChunk *Chunk);
Symbol *createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
const WasmSignature *Signature = nullptr);
void initializeSymbols();

View File

@ -66,7 +66,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) {
Symbol *&Sym = SymMap[CachedHashStringRef(Name)];
if (Sym)
return {Sym, false};
Sym = make<Symbol>(Name, false);
Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>());
SymVector.emplace_back(Sym);
return {Sym, true};
}
@ -80,13 +80,10 @@ void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) {
// 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,
Symbol::Kind Kind, const WasmSignature *NewSig) {
bool NewIsFunction, const WasmSignature *NewSig) {
if (Existing.isLazy())
return;
bool NewIsFunction = Kind == Symbol::Kind::UndefinedFunctionKind ||
Kind == Symbol::Kind::DefinedFunctionKind;
// First check the symbol types match (i.e. either both are function
// symbols or both are data symbols).
if (Existing.isFunction() != NewIsFunction) {
@ -98,105 +95,102 @@ static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
}
// For function symbols, optionally check the function signature matches too.
if (!NewIsFunction || !Config->CheckSignatures)
auto *ExistingFunc = dyn_cast<FunctionSymbol>(&Existing);
if (!ExistingFunc || !Config->CheckSignatures)
return;
// Skip the signature check if the existing function has no signature (e.g.
// if it is an undefined symbol generated by --undefined command line flag).
if (!Existing.hasFunctionType())
if (!ExistingFunc->hasFunctionType())
return;
DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n");
DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n");
assert(NewSig);
const WasmSignature &OldSig = Existing.getFunctionType();
const WasmSignature &OldSig = ExistingFunc->getFunctionType();
if (*NewSig == OldSig)
return;
error("function signature mismatch: " + Existing.getName() +
error("function signature mismatch: " + ExistingFunc->getName() +
"\n>>> defined as " + toString(OldSig) + " in " +
toString(Existing.getFile()) + "\n>>> defined as " + toString(*NewSig) +
" in " + F.getName());
toString(ExistingFunc->getFile()) + "\n>>> defined as " +
toString(*NewSig) + " in " + F.getName());
}
static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
Symbol::Kind Kind, const InputChunk *Chunk) {
bool IsFunction, const InputChunk *Chunk) {
const WasmSignature *Sig = nullptr;
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
Sig = &F->Signature;
return checkSymbolTypes(Existing, F, Kind, Sig);
return checkSymbolTypes(Existing, F, IsFunction, Sig);
}
Symbol *SymbolTable::addSyntheticFunction(StringRef Name,
const WasmSignature *Type,
uint32_t Flags) {
DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name,
const WasmSignature *Type,
uint32_t Flags) {
DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
assert(WasInserted);
S->update(Symbol::DefinedFunctionKind, nullptr, Flags);
S->setFunctionType(Type);
return S;
return replaceSymbol<DefinedFunction>(S, Name, Flags, Type);
}
Symbol *SymbolTable::addSyntheticGlobal(StringRef Name) {
DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags) {
DEBUG(dbgs() << "addSyntheticGlobal: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
assert(WasInserted);
S->update(Symbol::DefinedGlobalKind);
return S;
return replaceSymbol<DefinedGlobal>(S, Name, Flags);
}
Symbol *SymbolTable::addDefined(StringRef Name, Symbol::Kind Kind,
uint32_t Flags, InputFile *F, InputChunk *Chunk,
Symbol *SymbolTable::addDefined(bool IsFunction, StringRef Name, uint32_t Flags,
InputFile *F, InputChunk *Chunk,
uint32_t Address) {
DEBUG(dbgs() << "addDefined: " << Name << " addr:" << Address << "\n");
if (IsFunction)
DEBUG(dbgs() << "addDefined: func:" << Name << "\n");
else
DEBUG(dbgs() << "addDefined: global:" << Name << " addr:" << Address
<< "\n");
Symbol *S;
bool WasInserted;
bool Replace = false;
bool CheckTypes = false;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
S->update(Kind, F, Flags, Chunk, Address);
Replace = true;
} else if (S->isLazy()) {
// The existing symbol is lazy. Replace it without checking types since
// Existing symbol is lazy. Replace it without checking types since
// lazy symbols don't have any type information.
DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n");
S->update(Kind, F, Flags, Chunk, Address);
Replace = true;
} else if (!S->isDefined()) {
// The existing symbol table entry is undefined. The new symbol replaces
// it, after checking the type matches
// Existing symbol is undefined: replace it, while check types.
DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n");
checkSymbolTypes(*S, *F, Kind, Chunk);
S->update(Kind, F, Flags, Chunk, Address);
Replace = true;
CheckTypes = true;
} else if ((Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) {
// the new symbol is weak we can ignore it
DEBUG(dbgs() << "existing symbol takes precedence\n");
} else if (S->isWeak()) {
// the new symbol is not weak and the existing symbol is, so we replace
// it
// the existing symbol is, so we replace it
DEBUG(dbgs() << "replacing existing weak symbol\n");
checkSymbolTypes(*S, *F, Kind, Chunk);
S->update(Kind, F, Flags, Chunk, Address);
Replace = true;
CheckTypes = true;
} else {
// neither symbol is week. They conflict.
reportDuplicate(S, F);
}
return S;
}
Symbol *SymbolTable::addUndefinedFunction(StringRef Name,
const WasmSignature *Type) {
DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n");
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
S->update(Symbol::UndefinedFunctionKind);
S->setFunctionType(Type);
} else if (!S->isFunction()) {
error("symbol type mismatch: " + Name);
if (Replace) {
if (CheckTypes)
checkSymbolTypes(*S, *F, IsFunction, Chunk);
if (IsFunction)
replaceSymbol<DefinedFunction>(S, Name, Flags, F, Chunk);
else
replaceSymbol<DefinedGlobal>(S, Name, Flags, F, Chunk, Address);
}
return S;
}
@ -208,17 +202,19 @@ Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
Symbol *S;
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
bool IsFunction = Kind == Symbol::UndefinedFunctionKind;
if (WasInserted) {
S->update(Kind, F, Flags);
if (Type)
S->setFunctionType(Type);
} else if (S->isLazy()) {
if (IsFunction)
replaceSymbol<UndefinedFunction>(S, Name, Flags, F, Type);
else
replaceSymbol<UndefinedGlobal>(S, Name, Flags, F);
} else if (auto *LazySym = dyn_cast<LazySymbol>(S)) {
DEBUG(dbgs() << "resolved by existing lazy\n");
auto *AF = cast<ArchiveFile>(S->getFile());
AF->addMember(&S->getArchiveSymbol());
auto *AF = cast<ArchiveFile>(LazySym->getFile());
AF->addMember(&LazySym->getArchiveSymbol());
} else if (S->isDefined()) {
DEBUG(dbgs() << "resolved by existing\n");
checkSymbolTypes(*S, *F, Kind, Type);
checkSymbolTypes(*S, *F, IsFunction, Type);
}
return S;
}
@ -230,8 +226,7 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) {
bool WasInserted;
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
S->update(Symbol::LazyKind, F);
S->setArchiveSymbol(*Sym);
replaceSymbol<LazySymbol>(S, Name, F, *Sym);
} else if (S->isUndefined()) {
// There is an existing undefined symbol. The can load from the
// archive.

View File

@ -49,7 +49,7 @@ public:
Symbol *find(StringRef Name);
ObjFile *findComdat(StringRef Name) const;
Symbol *addDefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
Symbol *addDefined(bool IsFunction, StringRef Name, uint32_t Flags,
InputFile *F, InputChunk *Chunk = nullptr,
uint32_t Address = 0);
Symbol *addUndefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
@ -58,9 +58,10 @@ public:
void addLazy(ArchiveFile *F, const Archive::Symbol *Sym);
bool addComdat(StringRef Name, ObjFile *);
Symbol *addSyntheticGlobal(StringRef Name);
Symbol *addSyntheticFunction(StringRef Name, const WasmSignature *Type,
uint32_t Flags);
DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags = 0);
DefinedFunction *addSyntheticFunction(StringRef Name,
const WasmSignature *Type,
uint32_t Flags = 0);
private:
std::pair<Symbol *, bool> insert(StringRef Name);

View File

@ -22,32 +22,11 @@ using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
Symbol *WasmSym::CallCtors;
Symbol *WasmSym::DsoHandle;
Symbol *WasmSym::DataEnd;
Symbol *WasmSym::HeapBase;
Symbol *WasmSym::StackPointer;
const WasmSignature &Symbol::getFunctionType() const {
if (Chunk != nullptr)
return dyn_cast<InputFunction>(Chunk)->Signature;
assert(FunctionType != nullptr);
return *FunctionType;
}
void Symbol::setFunctionType(const WasmSignature *Type) {
assert(FunctionType == nullptr);
assert(!Chunk);
FunctionType = Type;
}
uint32_t Symbol::getVirtualAddress() const {
assert(isGlobal());
DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
return Chunk ? dyn_cast<InputSegment>(Chunk)->translateVA(VirtualAddress)
: VirtualAddress;
}
DefinedFunction *WasmSym::CallCtors;
DefinedGlobal *WasmSym::DsoHandle;
DefinedGlobal *WasmSym::DataEnd;
DefinedGlobal *WasmSym::HeapBase;
DefinedGlobal *WasmSym::StackPointer;
bool Symbol::hasOutputIndex() const {
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
@ -61,12 +40,6 @@ uint32_t Symbol::getOutputIndex() const {
return OutputIndex.getValue();
}
void Symbol::setVirtualAddress(uint32_t Value) {
DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
assert(isGlobal());
VirtualAddress = Value;
}
void Symbol::setOutputIndex(uint32_t Index) {
DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n");
assert(!dyn_cast_or_null<InputFunction>(Chunk));
@ -74,41 +47,6 @@ void Symbol::setOutputIndex(uint32_t Index) {
OutputIndex = Index;
}
uint32_t Symbol::getTableIndex() const {
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
return F->getTableIndex();
return TableIndex.getValue();
}
bool Symbol::hasTableIndex() const {
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
return F->hasTableIndex();
return TableIndex.hasValue();
}
void Symbol::setTableIndex(uint32_t Index) {
// For imports, we set the table index here on the Symbol; for defined
// functions we set the index on the InputFunction so that we don't export
// the same thing twice (keeps the table size down).
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk)) {
F->setTableIndex(Index);
return;
}
DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
assert(!TableIndex.hasValue());
TableIndex = Index;
}
void Symbol::update(Kind K, InputFile *F, uint32_t Flags_, InputChunk *Chunk_,
uint32_t Address) {
SymbolKind = K;
File = F;
Flags = Flags_;
Chunk = Chunk_;
if (Address != UINT32_MAX)
setVirtualAddress(Address);
}
bool Symbol::isWeak() const {
return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
}
@ -130,6 +68,58 @@ void Symbol::setHidden(bool IsHidden) {
Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT;
}
const WasmSignature &FunctionSymbol::getFunctionType() const {
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
return F->Signature;
assert(FunctionType != nullptr);
return *FunctionType;
}
void FunctionSymbol::setFunctionType(const WasmSignature *Type) {
assert(FunctionType == nullptr);
assert(!Chunk);
FunctionType = Type;
}
uint32_t FunctionSymbol::getTableIndex() const {
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
return F->getTableIndex();
return TableIndex.getValue();
}
bool FunctionSymbol::hasTableIndex() const {
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk))
return F->hasTableIndex();
return TableIndex.hasValue();
}
void FunctionSymbol::setTableIndex(uint32_t Index) {
// For imports, we set the table index here on the Symbol; for defined
// functions we set the index on the InputFunction so that we don't export
// the same thing twice (keeps the table size down).
if (auto *F = dyn_cast_or_null<InputFunction>(Chunk)) {
F->setTableIndex(Index);
return;
}
DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n");
assert(!TableIndex.hasValue());
TableIndex = Index;
}
uint32_t DefinedGlobal::getVirtualAddress() const {
assert(isGlobal());
DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
return Chunk ? dyn_cast<InputSegment>(Chunk)->translateVA(VirtualAddress)
: VirtualAddress;
}
void DefinedGlobal::setVirtualAddress(uint32_t Value) {
DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
assert(isGlobal());
VirtualAddress = Value;
}
std::string lld::toString(const wasm::Symbol &Sym) {
if (Config->Demangle)
if (Optional<std::string> S = demangleItanium(Sym.getName()))

View File

@ -23,6 +23,7 @@ namespace wasm {
class InputFile;
class InputChunk;
// The base class for real symbol classes.
class Symbol {
public:
enum Kind {
@ -37,9 +38,7 @@ public:
InvalidKind,
};
Symbol(StringRef Name, uint32_t Flags) : Flags(Flags), Name(Name) {}
Kind getKind() const { return SymbolKind; }
Kind kind() const { return static_cast<Kind>(SymbolKind); }
bool isLazy() const { return SymbolKind == LazyKind; }
bool isDefined() const { return SymbolKind <= LastDefinedKind; }
@ -63,9 +62,6 @@ public:
InputFile *getFile() const { return File; }
InputChunk *getChunk() const { return Chunk; }
bool hasFunctionType() const { return FunctionType != nullptr; }
const WasmSignature &getFunctionType() const;
void setFunctionType(const WasmSignature *Type);
void setHidden(bool IsHidden);
uint32_t getOutputIndex() const;
@ -77,6 +73,28 @@ public:
// space of the output object.
void setOutputIndex(uint32_t Index);
protected:
Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, InputChunk *C)
: Name(Name), SymbolKind(K), Flags(Flags), File(F), Chunk(C) {}
StringRef Name;
Kind SymbolKind;
uint32_t Flags;
InputFile *File;
InputChunk *Chunk;
llvm::Optional<uint32_t> OutputIndex;
};
class FunctionSymbol : public Symbol {
public:
static bool classof(const Symbol *S) {
return S->kind() == DefinedFunctionKind ||
S->kind() == UndefinedFunctionKind;
}
bool hasFunctionType() const { return FunctionType != nullptr; }
const WasmSignature &getFunctionType() const;
uint32_t getTableIndex() const;
// Returns true if a table index has been set for this symbol
@ -85,30 +103,99 @@ public:
// Set the table index of the symbol
void setTableIndex(uint32_t Index);
// Returns the virtual address of a defined global.
// Only works for globals, not functions.
protected:
void setFunctionType(const WasmSignature *Type);
FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
InputChunk *C)
: Symbol(Name, K, Flags, F, C) {}
llvm::Optional<uint32_t> TableIndex;
// Explict function type, needed for undefined or synthetic functions only.
const WasmSignature *FunctionType = nullptr;
};
class DefinedFunction : public FunctionSymbol {
public:
DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F = nullptr,
InputChunk *C = nullptr)
: FunctionSymbol(Name, DefinedFunctionKind, Flags, F, C) {}
DefinedFunction(StringRef Name, uint32_t Flags, const WasmSignature *Type)
: FunctionSymbol(Name, DefinedFunctionKind, Flags, nullptr, nullptr) {
setFunctionType(Type);
}
static bool classof(const Symbol *S) {
return S->kind() == DefinedFunctionKind;
}
};
class UndefinedFunction : public FunctionSymbol {
public:
UndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File = nullptr,
const WasmSignature *Type = nullptr)
: FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, nullptr) {
setFunctionType(Type);
}
static bool classof(const Symbol *S) {
return S->kind() == UndefinedFunctionKind;
}
};
class GlobalSymbol : public Symbol {
public:
static bool classof(const Symbol *S) {
return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind;
}
protected:
GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F,
InputChunk *C)
: Symbol(Name, K, Flags, F, C) {}
};
class DefinedGlobal : public GlobalSymbol {
public:
DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *F = nullptr,
InputChunk *C = nullptr, uint32_t Address = 0)
: GlobalSymbol(Name, DefinedGlobalKind, Flags, F, C),
VirtualAddress(Address) {}
static bool classof(const Symbol *S) {
return S->kind() == DefinedGlobalKind;
}
uint32_t getVirtualAddress() const;
void setVirtualAddress(uint32_t VA);
void update(Kind K, InputFile *F = nullptr, uint32_t Flags = 0,
InputChunk *chunk = nullptr, uint32_t Address = UINT32_MAX);
protected:
uint32_t VirtualAddress;
};
class UndefinedGlobal : public GlobalSymbol {
public:
UndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File = nullptr)
: GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, nullptr) {}
static bool classof(const Symbol *S) {
return S->kind() == UndefinedGlobalKind;
}
};
class LazySymbol : public Symbol {
public:
LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym)
: Symbol(Name, LazyKind, 0, File, nullptr), ArchiveSymbol(Sym) {}
static bool classof(const Symbol *S) { return S->kind() == LazyKind; }
void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }
const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }
protected:
uint32_t Flags;
uint32_t VirtualAddress = 0;
StringRef Name;
Archive::Symbol ArchiveSymbol = {nullptr, 0, 0};
Kind SymbolKind = InvalidKind;
InputFile *File = nullptr;
InputChunk *Chunk = nullptr;
llvm::Optional<uint32_t> OutputIndex;
llvm::Optional<uint32_t> TableIndex;
const WasmSignature *FunctionType = nullptr;
Archive::Symbol ArchiveSymbol;
};
// linker-generated symbols
@ -116,27 +203,50 @@ struct WasmSym {
// __stack_pointer
// Global that holds the address of the top of the explicit value stack in
// linear memory.
static Symbol *StackPointer;
static DefinedGlobal *StackPointer;
// __data_end
// Symbol marking the end of the data and bss.
static Symbol *DataEnd;
static DefinedGlobal *DataEnd;
// __heap_base
// Symbol marking the end of the data, bss and explicit stack. Any linear
// memory following this address is not used by the linked code and can
// therefore be used as a backing store for brk()/malloc() implementations.
static Symbol *HeapBase;
static DefinedGlobal *HeapBase;
// __wasm_call_ctors
// Function that directly calls all ctors in priority order.
static Symbol *CallCtors;
static DefinedFunction *CallCtors;
// __dso_handle
// Global used in calls to __cxa_atexit to determine current DLL
static Symbol *DsoHandle;
static DefinedGlobal *DsoHandle;
};
// A buffer class that is large enough to hold any Symbol-derived
// object. We allocate memory using this class and instantiate a symbol
// using the placement new.
union SymbolUnion {
alignas(DefinedFunction) char A[sizeof(DefinedFunction)];
alignas(DefinedGlobal) char B[sizeof(DefinedGlobal)];
alignas(LazySymbol) char C[sizeof(LazySymbol)];
alignas(UndefinedFunction) char D[sizeof(UndefinedFunction)];
alignas(UndefinedGlobal) char E[sizeof(UndefinedFunction)];
};
template <typename T, typename... ArgT>
T *replaceSymbol(Symbol *S, ArgT &&... Arg) {
static_assert(std::is_trivially_destructible<T>(),
"Symbol types must be trivially destructible");
static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small");
static_assert(alignof(T) <= alignof(SymbolUnion),
"SymbolUnion not aligned enough");
assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr &&
"Not a Symbol");
return new (S) T(std::forward<ArgT>(Arg)...);
}
} // namespace wasm
// Returns a symbol name for an error message.

View File

@ -119,12 +119,12 @@ private:
std::vector<const WasmSignature *> Types;
DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices;
std::vector<const Symbol *> ImportedFunctions;
std::vector<const Symbol *> ImportedGlobals;
std::vector<const FunctionSymbol *> ImportedFunctions;
std::vector<const GlobalSymbol *> ImportedGlobals;
std::vector<WasmExportEntry> ExportedSymbols;
std::vector<const Symbol *> DefinedGlobals;
std::vector<const DefinedGlobal *> DefinedGlobals;
std::vector<InputFunction *> DefinedFunctions;
std::vector<const Symbol *> IndirectFunctions;
std::vector<const FunctionSymbol *> IndirectFunctions;
std::vector<WasmInitFunc> InitFunctions;
// Elements that are used to construct the final output
@ -164,7 +164,7 @@ void Writer::createImportSection() {
writeUleb128(OS, NumImports, "import count");
for (const Symbol *Sym : ImportedFunctions) {
for (const FunctionSymbol *Sym : ImportedFunctions) {
WasmImport Import;
Import.Module = "env";
Import.Field = Sym->getName();
@ -234,7 +234,7 @@ void Writer::createGlobalSection() {
raw_ostream &OS = Section->getStream();
writeUleb128(OS, DefinedGlobals.size(), "global count");
for (const Symbol *Sym : DefinedGlobals) {
for (const DefinedGlobal *Sym : DefinedGlobals) {
WasmGlobal Global;
Global.Type.Type = WASM_TYPE_I32;
Global.Type.Mutable = Sym == WasmSym::StackPointer;
@ -316,7 +316,7 @@ void Writer::createElemSection() {
writeUleb128(OS, IndirectFunctions.size(), "elem count");
uint32_t TableIndex = kInitialTableOffset;
for (const Symbol *Sym : IndirectFunctions) {
for (const FunctionSymbol *Sym : IndirectFunctions) {
assert(Sym->getTableIndex() == TableIndex);
writeUleb128(OS, Sym->getOutputIndex(), "function index");
++TableIndex;
@ -619,12 +619,12 @@ void Writer::calculateImports() {
if (!Sym->isUndefined() || (Sym->isWeak() && !Config->Relocatable))
continue;
if (Sym->isFunction()) {
Sym->setOutputIndex(ImportedFunctions.size());
ImportedFunctions.push_back(Sym);
} else {
Sym->setOutputIndex(ImportedGlobals.size());
ImportedGlobals.push_back(Sym);
if (auto *F = dyn_cast<FunctionSymbol>(Sym)) {
F->setOutputIndex(ImportedFunctions.size());
ImportedFunctions.push_back(F);
} else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) {
G->setOutputIndex(ImportedGlobals.size());
ImportedGlobals.push_back(G);
}
}
}
@ -712,7 +712,7 @@ void Writer::calculateTypes() {
File->TypeMap[I] = registerType(Types[I]);
}
for (const Symbol *Sym : ImportedFunctions)
for (const FunctionSymbol *Sym : ImportedFunctions)
registerType(Sym->getFunctionType());
for (const InputFunction *F : DefinedFunctions)
@ -723,7 +723,7 @@ void Writer::assignIndexes() {
uint32_t GlobalIndex = ImportedGlobals.size() + DefinedGlobals.size();
uint32_t FunctionIndex = ImportedFunctions.size() + DefinedFunctions.size();
auto AddDefinedGlobal = [&](Symbol* Sym) {
auto AddDefinedGlobal = [&](DefinedGlobal *Sym) {
if (Sym) {
DefinedGlobals.emplace_back(Sym);
Sym->setOutputIndex(GlobalIndex++);
@ -743,12 +743,10 @@ void Writer::assignIndexes() {
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())
if (File != Sym->getFile())
continue;
if (Sym->isFunction())
continue;
AddDefinedGlobal(Sym);
if (auto *G = dyn_cast<DefinedGlobal>(Sym))
AddDefinedGlobal(G);
}
}
}
@ -772,7 +770,7 @@ void Writer::assignIndexes() {
for (const WasmRelocation& Reloc : Chunk->getRelocations()) {
if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 ||
Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) {
Symbol *Sym = File->getFunctionSymbol(Reloc.Index);
FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index);
if (Sym->hasTableIndex() || !Sym->hasOutputIndex())
continue;
Sym->setTableIndex(TableIndex++);