From 31efdcd78e3b7b41884875bcfef2f87c53a95d8a Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Thu, 11 Jan 2018 22:31:35 +0000 Subject: [PATCH] [WebAssembly] When loading libraries look for companion `.imports` file This allows libraries to supply a list of symbols which are allowed to be undefined at link time (i.e. result in imports). This method replaces the existing mechanism (-allow-undefined-file) used by the clang driver to allow undefined symbols in libc. For more on motivation for this see: https://github.com/WebAssembly/tool-conventions/issues/35 In the long run we hope to remove this features and instead include this information in the object format itself. Differential Revision: https://reviews.llvm.org/D41922 llvm-svn: 322320 --- lld/test/wasm/archive.ll | 25 +++++++++++++++++-------- lld/wasm/Driver.cpp | 30 ++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/lld/test/wasm/archive.ll b/lld/test/wasm/archive.ll index a43e460d69f26..536c2bcfc058e 100644 --- a/lld/test/wasm/archive.ll +++ b/lld/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 diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp index 97ec262be3081..0059e5649e8a7 100644 --- a/lld/wasm/Driver.cpp +++ b/lld/wasm/Driver.cpp @@ -161,16 +161,36 @@ opt::InputArgList WasmOptTable::parse(ArrayRef Argv) { 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 @@ void LinkerDriver::link(ArrayRef ArgsArr) { 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");