diff options
Diffstat (limited to 'lld/wasm/SymbolTable.cpp')
| -rw-r--r-- | lld/wasm/SymbolTable.cpp | 236 |
1 files changed, 125 insertions, 111 deletions
diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index d8d7be9f045..b9f4e6e5e3a 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -71,63 +71,56 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { return {Sym, true}; } -// 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, - WasmSymbolType NewType, - const WasmSignature *NewFunctionSig, - const WasmGlobalType *NewGlobalType) { - if (Existing.isLazy()) - return; - - WasmSymbolType ExistingType = Existing.getWasmType(); +static void reportTypeError(const Symbol *Existing, const InputFile *File, + StringRef Type) { + error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " + + toString(Existing->getWasmType()) + " in " + + toString(Existing->getFile()) + "\n>>> defined as " + Type + " in " + + toString(File)); +} - // First check the symbol types match (i.e. either both are function - // symbols or both are data symbols). - if (NewType != ExistingType) { - error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " + - toString(ExistingType) + " in " + toString(Existing.getFile()) + - "\n>>> defined as " + toString(NewType) + " in " + F.getName()); +static void checkFunctionType(const Symbol *Existing, const InputFile *File, + const WasmSignature *NewSig) { + if (!isa<FunctionSymbol>(Existing)) { + reportTypeError(Existing, File, "Function"); return; } - // For function/global symbols, optionally check the type matches too. - if (NewType == WASM_SYMBOL_TYPE_DATA || !Config->CheckSignatures) + if (!Config->CheckSignatures) return; - DEBUG(dbgs() << "checkSymbolTypes: " << Existing.getName() << "\n"); - - 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()); - }; - - 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; - - assert(NewFunctionSig); - if (*NewFunctionSig == *OldSig) - return; - - ReportError(toString(*OldSig), toString(*NewFunctionSig)); - } else { - auto &Sym = cast<GlobalSymbol>(Existing); + const WasmSignature *OldSig = + cast<FunctionSymbol>(Existing)->getFunctionType(); + if (OldSig && *NewSig != *OldSig) { + error("Function type mismatch: " + Existing->getName() + + "\n>>> defined as " + toString(*OldSig) + " in " + + toString(Existing->getFile()) + "\n>>> defined as " + + toString(*NewSig) + " in " + toString(File)); + } +} - assert(NewGlobalType != nullptr); - const WasmGlobalType *OldType = Sym.getGlobalType(); - if (*NewGlobalType == *OldType) - return; +// 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 checkGlobalType(const Symbol *Existing, const InputFile *File, + const WasmGlobalType *NewType) { + if (!isa<GlobalSymbol>(Existing)) { + reportTypeError(Existing, File, "Global"); + return; + } - ReportError(toString(*OldType), toString(*NewGlobalType)); + const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType(); + if (*NewType != *OldType) { + error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " + + toString(*OldType) + " in " + toString(Existing->getFile()) + + "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); } } +static void checkDataType(const Symbol *Existing, const InputFile *File) { + if (!isa<DataSymbol>(Existing)) + reportTypeError(Existing, File, "Data"); +} + DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, const WasmSignature *Type, uint32_t Flags) { @@ -159,29 +152,12 @@ DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, return replaceSymbol<DefinedGlobal>(S, Name, Flags, nullptr, Global); } -static bool shouldReplace(const Symbol &Existing, InputFile *NewFile, - 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()) { - DEBUG(dbgs() << "replacing existing lazy symbol: " << Existing.getName() - << "\n"); - return true; - } - - // Now we have two wasm symbols, and all wasm symbols that have the same - // 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, NewType, NewFuncType, NewGlobalType); - +static bool shouldReplace(const Symbol *Existing, InputFile *NewFile, + uint32_t NewFlags) { // If existing symbol is undefined, replace it. - if (!Existing.isDefined()) { + if (!Existing->isDefined()) { DEBUG(dbgs() << "resolving existing undefined symbol: " - << Existing.getName() << "\n"); + << Existing->getName() << "\n"); return true; } @@ -192,93 +168,131 @@ static bool shouldReplace(const Symbol &Existing, InputFile *NewFile, } // If the existing symbol is weak, we should replace it. - if (Existing.isWeak()) { + if (Existing->isWeak()) { DEBUG(dbgs() << "replacing existing weak symbol\n"); return true; } // Neither symbol is week. They conflict. - error("duplicate symbol: " + toString(Existing) + "\n>>> defined in " + - toString(Existing.getFile()) + "\n>>> defined in " + toString(NewFile)); + error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + + toString(Existing->getFile()) + "\n>>> defined in " + + toString(NewFile)); return true; } Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, - InputFile *F, InputFunction *Function) { + InputFile *File, + InputFunction *Function) { DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted || shouldReplace(*S, F, WASM_SYMBOL_TYPE_FUNCTION, Flags, - &Function->Signature)) - replaceSymbol<DefinedFunction>(S, Name, Flags, F, Function); + + if (WasInserted || S->isLazy()) { + replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); + return S; + } + + checkFunctionType(S, File, &Function->Signature); + + if (shouldReplace(S, File, Flags)) + replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); return S; } Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, - InputFile *F, InputSegment *Segment, + InputFile *File, 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, WASM_SYMBOL_TYPE_DATA, Flags)) - replaceSymbol<DefinedData>(S, Name, Flags, F, Segment, Address, Size); + + if (WasInserted || S->isLazy()) { + replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); + return S; + } + + checkDataType(S, File); + + if (shouldReplace(S, File, Flags)) + replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); return S; } Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, - InputFile *F, InputGlobal *Global) { + InputFile *File, 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); + + if (WasInserted || S->isLazy()) { + replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); + return S; + } + + checkGlobalType(S, File, &Global->getType()); + + if (shouldReplace(S, File, Flags)) + replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); return S; } -Symbol *SymbolTable::addUndefined(StringRef Name, WasmSymbolType Type, - uint32_t Flags, InputFile *F, - const WasmSignature *FunctionType, - const WasmGlobalType *GlobalType) { - DEBUG(dbgs() << "addUndefined type=" << Type << ": " << Name << "\n"); +Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags, + InputFile *File, + const WasmSignature *Sig) { + DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted) { - 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; - } + if (WasInserted) + replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig); + else if (auto *Lazy = dyn_cast<LazySymbol>(S)) + cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol()); + else if (S->isDefined()) + checkFunctionType(S, File, Sig); + return S; +} + +Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags, + InputFile *File) { + DEBUG(dbgs() << "addUndefinedData: " << Name << "\n"); - if (auto *Lazy = dyn_cast<LazySymbol>(S)) { - DEBUG(dbgs() << "resolved by existing lazy\n"); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + + if (WasInserted) + replaceSymbol<UndefinedData>(S, Name, Flags, File); + else if (auto *Lazy = dyn_cast<LazySymbol>(S)) cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol()); - return S; - } + else if (S->isDefined()) + checkDataType(S, File); + return S; +} - if (S->isDefined()) { - DEBUG(dbgs() << "resolved by existing\n"); - checkSymbolTypes(*S, *F, Type, FunctionType, GlobalType); - } +Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags, + InputFile *File, + const WasmGlobalType *Type) { + DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n"); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + + if (WasInserted) + replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type); + else if (auto *Lazy = dyn_cast<LazySymbol>(S)) + cast<ArchiveFile>(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol()); + else if (S->isDefined()) + checkGlobalType(S, File, Type); return S; } -void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { +void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) { DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); StringRef Name = Sym->getName(); @@ -287,14 +301,14 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - replaceSymbol<LazySymbol>(S, Name, F, *Sym); + replaceSymbol<LazySymbol>(S, Name, File, *Sym); return; } // If there is an existing undefined symbol, load a new one from the archive. if (S->isUndefined()) { DEBUG(dbgs() << "replacing existing undefined\n"); - F->addMember(Sym); + File->addMember(Sym); } } |

