Index: test/wasm/archive.ll =================================================================== --- test/wasm/archive.ll +++ test/wasm/archive.ll @@ -3,26 +3,35 @@ ; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/archive2.ll -o %t.a2.o ; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/hello.ll -o %t.a3.o ; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o +; RUN: rm -f %t.imports +; RUN: not lld -flavor wasm %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED %s + +; CHECK-UNDEFINED: undefined symbol: missing_func + +; RUN: echo 'missing_func' > %t.imports ; RUN: lld -flavor wasm %t.a %t.o -o %t.wasm + ; RUN: llvm-nm -a %t.wasm | FileCheck %s declare i32 @foo() local_unnamed_addr #1 +declare i32 @missing_func() local_unnamed_addr #1 define i32 @_start() local_unnamed_addr #0 { entry: - %call = tail call i32 @foo() #2 - ret i32 %call + %call1 = call i32 @foo() #2 + %call2 = call i32 @missing_func() #2 + ret i32 %call2 } ; Verify that multually dependant object files in an archive is handled ; correctly. -; CHECK: 00000002 T _start -; CHECK-NEXT: 00000002 T _start -; CHECK-NEXT: 00000000 T bar -; CHECK-NEXT: 00000000 T bar -; CHECK-NEXT: 00000001 T foo -; CHECK-NEXT: 00000001 T foo +; CHECK: 00000003 T _start +; CHECK-NEXT: 00000003 T _start +; CHECK-NEXT: 00000001 T bar +; CHECK-NEXT: 00000001 T bar +; CHECK-NEXT: 00000002 T foo +; CHECK-NEXT: 00000002 T foo ; Verify that symbols from unused objects don't appear in the symbol table ; CHECK-NOT: hello Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -161,16 +161,36 @@ return Args; } +// Currently we allow a ".imports" to live alongside a library. This can +// be used to specify a list of symbols which can be undefined at link +// time (imported from the environment. For example libc.a include an +// import file that lists the syscall functions it relies on at runtime. +// In the long run this information would be better stored as a symbol +// attribute/flag in the object file itself. +// See: https://github.com/WebAssembly/tool-conventions/issues/35 +static void readImportFile(StringRef Filename) { + if (Optional Buf = readFile(Filename)) + for (StringRef Sym : args::getLines(*Buf)) + Config->AllowUndefinedSymbols.insert(Sym); +} + void LinkerDriver::addFile(StringRef Path) { Optional Buffer = readFile(Path); if (!Buffer.hasValue()) return; MemoryBufferRef MBRef = *Buffer; - if (identify_magic(MBRef.getBuffer()) == file_magic::archive) + if (identify_magic(MBRef.getBuffer()) == file_magic::archive) { + SmallString<128> ImportFile = Path; + path::replace_extension(ImportFile, ".imports"); + if (fs::exists(ImportFile)) + readImportFile(ImportFile.str()); + Files.push_back(make(MBRef)); - else - Files.push_back(make(MBRef)); + return; + } + + Files.push_back(make(MBRef)); } // Add a given library by searching it from input search paths. @@ -257,9 +277,7 @@ args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize); if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file)) - if (Optional Buf = readFile(Arg->getValue())) - for (StringRef Sym : args::getLines(*Buf)) - Config->AllowUndefinedSymbols.insert(Sym); + readImportFile(Arg->getValue()); if (Config->OutputFile.empty()) error("no output file specified");