forked from OSchip/llvm-project
[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
This commit is contained in:
parent
8460b26403
commit
31de2f0ccf
|
@ -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
|
|
@ -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()) {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue