Index: lld/trunk/test/wasm/load-undefined.ll =================================================================== --- lld/trunk/test/wasm/load-undefined.ll +++ lld/trunk/test/wasm/load-undefined.ll @@ -0,0 +1,38 @@ +; Verify that the -u / --undefined option is able to pull in symbols from +; an archive, and doesn't error when uses to pull in a symbol already loaded. +; +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret64.ll -o %t.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret32.ll -o %t2.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t3.o +; RUN: llvm-ar rcs %t2.a %t2.o +; RUN: lld -flavor wasm %t3.o %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64 +; RUN: obj2yaml %t.wasm | FileCheck %s + +define i32 @_start() local_unnamed_addr { +entry: + ret i32 1 +} + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: ret32 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: ret64 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Type: + + +; Verify that referencing a symbol that doesn't exist won't work +; RUN: not lld -flavor wasm %t3.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s +; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist + +; RUN: not lld -flavor wasm %t3.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s +; CHECK-UNDEFINED2: function forced with --undefined not found: symboldoesnotexist Index: lld/trunk/wasm/Driver.cpp =================================================================== --- lld/trunk/wasm/Driver.cpp +++ lld/trunk/wasm/Driver.cpp @@ -273,6 +273,8 @@ if (Config->Relocatable && !Config->Entry.empty()) error("entry point specified for relocatable output file"); + if (Config->Relocatable && Args.hasArg(OPT_undefined)) + error("undefined symbols specified for relocatable output file"); if (!Config->Relocatable) { if (Config->Entry.empty()) @@ -280,6 +282,10 @@ static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; addSyntheticUndefinedFunction(Config->Entry, &Signature); + // Handle the `--undefined ` options. + for (StringRef S : args::getStrings(Args, OPT_undefined)) + addSyntheticUndefinedFunction(S, nullptr); + Config->StackPointerSymbol = addSyntheticGlobal("__stack_pointer", 0); } @@ -297,6 +303,18 @@ Symtab->reportRemainingUndefines(); if (errorCount()) return; + } else { + // When we allow undefined symbols we cannot include those defined in + // -u/--undefined since these undefined symbols have only names and no + // function signature, which means they cannot be written to the final + // output. + for (StringRef S : args::getStrings(Args, OPT_undefined)) { + Symbol *Sym = Symtab->find(S); + if (!Sym->isDefined()) + error("function forced with --undefined not found: " + Sym->getName()); + } + if (errorCount()) + return; } if (!Config->Entry.empty()) { Index: lld/trunk/wasm/Options.td =================================================================== --- lld/trunk/wasm/Options.td +++ lld/trunk/wasm/Options.td @@ -6,6 +6,11 @@ class J: Joined<["--", "-"], name>; class S: Separate<["--", "-"], name>; +multiclass Eq { + def "": Separate<["--", "-"], name>; + def _eq: Joined<["--", "-"], name # "=">, Alias(NAME)>; +} + def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"">, HelpText<"Add a directory to the library search path">; @@ -52,6 +57,9 @@ def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; +defm undefined: Eq<"undefined">, + HelpText<"Force undefined symbol during linking">; + def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"