diff options
| author | Sam Clegg <sbc@chromium.org> | 2018-02-23 05:08:53 +0000 |
|---|---|---|
| committer | Sam Clegg <sbc@chromium.org> | 2018-02-23 05:08:53 +0000 |
| commit | 93102974386d5fe5ea217ec3d4aeda55395db4ff (patch) | |
| tree | 06f3eb15d4047c4949f48cc9f1cec2fdbda7e2e1 /lld/wasm/SymbolTable.cpp | |
| parent | 6c899ba6dee1a6cd1e1a49900bb5f3b6353a5487 (diff) | |
| download | bcm5719-llvm-93102974386d5fe5ea217ec3d4aeda55395db4ff.tar.gz bcm5719-llvm-93102974386d5fe5ea217ec3d4aeda55395db4ff.zip | |
[WebAssembly] Add explicit symbol table
This change modified lld to in response the llvm change which
moved to a more explicit symbol table in the object format.
Based on patches by Nicholas Wilson:
1. https://reviews.llvm.org/D41955
2. https://reviews.llvm.org/D42585
The primary difference that we see in the test output is that
for relocatable (-r) output we now have symbol table which
replaces exports/imports and globals.
See: https://github.com/WebAssembly/tool-conventions/issues/38
Differential Revision: https://reviews.llvm.org/D43264
llvm-svn: 325861
Diffstat (limited to 'lld/wasm/SymbolTable.cpp')
| -rw-r--r-- | lld/wasm/SymbolTable.cpp | 130 |
1 files changed, 86 insertions, 44 deletions
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 094b5669a00..d8d7be9f045 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -10,6 +10,7 @@ #include "SymbolTable.h" #include "Config.h" #include "InputChunks.h" +#include "InputGlobal.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -73,50 +74,58 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { // 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, - bool NewIsFunction, const WasmSignature *NewSig) { + WasmSymbolType NewType, + const WasmSignature *NewFunctionSig, + const WasmGlobalType *NewGlobalType) { if (Existing.isLazy()) return; + WasmSymbolType ExistingType = Existing.getWasmType(); + // First check the symbol types match (i.e. either both are function // symbols or both are data symbols). - if (isa<FunctionSymbol>(Existing) != NewIsFunction) { + if (NewType != ExistingType) { error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " + - (isa<FunctionSymbol>(Existing) ? "Function" : "Data") + " in " + - toString(Existing.getFile()) + "\n>>> defined as " + - (NewIsFunction ? "Function" : "Data") + " in " + F.getName()); + toString(ExistingType) + " in " + toString(Existing.getFile()) + + "\n>>> defined as " + toString(NewType) + " in " + F.getName()); return; } - // For function symbols, optionally check the function signature matches too. - auto *ExistingFunc = dyn_cast<FunctionSymbol>(&Existing); - if (!ExistingFunc || !Config->CheckSignatures) + // For function/global symbols, optionally check the type matches too. + if (NewType == WASM_SYMBOL_TYPE_DATA || !Config->CheckSignatures) return; - const WasmSignature *OldSig = ExistingFunc->getFunctionType(); + DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n"); - // 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 (OldSig == nullptr) - return; + auto ReportError = [&](const Twine &Old, const Twine &New) { + error(toString(NewType) + " type mismatch: " + Existing.getName() + + "\n>>> defined as " + Old + " in " + toString(Existing.getFile()) + + "\n>>> defined as " + New + " in " + F.getName()); + }; - DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n"); - assert(NewSig); + if (NewType == WASM_SYMBOL_TYPE_FUNCTION) { + // 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). + auto &Sym = cast<FunctionSymbol>(Existing); + const WasmSignature *OldSig = Sym.getFunctionType(); + if (!OldSig) + return; - if (*NewSig == *OldSig) - return; + assert(NewFunctionSig); + if (*NewFunctionSig == *OldSig) + return; - error("function signature mismatch: " + ExistingFunc->getName() + - "\n>>> defined as " + toString(*OldSig) + " in " + - toString(ExistingFunc->getFile()) + "\n>>> defined as " + - toString(*NewSig) + " in " + F.getName()); -} + ReportError(toString(*OldSig), toString(*NewFunctionSig)); + } else { + auto &Sym = cast<GlobalSymbol>(Existing); -static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, - 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, IsFunction, Sig); + assert(NewGlobalType != nullptr); + const WasmGlobalType *OldType = Sym.getGlobalType(); + if (*NewGlobalType == *OldType) + return; + + ReportError(toString(*OldType), toString(*NewGlobalType)); + } } DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, @@ -140,9 +149,21 @@ DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, return replaceSymbol<DefinedData>(S, Name, Flags); } +DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, + InputGlobal *Global) { + DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global << "\n"); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + assert(WasInserted); + return replaceSymbol<DefinedGlobal>(S, Name, Flags, nullptr, Global); +} + static bool shouldReplace(const Symbol &Existing, InputFile *NewFile, - uint32_t NewFlags, InputChunk *NewChunk, - bool NewIsFunction) { + WasmSymbolType NewType, uint32_t NewFlags, + const WasmSignature *NewFuncType = nullptr, + const WasmGlobalType *NewGlobalType = nullptr) { + // If existing symbol is lazy, replace it without checking types since // lazy symbols don't have any type information. if (Existing.isLazy()) { @@ -155,7 +176,7 @@ static bool shouldReplace(const Symbol &Existing, InputFile *NewFile, // symbol name must have the same type, even if they are undefined. This // is different from ELF because symbol types are not that significant // in ELF, and undefined symbols in ELF don't have type in the first place. - checkSymbolTypes(Existing, *NewFile, NewIsFunction, NewChunk); + checkSymbolTypes(Existing, *NewFile, NewType, NewFuncType, NewGlobalType); // If existing symbol is undefined, replace it. if (!Existing.isDefined()) { @@ -188,38 +209,58 @@ Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted || shouldReplace(*S, F, Flags, Function, true)) + if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_FUNCTION, Flags, + &Function->Signature)) replaceSymbol<DefinedFunction>(S, Name, Flags, F, Function); return S; } Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, - InputFile *F, InputSegment *Segment, - uint32_t Address) { + InputFile *F, InputSegment *Segment, + uint32_t Address, uint32_t Size) { DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted || shouldReplace(*S, F, Flags, Segment, false)) - replaceSymbol<DefinedData>(S, Name, Flags, F, Segment, Address); + if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_DATA, Flags)) + replaceSymbol<DefinedData>(S, Name, Flags, F, Segment, Address, Size); return S; } -Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind, +Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, + InputFile *F, InputGlobal *Global) { + DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n"); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_GLOBAL, Flags, + nullptr, &Global->getType())) + replaceSymbol<DefinedGlobal>(S, Name, Flags, F, Global); + return S; +} + +Symbol *SymbolTable::addUndefined(StringRef Name, WasmSymbolType Type, uint32_t Flags, InputFile *F, - const WasmSignature *Type) { - DEBUG(dbgs() << "addUndefined: " << Name << "\n"); + const WasmSignature *FunctionType, + const WasmGlobalType *GlobalType) { + DEBUG(dbgs() << "addUndefined type=" << Type << ": " << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - bool IsFunction = Kind == Symbol::UndefinedFunctionKind; if (WasInserted) { - if (IsFunction) - replaceSymbol<UndefinedFunction>(S, Name, Flags, F, Type); - else + switch (Type) { + case WASM_SYMBOL_TYPE_FUNCTION: + replaceSymbol<UndefinedFunction>(S, Name, Flags, F, FunctionType); + break; + case WASM_SYMBOL_TYPE_GLOBAL: + replaceSymbol<UndefinedGlobal>(S, Name, Flags, F, GlobalType); + break; + case WASM_SYMBOL_TYPE_DATA: replaceSymbol<UndefinedData>(S, Name, Flags, F); + break; + } return S; } @@ -231,8 +272,9 @@ Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind, if (S->isDefined()) { DEBUG(dbgs() << "resolved by existing\n"); - checkSymbolTypes(*S, *F, IsFunction, Type); + checkSymbolTypes(*S, *F, Type, FunctionType, GlobalType); } + return S; } |

