diff --git a/lld/test/wasm/Inputs/weak-undefined.s b/lld/test/wasm/Inputs/weak-undefined.s new file mode 100644 --- /dev/null +++ b/lld/test/wasm/Inputs/weak-undefined.s @@ -0,0 +1,2 @@ +.functype foo () -> () +.weak foo diff --git a/lld/test/wasm/weak-and-strong-undef.s b/lld/test/wasm/weak-and-strong-undef.s new file mode 100644 --- /dev/null +++ b/lld/test/wasm/weak-and-strong-undef.s @@ -0,0 +1,18 @@ +# Test that when a symbol (foo) is both weakly and strongly referenced +# the strong undefined symbol always generates an error, whichever object +# file is seen first. + +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown %S/Inputs/weak-undefined.s -o %t2.o +# RUN: not wasm-ld %t1.o %t2.o -o /dev/null 2>&1 | FileCheck %s +# RUN: not wasm-ld %t2.o %t1.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: undefined symbol: foo + +_start: + .globl _start + .functype _start () -> () + call foo + end_function + +.functype foo () -> () diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -406,7 +406,7 @@ template static void setImportAttributes(T *existing, Optional importName, Optional importModule, - InputFile *file) { + uint32_t flags, InputFile *file) { if (importName) { if (!existing->importName) existing->importName = importName; @@ -426,6 +426,12 @@ toString(existing->getFile()) + "\n>>> defined as " + *importModule + " in " + toString(file)); } + + // Update symbol binding, if the existing symbol is weak + uint32_t binding = flags & WASM_SYMBOL_BINDING_MASK; + if (existing->isWeak() && binding != WASM_SYMBOL_BINDING_WEAK) { + existing->flags = (existing->flags & ~WASM_SYMBOL_BINDING_MASK) | binding; + } } Symbol *SymbolTable::addUndefinedFunction(StringRef name, @@ -436,7 +442,8 @@ bool isCalledDirectly) { LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << name << " [" << (sig ? toString(*sig) : "none") - << "] IsCalledDirectly:" << isCalledDirectly << "\n"); + << "] IsCalledDirectly:" << isCalledDirectly << " flags=0x" + << utohexstr(flags) << "\n"); assert(flags & WASM_SYMBOL_UNDEFINED); Symbol *s; @@ -460,20 +467,21 @@ reportTypeError(s, file, WASM_SYMBOL_TYPE_FUNCTION); return s; } - auto *existingUndefined = dyn_cast(existingFunction); if (!existingFunction->signature && sig) existingFunction->signature = sig; + auto *existingUndefined = dyn_cast(existingFunction); if (isCalledDirectly && !signatureMatches(existingFunction, sig)) { - // If the existing undefined functions is not called direcltly then let + // If the existing undefined functions is not called directly then let // this one take precedence. Otherwise the existing function is either - // direclty called or defined, in which case we need a function variant. + // directly called or defined, in which case we need a function variant. if (existingUndefined && !existingUndefined->isCalledDirectly) replaceSym(); else if (getFunctionVariant(s, sig, file, &s)) replaceSym(); } if (existingUndefined) - setImportAttributes(existingUndefined, importName, importModule, file); + setImportAttributes(existingUndefined, importName, importModule, flags, + file); } return s; @@ -634,7 +642,7 @@ auto *func = make(sig, sym->getName(), debugName); func->setBody(unreachableFn); syntheticFunctions.emplace_back(func); - replaceSymbol(sym, sym->getName(), sym->getFlags(), nullptr, + replaceSymbol(sym, sym->getName(), sym->flags, nullptr, func); return func; } diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -86,8 +86,6 @@ // Returns the file from which this symbol was created. InputFile *getFile() const { return file; } - uint32_t getFlags() const { return flags; } - InputChunk *getChunk() const; // Indicates that the section or import for this symbol will be included in @@ -124,14 +122,12 @@ protected: Symbol(StringRef name, Kind k, uint32_t flags, InputFile *f) - : name(name), file(f), flags(flags), symbolKind(k), - referenced(!config->gcSections), requiresGOT(false), - isUsedInRegularObj(false), forceExport(false), canInline(false), - traced(false) {} + : name(name), file(f), symbolKind(k), referenced(!config->gcSections), + requiresGOT(false), isUsedInRegularObj(false), forceExport(false), + canInline(false), traced(false), flags(flags) {} StringRef name; InputFile *file; - uint32_t flags; uint32_t outputSymbolIndex = INVALID_INDEX; uint32_t gotIndex = INVALID_INDEX; Kind symbolKind; @@ -160,6 +156,8 @@ // True if this symbol is specified by --trace-symbol option. bool traced : 1; + + uint32_t flags; }; class FunctionSymbol : public Symbol { diff --git a/lld/wasm/SyntheticSections.cpp b/lld/wasm/SyntheticSections.cpp --- a/lld/wasm/SyntheticSections.cpp +++ b/lld/wasm/SyntheticSections.cpp @@ -391,7 +391,7 @@ for (const Symbol *sym : symtabEntries) { assert(sym->isDefined() || sym->isUndefined()); WasmSymbolType kind = sym->getWasmType(); - uint32_t flags = sym->getFlags(); + uint32_t flags = sym->flags; writeU8(sub.os, kind, "sym kind"); writeUleb128(sub.os, flags, "sym flags");