Index: lld/trunk/test/wasm/call-indirect.ll =================================================================== --- lld/trunk/test/wasm/call-indirect.ll +++ lld/trunk/test/wasm/call-indirect.ll @@ -105,9 +105,6 @@ ; CHECK-NEXT: - Name: __data_end ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 4 ; CHECK-NEXT: - Name: bar ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 @@ -117,6 +114,9 @@ ; CHECK-NEXT: - Name: foo ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 ; CHECK-NEXT: - Name: indirect_func ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 3 Index: lld/trunk/test/wasm/cxx-mangling.ll =================================================================== --- lld/trunk/test/wasm/cxx-mangling.ll +++ lld/trunk/test/wasm/cxx-mangling.ll @@ -32,12 +32,12 @@ ; CHECK-NEXT: - Name: __data_end ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: _Z3fooi ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Index: 0 Index: lld/trunk/test/wasm/demangle.ll =================================================================== --- lld/trunk/test/wasm/demangle.ll +++ lld/trunk/test/wasm/demangle.ll @@ -1,17 +1,19 @@ ; RUN: llc -filetype=obj %s -o %t.o -; RUN: not wasm-ld --undefined _Z3fooi \ -; RUN: -o %t.wasm %t.o 2>&1 | FileCheck %s +; RUN: not wasm-ld -o %t.wasm %t.o 2>&1 | FileCheck %s -; CHECK: error: undefined symbol: foo(int) +; CHECK: error: {{.*}}.o: undefined symbol: foo(int) -; RUN: not wasm-ld --no-demangle --undefined _Z3fooi \ -; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s +; RUN: not wasm-ld --no-demangle \ +; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s -; CHECK-NODEMANGLE: error: undefined symbol: _Z3fooi +; CHECK-NODEMANGLE: error: {{.*}}.o: undefined symbol: _Z3fooi target triple = "wasm32-unknown-unknown" +declare void @_Z3fooi(i32); + define hidden void @_start() local_unnamed_addr { entry: + call void @_Z3fooi(i32 1) ret void } Index: lld/trunk/test/wasm/export-all.ll =================================================================== --- lld/trunk/test/wasm/export-all.ll +++ lld/trunk/test/wasm/export-all.ll @@ -42,7 +42,7 @@ ; CHECK-NOT: - Name: internal_func ; EXPORT: - Type: EXPORT -; EXPORT: - Name: _start ; EXPORT: - Name: bar ; EXPORT: - Name: foo +; EXPORT: - Name: _start ; EXPORT-NOT: - Name: internal_func Index: lld/trunk/test/wasm/export.ll =================================================================== --- lld/trunk/test/wasm/export.ll +++ lld/trunk/test/wasm/export.ll @@ -28,10 +28,10 @@ ; CHECK-NEXT: - Name: __data_end ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: hidden_function ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Type: CODE Index: lld/trunk/test/wasm/load-undefined.test =================================================================== --- lld/trunk/test/wasm/load-undefined.test +++ lld/trunk/test/wasm/load-undefined.test @@ -18,9 +18,9 @@ ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: ret32 -; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Name: ret64 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: ret32 ; CHECK-NEXT: ... ; NO-LOAD: Name: name @@ -33,9 +33,6 @@ ; NO-LOAD-NEXT: Name: ret64 ; NO-LOAD-NEXT: ... -; Verify that referencing a symbol that doesn't exist won't work -; RUN: not wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s -; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist - -; RUN: not wasm-ld %t.start.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s -; CHECK-UNDEFINED2: symbol forced with --undefined not found: symboldoesnotexist +; Verify that referencing a symbol that is not found doesn't result in a link +; failure. This matches the behaviour of the ELF linker. +; RUN: wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist Index: lld/trunk/test/wasm/lto/export.ll =================================================================== --- lld/trunk/test/wasm/lto/export.ll +++ lld/trunk/test/wasm/lto/export.ll @@ -29,10 +29,10 @@ ; CHECK-NEXT: - Name: __data_end ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: hidden_function ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Type: CODE Index: lld/trunk/test/wasm/undefined-entry.test =================================================================== --- lld/trunk/test/wasm/undefined-entry.test +++ lld/trunk/test/wasm/undefined-entry.test @@ -1,11 +1,9 @@ RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o RUN: not wasm-ld -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s +RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s RUN: not wasm-ld -entry=foo -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM -RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-ALLOW -CHECK: error: undefined symbol: _start -CHECK-CUSTOM: error: undefined symbol: foo -CHECK-ALLOW: error: entry symbol not defined (pass --no-entry to supress): -_start +CHECK: error: entry symbol not defined (pass --no-entry to supress): _start +CHECK-CUSTOM: error: entry symbol not defined (pass --no-entry to supress): foo RUN: wasm-ld --no-entry -o %t.wasm %t.ret32.o Index: lld/trunk/test/wasm/undefined.ll =================================================================== --- lld/trunk/test/wasm/undefined.ll +++ lld/trunk/test/wasm/undefined.ll @@ -1,10 +1,10 @@ ; RUN: llc -filetype=obj %s -o %t.o ; RUN: wasm-ld --allow-undefined -o %t.wasm %t.o -; Fails due to undefined 'foo' and also 'baz' +; Fails due to undefined 'foo' ; RUN: not wasm-ld --undefined=baz -o %t.wasm %t.o 2>&1 | FileCheck %s ; CHECK: error: {{.*}}.o: undefined symbol: foo -; CHECK: error: undefined symbol: baz +; CHECK-NOT: undefined symbol: baz ; Succeeds if we pass a file containing 'foo' as --allow-undefined-file. ; RUN: echo 'foo' > %t.txt Index: lld/trunk/test/wasm/visibility-hidden.ll =================================================================== --- lld/trunk/test/wasm/visibility-hidden.ll +++ lld/trunk/test/wasm/visibility-hidden.ll @@ -43,12 +43,12 @@ ; CHECK-NEXT: - Name: __data_end ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: objectDefault ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: archiveDefault ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 5 Index: lld/trunk/test/wasm/weak-alias-overide.ll =================================================================== --- lld/trunk/test/wasm/weak-alias-overide.ll +++ lld/trunk/test/wasm/weak-alias-overide.ll @@ -74,12 +74,12 @@ ; CHECK-NEXT: - Name: __data_end ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: alias_fn ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: direct_fn ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 3 Index: lld/trunk/test/wasm/weak-undefined.ll =================================================================== --- lld/trunk/test/wasm/weak-undefined.ll +++ lld/trunk/test/wasm/weak-undefined.ll @@ -81,15 +81,15 @@ ; CHECK-NEXT: - Name: __data_end ; CHECK-NEXT: Kind: GLOBAL ; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: get_address_of_foo ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: get_address_of_global_var ; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: ; CHECK-NEXT: - Index: 0 Index: lld/trunk/wasm/Driver.cpp =================================================================== --- lld/trunk/wasm/Driver.cpp +++ lld/trunk/wasm/Driver.cpp @@ -329,14 +329,19 @@ } // Force Sym to be entered in the output. Used for -u or equivalent. -static Symbol *addUndefined(StringRef Name) { - Symbol *S = Symtab->addUndefinedFunction(Name, 0, nullptr, nullptr); +static Symbol *handleUndefined(StringRef Name) { + Symbol *Sym = Symtab->find(Name); + if (!Sym) + return nullptr; // Since symbol S may not be used inside the program, LTO may // eliminate it. Mark the symbol as "used" to prevent it. - S->IsUsedInRegularObj = true; + Sym->IsUsedInRegularObj = true; - return S; + if (auto *LazySym = dyn_cast(Sym)) + LazySym->fetch(); + + return Sym; } void LinkerDriver::link(ArrayRef ArgsArr) { @@ -462,15 +467,6 @@ WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol( "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN); WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0); - - // For now, since we don't actually use the start function as the - // wasm start symbol, we don't need to care about it signature. - if (!Config->Entry.empty()) - EntrySym = addUndefined(Config->Entry); - - // Handle the `--undefined ` options. - for (auto *Arg : Args.filtered(OPT_undefined)) - addUndefined(Arg->getValue()); } createFiles(Args); @@ -484,10 +480,29 @@ if (errorCount()) return; - // Add synthetic dummies for weak undefined functions. - if (!Config->Relocatable) + // Handle the `--undefined ` options. + for (auto *Arg : Args.filtered(OPT_undefined)) + handleUndefined(Arg->getValue()); + + if (!Config->Relocatable) { + // Add synthetic dummies for weak undefined functions. handleWeakUndefines(); + if (!Config->Entry.empty()) { + EntrySym = handleUndefined(Config->Entry); + if (!EntrySym) + error("entry symbol not defined (pass --no-entry to supress): " + + Config->Entry); + } + + // Make sure we have resolved all symbols. + if (!Config->AllowUndefined) + Symtab->reportRemainingUndefines(); + } + + if (errorCount()) + return; + // Handle --export. for (auto *Arg : Args.filtered(OPT_export)) { StringRef Name = Arg->getValue(); @@ -504,27 +519,6 @@ if (errorCount()) return; - // Make sure we have resolved all symbols. - if (!Config->Relocatable && !Config->AllowUndefined) { - Symtab->reportRemainingUndefines(); - } else { - // Even when using --allow-undefined we still want to report the absence of - // our initial set of undefined symbols (i.e. the entry point and symbols - // specified via --undefined). - // Part of the reason for this is that these function don't have signatures - // so which means they cannot be written as wasm function imports. - for (auto *Arg : Args.filtered(OPT_undefined)) { - Symbol *Sym = Symtab->find(Arg->getValue()); - if (!Sym->isDefined()) - error("symbol forced with --undefined not found: " + Sym->getName()); - } - if (EntrySym && !EntrySym->isDefined()) - error("entry symbol not defined (pass --no-entry to supress): " + - EntrySym->getName()); - } - if (errorCount()) - return; - if (EntrySym) EntrySym->setHidden(false); Index: lld/trunk/wasm/SymbolTable.cpp =================================================================== --- lld/trunk/wasm/SymbolTable.cpp +++ lld/trunk/wasm/SymbolTable.cpp @@ -60,7 +60,6 @@ } void SymbolTable::reportRemainingUndefines() { - SetVector Undefs; for (Symbol *Sym : SymVector) { if (!Sym->isUndefined() || Sym->isWeak()) continue; @@ -68,20 +67,8 @@ continue; if (!Sym->IsUsedInRegularObj) continue; - Undefs.insert(Sym); + error(toString(Sym->getFile()) + ": undefined symbol: " + toString(*Sym)); } - - if (Undefs.empty()) - return; - - for (ObjFile *File : ObjectFiles) - for (Symbol *Sym : File->getSymbols()) - if (Undefs.count(Sym)) - error(toString(File) + ": undefined symbol: " + toString(*Sym)); - - for (Symbol *Sym : Undefs) - if (!Sym->getFile()) - error("undefined symbol: " + toString(*Sym)); } Symbol *SymbolTable::find(StringRef Name) {