Index: lld/wasm/Driver.cpp =================================================================== --- lld/wasm/Driver.cpp +++ lld/wasm/Driver.cpp @@ -222,11 +222,6 @@ return Arg->getValue(); } -static Symbol* addUndefinedFunction(StringRef Name, const WasmSignature *Type) { - return Symtab->addUndefined(Name, Symbol::UndefinedFunctionKind, 0, nullptr, - Type); -} - void LinkerDriver::link(ArrayRef ArgsArr) { WasmOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); @@ -307,11 +302,12 @@ WasmSym::DataEnd = Symtab->addSyntheticGlobal("__data_end"); if (!Config->Entry.empty()) - EntrySym = addUndefinedFunction(Config->Entry, &NullSignature); + EntrySym = Symtab->addUndefinedFunction(Config->Entry, 0, nullptr, + &NullSignature); // Handle the `--undefined ` options. for (auto* Arg : Args.filtered(OPT_undefined)) - addUndefinedFunction(Arg->getValue(), nullptr); + Symtab->addUndefinedFunction(Arg->getValue(), 0, nullptr, nullptr); } createFiles(Args); Index: lld/wasm/InputFiles.cpp =================================================================== --- lld/wasm/InputFiles.cpp +++ lld/wasm/InputFiles.cpp @@ -259,8 +259,8 @@ LLVM_FALLTHROUGH; // Exclude function, and add the symbol as undefined } case WasmSymbol::SymbolType::FUNCTION_IMPORT: - S = createUndefined(WasmSym, Symbol::Kind::UndefinedFunctionKind, - getFunctionSig(WasmSym)); + S = Symtab->addUndefinedFunction(WasmSym.Name, WasmSym.Flags, this, + getFunctionSig(WasmSym)); break; case WasmSymbol::SymbolType::GLOBAL_EXPORT: { InputSegment *Segment = getSegment(WasmSym); @@ -272,7 +272,7 @@ LLVM_FALLTHROUGH; // Exclude global, and add the symbol as undefined } case WasmSymbol::SymbolType::GLOBAL_IMPORT: - S = createUndefined(WasmSym, Symbol::Kind::UndefinedGlobalKind); + S = Symtab->addUndefinedGlobal(WasmSym.Name, WasmSym.Flags, this); break; } @@ -297,11 +297,6 @@ DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n"); } -Symbol *ObjFile::createUndefined(const WasmSymbol &Sym, Symbol::Kind Kind, - const WasmSignature *Signature) { - return Symtab->addUndefined(Sym.Name, Kind, Sym.Flags, this, Signature); -} - Symbol *ObjFile::createDefinedFunction(const WasmSymbol &Sym, InputFunction *Function) { if (Sym.isBindingLocal()) Index: lld/wasm/SymbolTable.h =================================================================== --- lld/wasm/SymbolTable.h +++ lld/wasm/SymbolTable.h @@ -53,9 +53,9 @@ Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *F, InputSegment *Segment = 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 *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *F, + const WasmSignature *Type); + Symbol *addUndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *F); void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); bool addComdat(StringRef Name, ObjFile *); Index: lld/wasm/SymbolTable.cpp =================================================================== --- lld/wasm/SymbolTable.cpp +++ lld/wasm/SymbolTable.cpp @@ -73,51 +73,41 @@ // 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) { +static void checkFunctionTypes(const Symbol &Existing, const InputFile &F, + const WasmSignature *NewSig) { if (Existing.isLazy()) return; // First check the symbol types match (i.e. either both are function // symbols or both are data symbols). - if (isa(Existing) != NewIsFunction) { - error("symbol type mismatch: " + Existing.getName() + "\n>>> defined as " + - (isa(Existing) ? "Function" : "Global") + " in " + - toString(Existing.getFile()) + "\n>>> defined as " + - (NewIsFunction ? "Function" : "Global") + " in " + F.getName()); + if (!isa(Existing)) { + error("symbol type mismatch: " + toString(Existing) + + "\n>>> defined as Global in " + toString(Existing.getFile()) + + "\n>>> defined as Function in " + toString(&F)); return; } // For function symbols, optionally check the function signature matches too. - auto *ExistingFunc = dyn_cast(&Existing); - if (!ExistingFunc || !Config->CheckSignatures) + if (!Config->CheckSignatures) return; - - const WasmSignature *OldSig = ExistingFunc->getFunctionType(); + auto *Func = cast(&Existing); + const WasmSignature *OldSig = Func->getFunctionType(); // 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; - - DEBUG(dbgs() << "checkSymbolTypes: " << ExistingFunc->getName() << "\n"); - assert(NewSig); - - if (*NewSig == *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()); + if (OldSig && *NewSig != *OldSig) { + error("function signature mismatch: " + Func->getName() + + "\n>>> defined as " + toString(*OldSig) + " in " + + toString(Func->getFile()) + "\n>>> defined as " + toString(*NewSig) + + " in " + toString(&F)); + } } -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(Chunk)) - Sig = &F->Signature; - return checkSymbolTypes(Existing, F, IsFunction, Sig); +static void checkGlobalTypes(const Symbol &Existing, const InputFile &F) { + if (!Existing.isLazy() && isa(Existing)) + error("symbol type mismatch: " + toString(Existing) + + "\n>>> defined as Function in" + toString(Existing.getFile()) + + "\n>>> defined as Global in " + toString(&F)); } DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, @@ -141,8 +131,7 @@ } static bool shouldReplace(const Symbol &Existing, InputFile *NewFile, - uint32_t NewFlags, InputChunk *NewChunk, - bool NewIsFunction) { + uint32_t NewFlags, InputChunk *NewChunk) { // If existing symbol is lazy, replace it without checking types since // lazy symbols don't have any type information. if (Existing.isLazy()) { @@ -155,7 +144,10 @@ // 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); + if (auto *C = dyn_cast_or_null(NewChunk)) + checkFunctionTypes(Existing, *NewFile, &C->Signature); + else + checkGlobalTypes(Existing, *NewFile); // If existing symbol is undefined, replace it. if (!Existing.isDefined()) { @@ -188,7 +180,7 @@ Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted || shouldReplace(*S, F, Flags, Function, true)) + if (WasInserted || shouldReplace(*S, F, Flags, Function)) replaceSymbol(S, Name, Flags, F, Function); return S; } @@ -200,26 +192,48 @@ Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted || shouldReplace(*S, F, Flags, Segment, false)) + if (WasInserted || shouldReplace(*S, F, Flags, Segment)) replaceSymbol(S, Name, Flags, F, Segment, Address); return S; } -Symbol *SymbolTable::addUndefined(StringRef Name, Symbol::Kind Kind, - uint32_t Flags, InputFile *F, - const WasmSignature *Type) { - DEBUG(dbgs() << "addUndefined: " << Name << "\n"); +Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags, + InputFile *F, + const WasmSignature *Type) { + DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n"); + + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + + if (WasInserted) { + replaceSymbol(S, Name, Flags, F, Type); + return S; + } + + if (auto *Lazy = dyn_cast(S)) { + DEBUG(dbgs() << "resolved by existing lazy\n"); + cast(Lazy->getFile())->addMember(&Lazy->getArchiveSymbol()); + return S; + } + + if (S->isDefined()) { + DEBUG(dbgs() << "resolved by existing\n"); + checkFunctionTypes(*S, *F, Type); + } + return S; +} + +Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags, + InputFile *F) { + DEBUG(dbgs() << "addUndefinedGlobal: " << 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); + replaceSymbol(S, Name, Flags, F); return S; } @@ -231,7 +245,7 @@ if (S->isDefined()) { DEBUG(dbgs() << "resolved by existing\n"); - checkSymbolTypes(*S, *F, IsFunction, Type); + checkGlobalTypes(*S, *F); } return S; }