[WebAssembly] Refactor symbol and symbol table to remove WasmSymbol references

This WasmSymbol types comes directly from the input objects
but we want to be able to represent synthetic symbols too.

This is more in line with how the ELF linker represents symbols.

This change also removes the logic from Symbol::getVirtualAddress
for finding the global address and instead has the InputFile
provide this.

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

llvm-svn: 322145
This commit is contained in:
Sam Clegg 2018-01-10 00:52:20 +00:00
parent 04576cc060
commit 20db381b90
6 changed files with 91 additions and 93 deletions

View File

@ -134,6 +134,15 @@ static void copyRelocationsRange(std::vector<WasmRelocation> &To,
To.push_back(R);
}
// Get the value stored in the wasm global represented by this symbol.
// This represents the virtual address of the symbol in the input file.
uint32_t ObjFile::getGlobalValue(const WasmSymbol &Sym) const {
const WasmGlobal &Global =
getWasmObj()->globals()[Sym.ElementIndex - NumGlobalImports];
assert(Global.Type == llvm::wasm::WASM_TYPE_I32);
return Global.InitExpr.Value.Int32;
}
// 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).
@ -190,16 +199,19 @@ void ObjFile::initializeSymbols() {
Symbol *S;
switch (WasmSym.Type) {
case WasmSymbol::SymbolType::FUNCTION_IMPORT:
S = createUndefined(WasmSym, getFunctionSig(WasmSym));
S = createUndefined(WasmSym, Symbol::Kind::UndefinedFunctionKind,
getFunctionSig(WasmSym));
break;
case WasmSymbol::SymbolType::GLOBAL_IMPORT:
S = createUndefined(WasmSym);
S = createUndefined(WasmSym, Symbol::Kind::UndefinedGlobalKind);
break;
case WasmSymbol::SymbolType::GLOBAL_EXPORT:
S = createDefined(WasmSym, getSegment(WasmSym), nullptr);
S = createDefined(WasmSym, Symbol::Kind::DefinedGlobalKind,
getSegment(WasmSym), nullptr, getGlobalValue(WasmSym));
break;
case WasmSymbol::SymbolType::FUNCTION_EXPORT:
S = createDefined(WasmSym, nullptr, getFunction(WasmSym));
S = createDefined(WasmSym, Symbol::Kind::DefinedFunctionKind, nullptr,
getFunction(WasmSym));
break;
case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME:
// These are for debugging only, no need to create linker symbols for them
@ -249,28 +261,22 @@ void ObjFile::initializeSymbols() {
DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n");
}
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym,
Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
const WasmSignature *Signature) {
return Symtab->addUndefined(this, &Sym, Signature);
return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature);
}
Symbol *ObjFile::createDefined(const WasmSymbol &Sym,
Symbol *ObjFile::createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,
const InputSegment *Segment,
InputFunction *Function) {
InputFunction *Function, uint32_t Address) {
Symbol *S;
if (Sym.isLocal()) {
S = make<Symbol>(Sym.Name, true);
Symbol::Kind Kind;
if (Sym.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT)
Kind = Symbol::Kind::DefinedFunctionKind;
else if (Sym.Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
Kind = Symbol::Kind::DefinedGlobalKind;
else
llvm_unreachable("invalid local symbol type");
S->update(Kind, this, &Sym, Segment, Function);
S->update(Kind, this, Sym.Flags, Segment, Function, Address);
return S;
}
return Symtab->addDefined(this, &Sym, Segment, Function);
return Symtab->addDefined(Sym.Name, Kind, Sym.Flags, this, Segment, Function,
Address);
}
void ArchiveFile::parse() {

View File

@ -17,6 +17,7 @@
#include "llvm/Object/Wasm.h"
#include "llvm/Support/MemoryBuffer.h"
#include "Symbols.h"
#include "WriterUtils.h"
#include <vector>
@ -31,7 +32,6 @@ using llvm::wasm::WasmSignature;
namespace lld {
namespace wasm {
class Symbol;
class InputFunction;
class InputSegment;
@ -97,8 +97,6 @@ public:
uint32_t relocateTableIndex(uint32_t Original) const;
uint32_t getRelocatedAddress(uint32_t Index) const;
size_t getNumGlobalImports() const { return NumGlobalImports; }
const WasmSection *CodeSection = nullptr;
std::vector<uint32_t> TypeMap;
@ -109,14 +107,16 @@ public:
ArrayRef<Symbol *> getTableSymbols() { return TableSymbols; }
private:
Symbol *createDefined(const WasmSymbol &Sym,
Symbol *createDefined(const WasmSymbol &Sym, Symbol::Kind Kind,
const InputSegment *Segment = nullptr,
InputFunction *Function = nullptr);
Symbol *createUndefined(const WasmSymbol &Sym,
InputFunction *Function = nullptr,
uint32_t Address = UINT32_MAX);
Symbol *createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind,
const WasmSignature *Signature = nullptr);
void initializeSymbols();
InputSegment *getSegment(const WasmSymbol &WasmSym) const;
const WasmSignature *getFunctionSig(const WasmSymbol &Sym) const;
uint32_t getGlobalValue(const WasmSymbol &Sym) const;
InputFunction *getFunction(const WasmSymbol &Sym) const;
// List of all symbols referenced or defined by this file.

View File

@ -20,6 +20,7 @@
#define DEBUG_TYPE "lld"
using namespace llvm;
using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
@ -80,18 +81,17 @@ 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,
const WasmSymbol &New,
const WasmSignature *NewSig) {
Symbol::Kind Kind, const WasmSignature *NewSig) {
if (Existing.isLazy())
return;
bool NewIsFunction = New.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT ||
New.Type == WasmSymbol::SymbolType::FUNCTION_IMPORT;
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) {
error("symbol type mismatch: " + New.Name + "\n>>> defined as " +
error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " +
(Existing.isFunction() ? "Function" : "Global") + " in " +
toString(Existing.getFile()) + "\n>>> defined as " +
(NewIsFunction ? "Function" : "Global") + " in " + F.getName());
@ -106,16 +106,17 @@ static void checkSymbolTypes(const Symbol &Existing, const InputFile &F,
if (!Existing.hasFunctionType())
return;
DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n");
DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n");
assert(NewSig);
const WasmSignature &OldSig = Existing.getFunctionType();
if (*NewSig == OldSig)
return;
error("function signature mismatch: " + New.Name + "\n>>> defined as " +
toString(OldSig) + " in " + toString(Existing.getFile()) +
"\n>>> defined as " + toString(*NewSig) + " in " + F.getName());
error("function signature mismatch: " + Existing.getName() +
"\n>>> defined as " + toString(OldSig) + " in " +
toString(Existing.getFile()) + "\n>>> defined as " + toString(*NewSig) +
" in " + F.getName());
}
Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
@ -130,40 +131,37 @@ Symbol *SymbolTable::addDefinedGlobal(StringRef Name) {
return S;
}
Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym,
Symbol *SymbolTable::addDefined(StringRef Name, Symbol::Kind Kind,
uint32_t Flags, InputFile *F,
const InputSegment *Segment,
InputFunction *Function) {
DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n");
InputFunction *Function, uint32_t Address) {
DEBUG(dbgs() << "addDefined: " << Name << " addr:" << Address << "\n");
Symbol *S;
bool WasInserted;
Symbol::Kind Kind = Symbol::DefinedFunctionKind;
if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT)
Kind = Symbol::DefinedGlobalKind;
std::tie(S, WasInserted) = insert(Sym->Name);
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
S->update(Kind, F, Sym, Segment, Function);
S->update(Kind, F, Flags, Segment, Function, Address);
} 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, Function);
DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n");
S->update(Kind, F, Flags, Segment, Function, Address);
} 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, Function ? &Function->Signature : nullptr);
S->update(Kind, F, Sym, Segment, Function);
} else if (Sym->isWeak()) {
DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n");
checkSymbolTypes(*S, *F, Kind, Function ? &Function->Signature : nullptr);
S->update(Kind, F, Flags, Segment, Function, Address);
} 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
DEBUG(dbgs() << "replacing existing weak symbol\n");
checkSymbolTypes(*S, *F, *Sym, Function ? &Function->Signature : nullptr);
S->update(Kind, F, Sym, Segment, Function);
checkSymbolTypes(*S, *F, Kind, Function ? &Function->Signature : nullptr);
S->update(Kind, F, Flags, Segment, Function, Address);
} else {
// neither symbol is week. They conflict.
reportDuplicate(S, F);
@ -185,17 +183,15 @@ Symbol *SymbolTable::addUndefinedFunction(StringRef Name,
return S;
}
Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym,
Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind,
uint32_t Flags, InputFile *F,
const WasmSignature *Type) {
DEBUG(dbgs() << "addUndefined: " << Sym->Name << "\n");
DEBUG(dbgs() << "addUndefined: " << Name << "\n");
Symbol *S;
bool WasInserted;
Symbol::Kind Kind = Symbol::UndefinedFunctionKind;
if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT)
Kind = Symbol::UndefinedGlobalKind;
std::tie(S, WasInserted) = insert(Sym->Name);
std::tie(S, WasInserted) = insert(Name);
if (WasInserted) {
S->update(Kind, F, Sym);
S->update(Kind, F, Flags);
if (Type)
S->setFunctionType(Type);
} else if (S->isLazy()) {
@ -204,7 +200,7 @@ Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym,
AF->addMember(&S->getArchiveSymbol());
} else if (S->isDefined()) {
DEBUG(dbgs() << "resolved by existing\n");
checkSymbolTypes(*S, *F, *Sym, Type);
checkSymbolTypes(*S, *F, Kind, Type);
}
return S;
}

View File

@ -17,7 +17,6 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/raw_ostream.h"
using llvm::object::WasmSymbol;
using llvm::wasm::WasmSignature;
namespace lld {
@ -49,11 +48,11 @@ public:
ArrayRef<Symbol *> getSymbols() const { return SymVector; }
Symbol *find(StringRef Name);
Symbol *addDefined(InputFile *F, const WasmSymbol *Sym,
const InputSegment *Segment = nullptr,
InputFunction *Function = nullptr);
Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym,
const WasmSignature *Signature = nullptr);
Symbol *addDefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
InputFile *F, const InputSegment *Segment = nullptr,
InputFunction *Function = nullptr, uint32_t Address = 0);
Symbol *addUndefined(StringRef Name, Symbol::Kind Kind, uint32_t Flags,
InputFile *F, 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

@ -19,6 +19,7 @@
#define DEBUG_TYPE "lld"
using namespace llvm;
using namespace llvm::wasm;
using namespace lld;
using namespace lld::wasm;
@ -39,19 +40,7 @@ void Symbol::setFunctionType(const WasmSignature *Type) {
uint32_t Symbol::getVirtualAddress() const {
assert(isGlobal());
DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n");
if (isUndefined())
return 0;
if (VirtualAddress.hasValue())
return VirtualAddress.getValue();
ObjFile *Obj = cast<ObjFile>(File);
assert(Sym != nullptr);
const WasmGlobal &Global =
Obj->getWasmObj()
->globals()[Sym->ElementIndex - Obj->getNumGlobalImports()];
assert(Global.Type == llvm::wasm::WASM_TYPE_I32);
assert(Segment);
return Segment->translateVA(Global.InitExpr.Value.Int32);
return Segment ? Segment->translateVA(VirtualAddress) : VirtualAddress;
}
bool Symbol::hasOutputIndex() const {
@ -68,7 +57,7 @@ uint32_t Symbol::getOutputIndex() const {
void Symbol::setVirtualAddress(uint32_t Value) {
DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n");
assert(!VirtualAddress.hasValue());
assert(isGlobal());
VirtualAddress = Value;
}
@ -85,18 +74,29 @@ void Symbol::setTableIndex(uint32_t Index) {
TableIndex = Index;
}
void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym,
const InputSegment *Seg, const InputFunction *Func) {
void Symbol::update(Kind K, InputFile *F, uint32_t Flags_,
const InputSegment *Seg, const InputFunction *Func,
uint32_t Address) {
SymbolKind = K;
File = F;
Sym = WasmSym;
Flags = Flags_;
Segment = Seg;
Function = Func;
if (Address != UINT32_MAX)
setVirtualAddress(Address);
}
bool Symbol::isWeak() const { return Sym && Sym->isWeak(); }
bool Symbol::isWeak() const {
return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK;
}
bool Symbol::isHidden() const { return Sym && Sym->isHidden(); }
bool Symbol::isLocal() const {
return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL;
}
bool Symbol::isHidden() const {
return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN;
}
std::string lld::toString(const wasm::Symbol &Sym) {
if (Config->Demangle)

View File

@ -15,9 +15,6 @@
#include "llvm/Object/Wasm.h"
using llvm::object::Archive;
using llvm::object::WasmSymbol;
using llvm::wasm::WasmExport;
using llvm::wasm::WasmImport;
using llvm::wasm::WasmSignature;
namespace lld {
@ -41,8 +38,8 @@ public:
InvalidKind,
};
Symbol(StringRef Name, bool IsLocal)
: WrittenToSymtab(0), WrittenToNameSec(0), IsLocal(IsLocal), Name(Name) {}
Symbol(StringRef Name, uint32_t Flags)
: WrittenToSymtab(0), WrittenToNameSec(0), Flags(Flags), Name(Name) {}
Kind getKind() const { return SymbolKind; }
@ -57,7 +54,7 @@ public:
SymbolKind == UndefinedFunctionKind;
}
bool isGlobal() const { return !isFunction(); }
bool isLocal() const { return IsLocal; }
bool isLocal() const;
bool isWeak() const;
bool isHidden() const;
@ -94,9 +91,10 @@ public:
void setVirtualAddress(uint32_t VA);
void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr,
void update(Kind K, InputFile *F = nullptr, uint32_t Flags = 0,
const InputSegment *Segment = nullptr,
const InputFunction *Function = nullptr);
const InputFunction *Function = nullptr,
uint32_t Address = UINT32_MAX);
void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; }
const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; }
@ -107,18 +105,17 @@ public:
unsigned WrittenToNameSec : 1;
protected:
unsigned IsLocal : 1;
uint32_t Flags;
uint32_t VirtualAddress = 0;
StringRef Name;
Archive::Symbol ArchiveSymbol = {nullptr, 0, 0};
Kind SymbolKind = InvalidKind;
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 = nullptr;
};