Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -31,6 +31,7 @@ bool ExportDynamic; bool NoInhibitExec; bool Shared; + bool WholeArchive = false; }; extern Configuration *Config; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -88,6 +88,17 @@ return identify_magic(MB.getBuffer()) == file_magic::unknown; } +// Runs the linker script or adds the file to the symbol table +// depending on its type. +static void addInputFile(SymbolTable *Symtab, StringRef Path) { + MemoryBufferRef MB = openFile(Path); + if (isLinkerScript(MB)) + // readLinkerScript may add files to the symbol table. + readLinkerScript(Symtab, MB); + else + Symtab->addFile(createFile(MB)); +} + void LinkerDriver::link(ArrayRef ArgsArr) { // Parse command line options. opt::InputArgList Args = Parser.parse(ArgsArr); @@ -124,17 +135,23 @@ // Create a symbol table. SymbolTable Symtab; - for (auto *Arg : Args.filtered(OPT_l, OPT_INPUT)) { - std::string Path = Arg->getValue(); - if (Arg->getOption().getID() == OPT_l) - Path = searchLibrary(Path); - MemoryBufferRef MB = openFile(Path); - if (isLinkerScript(MB)) { - // readLinkerScript may add files to the symbol table. - readLinkerScript(&Symtab, MB); + for (auto *Arg : Args) { + switch (Arg->getOption().getID()) { + case OPT_l: + addInputFile(&Symtab, searchLibrary(Arg->getValue())); + break; + case OPT_INPUT: + addInputFile(&Symtab, Arg->getValue()); + break; + case OPT_whole_archive: + Config->WholeArchive = true; + break; + case OPT_no_whole_archive: + Config->WholeArchive = false; + break; + default: continue; } - Symtab.addFile(createFile(MB)); } if (Symtab.getObjectFiles().empty()) Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -178,8 +178,11 @@ MemoryBufferRef getMember(const Archive::Symbol *Sym); llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } + std::vector getMembers(); private: + void openArchive(); + std::unique_ptr File; std::vector LazySymbols; llvm::DenseSet Seen; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -191,9 +191,7 @@ } void ArchiveFile::parse() { - ErrorOr> ArchiveOrErr = Archive::create(MB); - error(ArchiveOrErr, "Failed to parse archive"); - File = std::move(*ArchiveOrErr); + openArchive(); // Allocate a buffer for Lazy objects. size_t NumSyms = File->getNumberOfSymbols(); @@ -220,6 +218,29 @@ return *Ret; } +std::vector ArchiveFile::getMembers() { + openArchive(); + + 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; +} + +void ArchiveFile::openArchive() { + if (File) + return; + + ErrorOr> ArchiveOrErr = Archive::create(MB); + error(ArchiveOrErr, "Failed to parse archive"); + File = std::move(*ArchiveOrErr); +} + template SharedFile::SharedFile(MemoryBufferRef M) : SharedFileBase(getStaticELFKind(), M), ELFData(M) {} Index: ELF/Options.td =================================================================== --- ELF/Options.td +++ ELF/Options.td @@ -42,6 +42,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">; + // Aliases def alias_L : Joined<["--"], "library-path=">, Alias; def alias_discard_all: Flag<["-"], "x">, Alias; Index: ELF/SymbolTable.cpp =================================================================== --- ELF/SymbolTable.cpp +++ ELF/SymbolTable.cpp @@ -28,15 +28,21 @@ } void SymbolTable::addFile(std::unique_ptr File) { - File->parse(); - InputFile *FileP = File.release(); - if (auto *AF = dyn_cast(FileP)) { + if (auto *AF = dyn_cast(File.get())) { + File.release(); ArchiveFiles.emplace_back(AF); - for (Lazy &Sym : AF->getLazySymbols()) - addLazy(&Sym); + if (Config->WholeArchive) { + for (MemoryBufferRef &MBRef : AF->getMembers()) + addFile(createELFFile(MBRef)); + } else { + AF->parse(); + for (Lazy &Sym : AF->getLazySymbols()) + addLazy(&Sym); + } return; } - addELFFile(cast(FileP)); + File->parse(); + addELFFile(cast(File.release())); } static TargetInfo *createTarget(uint16_t EMachine) { 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: