diff options
| author | Sam Clegg <sbc@chromium.org> | 2017-12-07 03:19:53 +0000 |
|---|---|---|
| committer | Sam Clegg <sbc@chromium.org> | 2017-12-07 03:19:53 +0000 |
| commit | 31de2f0ccf4b616f595cef9b6181ce86ea419527 (patch) | |
| tree | acce0c6f2c096ccfa6a85754d3026ca246966bae | |
| parent | 8460b26403736e50afbb92b0657b8e556eb87a3c (diff) | |
| download | bcm5719-llvm-31de2f0ccf4b616f595cef9b6181ce86ea419527.tar.gz bcm5719-llvm-31de2f0ccf4b616f595cef9b6181ce86ea419527.zip | |
[WebAssembly] Add -u/--undefined argument handling
Adds a new argument to wasm-lld, `--undefined`, with
similar semantics to the ELF linker. It pulls in symbols
from files contained within a `.a` archive, forcing them
to be included even if the translation unit would not
otherwise be pulled in.
Patch by Nicholas Wilson
Differential Revision: https://reviews.llvm.org/D40724
llvm-svn: 320004
| -rw-r--r-- | lld/test/wasm/load-undefined.ll | 38 | ||||
| -rw-r--r-- | lld/wasm/Driver.cpp | 18 | ||||
| -rw-r--r-- | lld/wasm/Options.td | 9 | ||||
| -rw-r--r-- | lld/wasm/SymbolTable.cpp | 4 | ||||
| -rw-r--r-- | lld/wasm/Symbols.h | 1 |
5 files changed, 70 insertions, 0 deletions
diff --git a/lld/test/wasm/load-undefined.ll b/lld/test/wasm/load-undefined.ll new file mode 100644 index 00000000000..f979c9acb51 --- /dev/null +++ b/lld/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 diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 4f8f25f79c2..0b9653d9141 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -273,6 +273,8 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { 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 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; addSyntheticUndefinedFunction(Config->Entry, &Signature); + // Handle the `--undefined <sym>` options. + for (StringRef S : args::getStrings(Args, OPT_undefined)) + addSyntheticUndefinedFunction(S, nullptr); + Config->StackPointerSymbol = addSyntheticGlobal("__stack_pointer", 0); } @@ -297,6 +303,18 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { 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()) { diff --git a/lld/wasm/Options.td b/lld/wasm/Options.td index ca2400f32ca..e33b63f2d45 100644 --- a/lld/wasm/Options.td +++ b/lld/wasm/Options.td @@ -6,6 +6,11 @@ class F<string name>: Flag<["--", "-"], name>; class J<string name>: Joined<["--", "-"], name>; class S<string name>: Separate<["--", "-"], name>; +multiclass Eq<string name> { + def "": Separate<["--", "-"], name>; + def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>; +} + def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, HelpText<"Add a directory to the library search path">; @@ -52,6 +57,9 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; 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<"<option>">, HelpText<"Linker option extensions">; @@ -89,3 +97,4 @@ def alias_max_memory_m: Flag<["-"], "m">, Alias<max_memory>; def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; def alias_entry_entry: J<"entry=">, Alias<entry>; +def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>; diff --git a/lld/wasm/SymbolTable.cpp b/lld/wasm/SymbolTable.cpp index 5b65de86080..d9a6fa1f04f 100644 --- a/lld/wasm/SymbolTable.cpp +++ b/lld/wasm/SymbolTable.cpp @@ -118,6 +118,10 @@ static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, // For function symbols, optionally check the function signature matches too. if (!NewIsFunction || !Config->CheckSignatures) return; + // 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 (!Existing.hasFunctionType()) + return; DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n"); assert(NewSig); diff --git a/lld/wasm/Symbols.h b/lld/wasm/Symbols.h index 323746cc056..0f1c372a59b 100644 --- a/lld/wasm/Symbols.h +++ b/lld/wasm/Symbols.h @@ -69,6 +69,7 @@ public: uint32_t getGlobalIndex() const; uint32_t getFunctionIndex() const; + bool hasFunctionType() const { return FunctionType != nullptr; } const WasmSignature &getFunctionType() const; uint32_t getOutputIndex() const; |

