Index: ELF/Config.h =================================================================== --- ELF/Config.h +++ ELF/Config.h @@ -32,6 +32,7 @@ bool NoInhibitExec; bool Shared; bool Static = false; + bool WholeArchive = false; }; extern Configuration *Config; Index: ELF/Driver.cpp =================================================================== --- ELF/Driver.cpp +++ ELF/Driver.cpp @@ -139,6 +139,12 @@ case OPT_Bdynamic: Config->Static = false; break; + case OPT_whole_archive: + Config->WholeArchive = true; + break; + case OPT_no_whole_archive: + Config->WholeArchive = false; + break; default: break; } Index: ELF/InputFiles.h =================================================================== --- ELF/InputFiles.h +++ ELF/InputFiles.h @@ -176,6 +176,7 @@ MemoryBufferRef getMember(const Archive::Symbol *Sym); llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } + std::vector getMembers(); private: std::unique_ptr File; Index: ELF/InputFiles.cpp =================================================================== --- ELF/InputFiles.cpp +++ ELF/InputFiles.cpp @@ -181,10 +181,14 @@ } } -void ArchiveFile::parse() { +static std::unique_ptr openArchive(MemoryBufferRef MB) { ErrorOr> ArchiveOrErr = Archive::create(MB); error(ArchiveOrErr, "Failed to parse archive"); - File = std::move(*ArchiveOrErr); + return std::move(*ArchiveOrErr); +} + +void ArchiveFile::parse() { + File = openArchive(MB); // Allocate a buffer for Lazy objects. size_t NumSyms = File->getNumberOfSymbols(); @@ -211,6 +215,20 @@ return *Ret; } +std::vector ArchiveFile::getMembers() { + File = openArchive(MB); + + 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 @@ -36,6 +36,9 @@ def noinhibit_exec : Flag<["--"], "noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; +def no_whole_archive : Flag<["--"], "no-whole-archive">, + HelpText<"Restores the default behavior of loading archive members">; + def output : Separate<["-"], "o">, MetaVarName<"">, HelpText<"Path to file to write output">; @@ -48,6 +51,9 @@ 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">; + // Aliases def alias_Bdynamic_call_shared: Flag<["-"], "call_shared">, Alias; def alias_Bdynamic_dy: Flag<["-"], "dy">, 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); + if (Config->WholeArchive) { + for (MemoryBufferRef &MBRef : AF->getMembers()) + addFile(createELFFile(MBRef)); + return; + } + 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: