Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -31,6 +31,7 @@ bool ExportDynamic = false; bool NoInhibitExec = false; bool Shared = false; + bool WholeArchive = false; }; extern Configuration *Config; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -125,33 +125,33 @@ Config->NoInhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->Shared = Args.hasArg(OPT_shared); - // Create a list of input files. - std::vector Inputs; - - for (auto *Arg : Args.filtered(OPT_l, OPT_INPUT)) { - StringRef Path = Arg->getValue(); - if (Arg->getOption().getID() == OPT_l) { - Inputs.push_back(openFile(searchLibrary(Path))); - continue; - } - Inputs.push_back(openFile(Path)); - } - - if (Inputs.empty()) - error("no input files."); - // Create a symbol table. SymbolTable Symtab; - // Parse all input files and put all symbols to the symbol table. - // The symbol table will take care of name resolution. - for (MemoryBufferRef MB : Inputs) { - std::unique_ptr File = createFile(MB); - Symtab.addFile(std::move(File)); + // Parse all input files considering corresponding command line options. + // Put all symbols to the symbol table which takes care of name resolution. + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_l: + Symtab.addFile(createFile(openFile(searchLibrary(Arg->getValue())))); + break; + case OPT_INPUT: + Symtab.addFile(createFile(openFile(Arg->getValue()))); + break; + case OPT_whole_archive: + Config->WholeArchive = true; + break; + case OPT_no_whole_archive: + Config->WholeArchive = false; + break; + } } - // Write the result. const ELFFileBase *FirstObj = Symtab.getFirstELF(); + if (!FirstObj) + error("no input files."); + + // Write the result. switch (FirstObj->getELFKind()) { case ELF32LEKind: writeResult(&Symtab); Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -174,7 +174,8 @@ // (So that we don't instantiate same members more than once.) MemoryBufferRef getMember(const Archive::Symbol *Sym); - llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } + llvm::MutableArrayRef getLazySymbols(); + std::vector getMembers(); private: std::unique_ptr File; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -184,14 +184,6 @@ ErrorOr> ArchiveOrErr = Archive::create(MB); error(ArchiveOrErr, "Failed to parse archive"); File = std::move(*ArchiveOrErr); - - // Allocate a buffer for Lazy objects. - size_t NumSyms = File->getNumberOfSymbols(); - LazySymbols.reserve(NumSyms); - - // Read the symbol table to construct Lazy objects. - for (const Archive::Symbol &Sym : File->symbols()) - LazySymbols.emplace_back(this, Sym); } // Returns a buffer pointing to a member file containing a given symbol. @@ -210,6 +202,37 @@ return *Ret; } +llvm::MutableArrayRef ArchiveFile::getLazySymbols() { + if (!LazySymbols.empty()) + return LazySymbols; + + assert(nullptr != File && "File isn't opened, call parse() first"); + + // Allocate a buffer for Lazy objects. + size_t NumSyms = File->getNumberOfSymbols(); + LazySymbols.reserve(NumSyms); + + // Read the symbol table to construct Lazy objects. + for (const Archive::Symbol &Sym : File->symbols()) + LazySymbols.emplace_back(this, Sym); + + return LazySymbols; +} + +std::vector ArchiveFile::getMembers() { + assert(nullptr != File && "File isn't opened, call parse() first"); + + std::vector Result; + for (const Archive::Child &Child : File->children()) { + ErrorOr MbOrErr = Child.getMemoryBufferRef(); + error(MbOrErr, + Twine("Could not get the buffer for a child of the archive ") + + File->getFileName()); + Result.push_back(MbOrErr.get()); + } + return Result; +} + template SharedFile::SharedFile(MemoryBufferRef M) : SharedFileBase(getStaticELFKind(), M), ELFData(M) {} Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -56,6 +56,12 @@ def sysroot : Joined<["--"], "sysroot=">, HelpText<"Set the system root">; +def whole_archive : Flag<["--"], "whole-archive">, + HelpText<"Force load of all members in a static library">; + +def no_whole_archive : Flag<["--"], "no-whole-archive">, + HelpText<"Restores the default behavior of loading archive members">; + def entry : Separate<["--", "-"], "entry">, MetaVarName<"">, HelpText<"Name of entry point symbol">; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -32,8 +32,13 @@ InputFile *FileP = File.release(); if (auto *AF = dyn_cast(FileP)) { ArchiveFiles.emplace_back(AF); - for (Lazy &Sym : AF->getLazySymbols()) - addLazy(&Sym); + if (Config->WholeArchive) { + for (MemoryBufferRef &MBRef : AF->getMembers()) + addFile(createELFFile(MBRef)); + } else { + for (Lazy &Sym : AF->getLazySymbols()) + addLazy(&Sym); + } return; } addELFFile(cast(FileP)); Index: test/elf2/Inputs/whole-archive.s =================================================================== --- /dev/null +++ test/elf2/Inputs/whole-archive.s @@ -0,0 +1,2 @@ +.globl _bar; +_bar: Index: test/elf2/whole-archive.s =================================================================== --- /dev/null +++ test/elf2/whole-archive.s @@ -0,0 +1,34 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +// RUN: %p/Inputs/whole-archive.s -o %ta.o +// RUN: rm -f %t.a +// RUN: llvm-ar rcs %t.a %ta.o + +// Should not add symbols from the archive by default as they are not required +// RUN: lld -flavor gnu2 -o %t3 %t.o %t.a +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s +// NOTADDED: Symbols [ +// NOTADDED-NOT: Name: _bar +// NOTADDED: ] + +// Should add symbols from the archive if --whole-archive is used +// RUN: lld -flavor gnu2 -o %t3 %t.o --whole-archive %t.a +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s +// ADDED: Symbols [ +// ADDED: Name: _bar +// ADDED: ] + +// --no-whole-archive should restore default behaviour +// RUN: lld -flavor gnu2 -o %t3 %t.o --whole-archive --no-whole-archive %t.a +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s + +// --whole-archive and --no-whole-archive should affect only archives which follow them +// RUN: lld -flavor gnu2 -o %t3 %t.o %t.a --whole-archive --no-whole-archive +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=NOTADDED %s +// RUN: lld -flavor gnu2 -o %t3 %t.o --whole-archive %t.a --no-whole-archive +// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s + +.globl _start; +_start: