Index: test/wasm/whole-archive.test =================================================================== --- /dev/null +++ test/wasm/whole-archive.test @@ -0,0 +1,34 @@ +RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o +RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +RUN: rm -f %t.a +RUN: llvm-ar rcs %t.a %t.ret32.o + +Should not add symbols from the archive by default as they are not required +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o %t.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s +NOTADDED: FunctionNames: +NOTADDED-NOT: Name: ret32 +NOTADDED: ... + +Should add symbols from the archive if --whole-archive is used +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %t.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s +ADDED: FunctionNames: +ADDED: Name: ret32 +ADDED: ... + +--no-whole-archive should restore default behaviour +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive --no-whole-archive %t.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s + +--whole-archive and --no-whole-archive should affect only archives which follow them +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o %t.a --whole-archive --no-whole-archive +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %t.a --no-whole-archive +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s + +--whole-archive should also work with thin archives +RUN: rm -f %tthin.a +RUN: llvm-ar --format=gnu rcsT %tthin.a %t.ret32.o +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %tthin.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s Index: wasm/Driver.cpp =================================================================== --- wasm/Driver.cpp +++ wasm/Driver.cpp @@ -68,6 +68,10 @@ void createFiles(opt::InputArgList &Args); void addFile(StringRef Path); void addLibrary(StringRef Name); + + // True if we are in --whole-archive and --no-whole-archive. + bool InWholeArchive = false; + std::vector Files; }; } // anonymous namespace @@ -180,6 +184,37 @@ Config->AllowUndefinedSymbols.insert(Sym); } +// Returns slices of MB by parsing MB as an archive file. +// Each slice consists of a member file in the archive. +std::vector static getArchiveMembers( + MemoryBufferRef MB) { + std::unique_ptr File = + CHECK(Archive::create(MB), + MB.getBufferIdentifier() + ": failed to parse archive"); + + std::vector V; + Error Err = Error::success(); + for (const ErrorOr &COrErr : File->children(Err)) { + Archive::Child C = + CHECK(COrErr, MB.getBufferIdentifier() + + ": could not get the child of the archive"); + MemoryBufferRef MBRef = + CHECK(C.getMemoryBufferRef(), + MB.getBufferIdentifier() + + ": could not get the buffer for a child of the archive"); + V.push_back(MBRef); + } + if (Err) + fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + + toString(std::move(Err))); + + // Take ownership of memory buffers created for members of thin archives. + for (std::unique_ptr &MB : File->takeThinBuffers()) + make>(std::move(MB)); + + return V; +} + void LinkerDriver::addFile(StringRef Path) { Optional Buffer = readFile(Path); if (!Buffer.hasValue()) @@ -188,6 +223,13 @@ switch (identify_magic(MBRef.getBuffer())) { case file_magic::archive: { + // Handle -whole-archive. + if (InWholeArchive) { + for (MemoryBufferRef &M : getArchiveMembers(MBRef)) + Files.push_back(createObjectFile(M)); + return; + } + SmallString<128> ImportFile = Path; path::replace_extension(ImportFile, ".imports"); if (fs::exists(ImportFile)) @@ -197,10 +239,11 @@ return; } case file_magic::bitcode: - Files.push_back(make(MBRef)); + case file_magic::wasm_object: + Files.push_back(createObjectFile(MBRef)); break; default: - Files.push_back(make(MBRef)); + error("unknown file type: " + MBRef.getBufferIdentifier()); } } @@ -225,6 +268,12 @@ case OPT_INPUT: addFile(Arg->getValue()); break; + case OPT_whole_archive: + InWholeArchive = true; + break; + case OPT_no_whole_archive: + InWholeArchive = false; + break; } } } Index: wasm/InputFiles.h =================================================================== --- wasm/InputFiles.h +++ wasm/InputFiles.h @@ -150,6 +150,10 @@ std::unique_ptr Obj; }; +// Will report a fatal() error if the input buffer is not a valid bitcode +// or was object file. +InputFile *createObjectFile(MemoryBufferRef MB); + // Opens a given file. llvm::Optional readFile(StringRef Path); Index: wasm/InputFiles.cpp =================================================================== --- wasm/InputFiles.cpp +++ wasm/InputFiles.cpp @@ -42,6 +42,17 @@ return MBRef; } +InputFile *lld::wasm::createObjectFile(MemoryBufferRef MB) { + file_magic Magic = identify_magic(MB.getBuffer()); + if (Magic == file_magic::wasm_object) + return make(MB); + + if (Magic == file_magic::bitcode) + return make(MB); + + fatal("unknown file type: " + MB.getBufferIdentifier()); +} + void ObjFile::dumpInfo() const { log("info for: " + getName() + "\n Symbols : " + Twine(Symbols.size()) + @@ -360,18 +371,7 @@ "could not get the buffer for the member defining symbol " + Sym->getName()); - InputFile *Obj; - - file_magic Magic = identify_magic(MB.getBuffer()); - if (Magic == file_magic::wasm_object) { - Obj = make(MB); - } else if (Magic == file_magic::bitcode) { - Obj = make(MB); - } else { - error("unknown file type: " + MB.getBufferIdentifier()); - return; - } - + InputFile *Obj = createObjectFile(MB); Obj->ArchiveName = getName(); Symtab->addFile(Obj); } Index: wasm/Options.td =================================================================== --- wasm/Options.td +++ wasm/Options.td @@ -132,6 +132,10 @@ def stack_first: F<"stack-first">, HelpText<"Place stack at start of linear memory rather than after data">; +defm whole_archive: B<"whole-archive", + "Force load of all members in a static library", + "Do not force load of all members in a static library (default)">; + // Aliases def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias; def alias_entry_entry: J<"entry=">, Alias; Index: wasm/SymbolTable.cpp =================================================================== --- wasm/SymbolTable.cpp +++ wasm/SymbolTable.cpp @@ -74,7 +74,7 @@ if (Undefs.empty()) return; - for (ObjFile *File : ObjectFiles) + for (InputFile *File : ObjectFiles) for (Symbol *Sym : File->getSymbols()) if (Undefs.count(Sym)) error(toString(File) + ": undefined symbol: " + toString(*Sym));