Index: lld/wasm/SymbolTable.h =================================================================== --- lld/wasm/SymbolTable.h +++ lld/wasm/SymbolTable.h @@ -42,7 +42,6 @@ std::vector ObjectFiles; - void reportDuplicate(Symbol *Existing, InputFile *NewFile); void reportRemainingUndefines(); ArrayRef getSymbols() const { return SymVector; } Index: lld/wasm/SymbolTable.cpp =================================================================== --- lld/wasm/SymbolTable.cpp +++ lld/wasm/SymbolTable.cpp @@ -71,12 +71,6 @@ return {Sym, true}; } -void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { - error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + - toString(Existing->getFile()) + "\n>>> defined in " + - toString(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, @@ -154,48 +148,63 @@ 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) { - Replace = true; - } else if (S->isLazy()) { - // 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"); - Replace = true; - } else if (!S->isDefined()) { - // Existing symbol is undefined: replace it, while check types. - DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n"); - 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"); - CheckTypes = true; - } else if (S->isWeak()) { - // the existing symbol is, so we replace it - DEBUG(dbgs() << "replacing existing weak symbol\n"); - Replace = true; - CheckTypes = true; - } else { - // neither symbol is week. They conflict. - reportDuplicate(S, F); - } - if (Replace) { - if (CheckTypes) - checkSymbolTypes(*S, *F, IsFunction, Chunk); + auto Replace = [&] { if (IsFunction) replaceSymbol(S, Name, Flags, F, cast(Chunk)); else replaceSymbol(S, Name, Flags, F, cast(Chunk), Address); + }; + + // If there's no existing symbol, just insert a new one. + if (WasInserted) { + Replace(); + return S; + } + + // If existing symbol is lazy, replace it without checking types since + // lazy symbols don't have any type information. + if (S->isLazy()) { + DEBUG(dbgs() << "replacing existing lazy symbol: " << Name << "\n"); + Replace(); + return S; } + + // 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 defined. 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(*S, *F, IsFunction, Chunk); + + // If existing symbol is undefined, replace it while checking types. + if (!S->isDefined()) { + DEBUG(dbgs() << "resolving existing undefined symbol: " << Name << "\n"); + Replace(); + return S; + } + + // Now we have two defined symbols. If the new one is weak, we can ignore it. + if ((Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { + DEBUG(dbgs() << "existing symbol takes precedence\n"); + return S; + } + + // If the existing symbol is weak, we should replace it. + if (S->isWeak()) { + DEBUG(dbgs() << "replacing existing weak symbol\n"); + Replace(); + return S; + } + + // Neither symbol is week. They conflict. + error("duplicate symbol: " + toString(*S) + "\n>>> defined in " + + toString(S->getFile()) + "\n>>> defined in " + toString(F)); return S; } @@ -203,20 +212,28 @@ uint32_t Flags, InputFile *F, const WasmSignature *Type) { DEBUG(dbgs() << "addUndefined: " << Name << "\n"); + Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); + bool IsFunction = Kind == Symbol::UndefinedFunctionKind; + if (WasInserted) { if (IsFunction) replaceSymbol(S, Name, Flags, F, Type); else replaceSymbol(S, Name, Flags, F); - } else if (auto *LazySym = dyn_cast(S)) { + return S; + } + + if (auto *Lazy = dyn_cast(S)) { DEBUG(dbgs() << "resolved by existing lazy\n"); - auto *AF = cast(LazySym->getFile()); - AF->addMember(&LazySym->getArchiveSymbol()); - } else if (S->isDefined()) { + cast(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol()); + return S; + } + + if (S->isDefined()) { DEBUG(dbgs() << "resolved by existing\n"); checkSymbolTypes(*S, *F, IsFunction, Type); } @@ -225,15 +242,18 @@ void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); - StringRef Name = Sym->getName(); + Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(Name); + std::tie(S, WasInserted) = insert(Sym->getName()); + if (WasInserted) { - replaceSymbol(S, Name, F, *Sym); - } else if (S->isUndefined()) { - // There is an existing undefined symbol. The can load from the - // archive. + replaceSymbol(S, Sym->getName(), F, *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); }