Skip to content

Commit

Permalink
[WebAssembly] When loading libraries look for companion .imports file
Browse files Browse the repository at this point in the history
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:
 WebAssembly/tool-conventions#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
  • Loading branch information
sbc100 committed Jan 11, 2018
1 parent ea4359e commit 31efdcd
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 14 deletions.
25 changes: 17 additions & 8 deletions lld/test/wasm/archive.ll
Expand Up @@ -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
Expand Down
30 changes: 24 additions & 6 deletions lld/wasm/Driver.cpp
Expand Up @@ -161,16 +161,36 @@ opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> 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<MemoryBufferRef> Buf = readFile(Filename))
for (StringRef Sym : args::getLines(*Buf))
Config->AllowUndefinedSymbols.insert(Sym);
}

void LinkerDriver::addFile(StringRef Path) {
Optional<MemoryBufferRef> 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<ArchiveFile>(MBRef));
else
Files.push_back(make<ObjFile>(MBRef));
return;
}

Files.push_back(make<ObjFile>(MBRef));
}

// Add a given library by searching it from input search paths.
Expand Down Expand Up @@ -257,9 +277,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) {
args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize);

if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file))
if (Optional<MemoryBufferRef> 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");
Expand Down

0 comments on commit 31efdcd

Please sign in to comment.