Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -214,11 +214,6 @@ return Arg->getValue(); } -static Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type) { - return Symtab->addUndefined(Name, WASM_SYMBOL_TYPE_FUNCTION, 0, nullptr, - Type); -} - void LinkerDriver::link(ArrayRef ArgsArr) { WasmOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); @@ -311,11 +306,12 @@ WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__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: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -268,9 +268,18 @@ } Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { - return Symtab->addUndefined( - Sym.Info.Name, static_cast(Sym.Info.Kind), Sym.Info.Flags, - this, Sym.FunctionType, Sym.GlobalType); + StringRef Name = Sym.Info.Name; + uint32_t Flags = Sym.Info.Flags; + + switch (Sym.Info.Kind) { + case WASM_SYMBOL_TYPE_FUNCTION: + return Symtab->addUndefinedFunction(Name, Flags, this, Sym.FunctionType); + case WASM_SYMBOL_TYPE_DATA: + return Symtab->addUndefinedData(Name, Flags, this); + case WASM_SYMBOL_TYPE_GLOBAL: + return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType); + } + llvm_unreachable("unkown symbol kind"); } Symbol *ObjFile::createDefinedFunction(const WasmSymbol &Sym, Index: wasm/SymbolTable.h =================================================================== --- wasm/SymbolTable.h +++ wasm/SymbolTable.h @@ -48,17 +48,20 @@ Symbol *find(StringRef Name); ObjFile *findComdat(StringRef Name) const; - Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *F, + Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, InputFunction *Function = nullptr); - Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *F, + Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File, InputSegment *Segment = nullptr, uint32_t Address = 0, uint32_t Size = 0); - Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *F, + Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, InputGlobal *G); - Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type); - Symbol *addUndefined(StringRef Name, WasmSymbolType Type, uint32_t Flags, - InputFile *F, const WasmSignature *Signature = nullptr, - const WasmGlobalType *GlobalType = nullptr); + + Symbol *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, + const WasmSignature *Signature); + Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File); + Symbol *addUndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, + const WasmGlobalType *Type); + void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); bool addComdat(StringRef Name, ObjFile *); Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -71,63 +71,56 @@ 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(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"); + const WasmSignature *OldSig = + cast(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)); + } +} - 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(Existing); - const WasmSignature *OldSig = Sym.getFunctionType(); - if (!OldSig) - return; - - assert(NewFunctionSig); - if (*NewFunctionSig == *OldSig) - return; - - ReportError(toString(*OldSig), toString(*NewFunctionSig)); - } else { - auto &Sym = cast(Existing); - - 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(Existing)) { + reportTypeError(Existing, File, "Global"); + return; + } - ReportError(toString(*OldType), toString(*NewGlobalType)); + const WasmGlobalType *OldType = cast(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(Existing)) + reportTypeError(Existing, File, "Data"); +} + DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, const WasmSignature *Type, uint32_t Flags) { @@ -159,29 +152,12 @@ return replaceSymbol(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 @@ } // 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(S, Name, Flags, F, Function); + + if (WasInserted || S->isLazy()) { + replaceSymbol(S, Name, Flags, File, Function); + return S; + } + + checkFunctionType(S, File, &Function->Signature); + + if (shouldReplace(S, File, Flags)) + replaceSymbol(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(S, Name, Flags, F, Segment, Address, Size); + + if (WasInserted || S->isLazy()) { + replaceSymbol(S, Name, Flags, File, Segment, Address, Size); + return S; + } + + checkDataType(S, File); + + if (shouldReplace(S, File, Flags)) + replaceSymbol(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(S, Name, Flags, F, Global); + + if (WasInserted || S->isLazy()) { + replaceSymbol(S, Name, Flags, File, Global); + return S; + } + + checkGlobalType(S, File, &Global->getType()); + + if (shouldReplace(S, File, Flags)) + replaceSymbol(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(S, Name, Flags, F, FunctionType); - break; - case WASM_SYMBOL_TYPE_GLOBAL: - replaceSymbol(S, Name, Flags, F, GlobalType); - break; - case WASM_SYMBOL_TYPE_DATA: - replaceSymbol(S, Name, Flags, F); - break; - } - return S; - } + if (WasInserted) + replaceSymbol(S, Name, Flags, File, Sig); + else if (auto *Lazy = dyn_cast(S)) + cast(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(S)) { - DEBUG(dbgs() << "resolved by existing lazy\n"); + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + + if (WasInserted) + replaceSymbol(S, Name, Flags, File); + else if (auto *Lazy = dyn_cast(S)) cast(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(S, Name, Flags, File, Type); + else if (auto *Lazy = dyn_cast(S)) + cast(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 @@ std::tie(S, WasInserted) = insert(Name); if (WasInserted) { - replaceSymbol(S, Name, F, *Sym); + replaceSymbol(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); } }