From 2696bbeb93acf67734fe1310ef3d643ab377deba Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Thu, 1 Oct 2015 18:02:21 +0000 Subject: [PATCH] [ELF2] Add --[no-]whole-archive command line switches Summary: If --whole-archive is used, all symbols from the following archives are added to the output. --no-whole-archive restores default behavior. These switches can be used multiple times. NB. We have to keep an ArchiveFile instance within SymbolTable even if --whole-archive mode is active since it can be a thin archive which contains just names of external files. In that case actual memory buffers for the archive members will be stored within the File member of ArchiveFile class. Reviewers: rafael, ruiu Subscribers: grimar, llvm-commits Projects: #lld Differential Revision: http://reviews.llvm.org/D13286 llvm-svn: 249045 --- lld/ELF/Config.h | 1 + lld/ELF/Driver.cpp | 6 +++++ lld/ELF/InputFiles.cpp | 22 ++++++++++++++++-- lld/ELF/InputFiles.h | 1 + lld/ELF/Options.td | 6 +++++ lld/ELF/SymbolTable.cpp | 14 ++++++++---- lld/test/elf2/Inputs/whole-archive.s | 2 ++ lld/test/elf2/whole-archive.s | 34 ++++++++++++++++++++++++++++ 8 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 lld/test/elf2/Inputs/whole-archive.s create mode 100644 lld/test/elf2/whole-archive.s diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index 10b92b7c19b9..2e2c031abbba 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -32,6 +32,7 @@ struct Configuration { bool NoInhibitExec; bool Shared; bool Static = false; + bool WholeArchive = false; }; extern Configuration *Config; diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index e611511d64fa..af8144fbd98a 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -139,6 +139,12 @@ void LinkerDriver::link(ArrayRef ArgsArr) { 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; } diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index cc7bbaa92160..5eabb298c2a5 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -181,10 +181,14 @@ SymbolBody *elf2::ObjectFile::createSymbolBody(StringRef StringTable, } } -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 @@ MemoryBufferRef ArchiveFile::getMember(const Archive::Symbol *Sym) { 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) {} diff --git a/lld/ELF/InputFiles.h b/lld/ELF/InputFiles.h index 47bf36fe5b98..4bb0d8f8ca53 100644 --- a/lld/ELF/InputFiles.h +++ b/lld/ELF/InputFiles.h @@ -176,6 +176,7 @@ public: MemoryBufferRef getMember(const Archive::Symbol *Sym); llvm::MutableArrayRef getLazySymbols() { return LazySymbols; } + std::vector getMembers(); private: std::unique_ptr File; diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td index 8b8e265d7dfc..4d4a84eee6c5 100644 --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -37,6 +37,9 @@ def l : Joined<["-"], "l">, MetaVarName<"">, def no_allow_shlib_undefined : Flag<["--"], "no-allow-shlib-undefined">; +def no_whole_archive : Flag<["--"], "no-whole-archive">, + HelpText<"Restores the default behavior of loading archive members">; + def noinhibit_exec : Flag<["--"], "noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; @@ -52,6 +55,9 @@ def shared : Flag<["-"], "shared">, 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; diff --git a/lld/ELF/SymbolTable.cpp b/lld/ELF/SymbolTable.cpp index 43b068d6676a..42b04596b894 100644 --- a/lld/ELF/SymbolTable.cpp +++ b/lld/ELF/SymbolTable.cpp @@ -28,15 +28,21 @@ bool SymbolTable::shouldUseRela() const { } 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) { diff --git a/lld/test/elf2/Inputs/whole-archive.s b/lld/test/elf2/Inputs/whole-archive.s new file mode 100644 index 000000000000..f9d56fc2fa21 --- /dev/null +++ b/lld/test/elf2/Inputs/whole-archive.s @@ -0,0 +1,2 @@ +.globl _bar; +_bar: diff --git a/lld/test/elf2/whole-archive.s b/lld/test/elf2/whole-archive.s new file mode 100644 index 000000000000..0b14ada126ce --- /dev/null +++ b/lld/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: