[lld] r265710 - ELF: Implement --start-lib and --end-lib
Rui Ueyama via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 7 12:24:53 PDT 2016
Author: ruiu
Date: Thu Apr 7 14:24:51 2016
New Revision: 265710
URL: http://llvm.org/viewvc/llvm-project?rev=265710&view=rev
Log:
ELF: Implement --start-lib and --end-lib
start-lib and end-lib are options to link object files in the same
semantics as archive files. If an object is in start-lib and end-lib,
the object is linked only when the file is needed to resolve
undefined symbols. That means, if an object is in start-lib and end-lib,
it behaves as if it were in an archive file.
In this patch, I introduced a new notion, LazyObjectFile. That is
analogous to Archive file type, but that works for a single object
file instead of for an archive file.
http://reviews.llvm.org/D18814
Added:
lld/trunk/test/ELF/lto/Inputs/start-lib.ll
lld/trunk/test/ELF/lto/start-lib.ll
lld/trunk/test/ELF/start-lib.s
Modified:
lld/trunk/ELF/Driver.cpp
lld/trunk/ELF/Driver.h
lld/trunk/ELF/InputFiles.cpp
lld/trunk/ELF/InputFiles.h
lld/trunk/ELF/Options.td
lld/trunk/ELF/OutputSections.cpp
lld/trunk/ELF/SymbolTable.cpp
lld/trunk/ELF/SymbolTable.h
lld/trunk/ELF/Symbols.cpp
lld/trunk/ELF/Symbols.h
Modified: lld/trunk/ELF/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.cpp (original)
+++ lld/trunk/ELF/Driver.cpp Thu Apr 7 14:24:51 2016
@@ -129,7 +129,10 @@ void LinkerDriver::addFile(StringRef Pat
Files.push_back(createSharedFile(MBRef));
return;
default:
- Files.push_back(createObjectFile(MBRef));
+ if (InLib)
+ Files.push_back(make_unique<LazyObjectFile>(MBRef));
+ else
+ Files.push_back(createObjectFile(MBRef));
}
}
@@ -359,6 +362,12 @@ void LinkerDriver::createFiles(opt::Inpu
case OPT_no_whole_archive:
WholeArchive = false;
break;
+ case OPT_start_lib:
+ InLib = true;
+ break;
+ case OPT_end_lib:
+ InLib = false;
+ break;
}
}
Modified: lld/trunk/ELF/Driver.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Driver.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Driver.h (original)
+++ lld/trunk/ELF/Driver.h Thu Apr 7 14:24:51 2016
@@ -33,8 +33,13 @@ private:
void createFiles(llvm::opt::InputArgList &Args);
template <class ELFT> void link(llvm::opt::InputArgList &Args);
- llvm::BumpPtrAllocator Alloc;
+ // True if we are in --whole-archive and --no-whole-archive.
bool WholeArchive = false;
+
+ // True if we are in --start-lib and --end-lib.
+ bool InLib = false;
+
+ llvm::BumpPtrAllocator Alloc;
std::vector<std::unique_ptr<InputFile>> Files;
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
};
Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Thu Apr 7 14:24:51 2016
@@ -564,6 +564,66 @@ std::unique_ptr<InputFile> elf::createSh
return createELFFile<SharedFile>(MB);
}
+void LazyObjectFile::parse() {
+ for (StringRef Sym : getSymbols())
+ LazySymbols.emplace_back(Sym, this->MB);
+}
+
+template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
+ typedef typename ELFT::Shdr Elf_Shdr;
+ typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::SymRange Elf_Sym_Range;
+
+ const ELFFile<ELFT> Obj = createELFObj<ELFT>(this->MB);
+ for (const Elf_Shdr &Sec : Obj.sections()) {
+ if (Sec.sh_type != SHT_SYMTAB)
+ continue;
+ Elf_Sym_Range Syms = Obj.symbols(&Sec);
+ uint32_t FirstNonLocal = Sec.sh_info;
+ StringRef StringTable = check(Obj.getStringTableForSymtab(Sec));
+ std::vector<StringRef> V;
+ for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
+ V.push_back(check(Sym.getName(StringTable)));
+ return V;
+ }
+ return {};
+}
+
+std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
+ LLVMContext Context;
+ std::unique_ptr<IRObjectFile> Obj =
+ check(IRObjectFile::create(this->MB, Context));
+ std::vector<StringRef> V;
+ for (const BasicSymbolRef &Sym : Obj->symbols()) {
+ if (BitcodeFile::shouldSkip(Sym))
+ continue;
+ SmallString<64> Name;
+ raw_svector_ostream OS(Name);
+ Sym.printName(OS);
+ V.push_back(Saver.save(StringRef(Name)));
+ }
+ return V;
+}
+
+// Returns a vector of globally-visible symbol names.
+std::vector<StringRef> LazyObjectFile::getSymbols() {
+ using namespace sys::fs;
+
+ StringRef Buf = this->MB.getBuffer();
+ if (identify_magic(Buf) == file_magic::bitcode)
+ return getBitcodeSymbols();
+
+ std::pair<unsigned char, unsigned char> Type = getElfArchType(Buf);
+ if (Type.first == ELF::ELFCLASS32) {
+ if (Type.second == ELF::ELFDATA2LSB)
+ return getElfSymbols<ELF32LE>();
+ return getElfSymbols<ELF32BE>();
+ }
+ if (Type.second == ELF::ELFDATA2LSB)
+ return getElfSymbols<ELF64LE>();
+ return getElfSymbols<ELF64BE>();
+}
+
template class elf::ELFFileBase<ELF32LE>;
template class elf::ELFFileBase<ELF32BE>;
template class elf::ELFFileBase<ELF64LE>;
Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Thu Apr 7 14:24:51 2016
@@ -36,7 +36,14 @@ class SymbolBody;
// The root class of input files.
class InputFile {
public:
- enum Kind { ObjectKind, SharedKind, ArchiveKind, BitcodeKind };
+ enum Kind {
+ ObjectKind,
+ SharedKind,
+ LazyObjectKind,
+ ArchiveKind,
+ BitcodeKind,
+ };
+
Kind kind() const { return FileKind; }
StringRef getName() const { return MB.getBufferIdentifier(); }
@@ -154,6 +161,36 @@ private:
llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc;
};
+// LazyObjectFile is analogous to ArchiveFile in the sense that
+// the file contains lazy symbols. The difference is that
+// LazyObjectFile wraps a single file instead of multiple files.
+//
+// This class is used for --start-lib and --end-lib options which
+// instruct the linker to link object files between them with the
+// archive file semantics.
+class LazyObjectFile : public InputFile {
+public:
+ explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {}
+
+ static bool classof(const InputFile *F) {
+ return F->kind() == LazyObjectKind;
+ }
+
+ void parse();
+
+ llvm::MutableArrayRef<LazyObject> getLazySymbols() { return LazySymbols; }
+
+private:
+ std::vector<StringRef> getSymbols();
+ template <class ELFT> std::vector<StringRef> getElfSymbols();
+ std::vector<StringRef> getBitcodeSymbols();
+
+ llvm::BumpPtrAllocator Alloc;
+ llvm::StringSaver Saver{Alloc};
+ std::vector<LazyObject> LazySymbols;
+};
+
+// An ArchiveFile object represents a .a file.
class ArchiveFile : public InputFile {
public:
explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
@@ -165,11 +202,11 @@ public:
// (So that we don't instantiate same members more than once.)
MemoryBufferRef getMember(const Archive::Symbol *Sym);
- llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; }
+ llvm::MutableArrayRef<LazyArchive> getLazySymbols() { return LazySymbols; }
private:
std::unique_ptr<Archive> File;
- std::vector<Lazy> LazySymbols;
+ std::vector<LazyArchive> LazySymbols;
llvm::DenseSet<uint64_t> Seen;
};
Modified: lld/trunk/ELF/Options.td
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Options.td?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Options.td (original)
+++ lld/trunk/ELF/Options.td Thu Apr 7 14:24:51 2016
@@ -48,6 +48,9 @@ def eh_frame_hdr : Flag<["--"], "eh-fram
def enable_new_dtags : Flag<["--"], "enable-new-dtags">,
HelpText<"Enable new dynamic tags">;
+def end_lib : Flag<["--"], "end-lib">,
+ HelpText<"End a library">;
+
def entry : Separate<["--", "-"], "entry">, MetaVarName<"<entry>">,
HelpText<"Name of entry point symbol">;
@@ -121,6 +124,9 @@ def shared : Flag<["-"], "shared">,
def soname : Joined<["-"], "soname=">,
HelpText<"Set DT_SONAME">;
+def start_lib : Flag<["--"], "start-lib">,
+ HelpText<"Start a library">;
+
def strip_all : Flag<["--"], "strip-all">,
HelpText<"Strip all symbols">;
Modified: lld/trunk/ELF/OutputSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.cpp (original)
+++ lld/trunk/ELF/OutputSections.cpp Thu Apr 7 14:24:51 2016
@@ -1501,7 +1501,8 @@ SymbolTableSection<ELFT>::getOutputSecti
break;
case SymbolBody::UndefinedElfKind:
case SymbolBody::UndefinedBitcodeKind:
- case SymbolBody::LazyKind:
+ case SymbolBody::LazyArchiveKind:
+ case SymbolBody::LazyObjectKind:
break;
case SymbolBody::DefinedBitcodeKind:
llvm_unreachable("should have been replaced");
Modified: lld/trunk/ELF/SymbolTable.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.cpp (original)
+++ lld/trunk/ELF/SymbolTable.cpp Thu Apr 7 14:24:51 2016
@@ -75,7 +75,7 @@ void SymbolTable<ELFT>::addFile(std::uni
return;
}
- // LLVM bitcode file.
+ // LLVM bitcode file
if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
F->parse(ComdatGroups);
@@ -85,7 +85,16 @@ void SymbolTable<ELFT>::addFile(std::uni
return;
}
- // .o file
+ // Lazy object file
+ if (auto *F = dyn_cast<LazyObjectFile>(FileP)) {
+ LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release()));
+ F->parse();
+ for (Lazy &Sym : F->getLazySymbols())
+ addLazy(&Sym);
+ return;
+ }
+
+ // Regular object file
auto *F = cast<ObjectFile<ELFT>>(FileP);
ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
F->parse(ComdatGroups);
@@ -306,7 +315,7 @@ void SymbolTable<ELFT>::addMemberFile(Sy
// Fetch a member file that has the definition for L.
// getMember returns nullptr if the member was already read from the library.
- if (std::unique_ptr<InputFile> File = L->getMember())
+ if (std::unique_ptr<InputFile> File = L->getFile())
addFile(std::move(File));
}
Modified: lld/trunk/ELF/SymbolTable.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SymbolTable.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/SymbolTable.h (original)
+++ lld/trunk/ELF/SymbolTable.h Thu Apr 7 14:24:51 2016
@@ -89,6 +89,7 @@ private:
// The symbol table owns all file objects.
std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
+ std::vector<std::unique_ptr<LazyObjectFile>> LazyObjectFiles;
std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles;
Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Thu Apr 7 14:24:51 2016
@@ -78,7 +78,8 @@ static typename ELFT::uint getSymVA(cons
case SymbolBody::UndefinedElfKind:
case SymbolBody::UndefinedBitcodeKind:
return 0;
- case SymbolBody::LazyKind:
+ case SymbolBody::LazyArchiveKind:
+ case SymbolBody::LazyObjectKind:
assert(Body.isUsedInRegularObj() && "lazy symbol reached writer");
return 0;
case SymbolBody::DefinedBitcodeKind:
@@ -301,7 +302,13 @@ DefinedCommon::DefinedCommon(StringRef N
: Defined(SymbolBody::DefinedCommonKind, N, Binding, StOther, Type),
Alignment(Alignment), Size(Size) {}
-std::unique_ptr<InputFile> Lazy::getMember() {
+std::unique_ptr<InputFile> Lazy::getFile() {
+ if (auto *S = dyn_cast<LazyArchive>(this))
+ return S->getFile();
+ return cast<LazyObject>(this)->getFile();
+}
+
+std::unique_ptr<InputFile> LazyArchive::getFile() {
MemoryBufferRef MBRef = File->getMember(&Sym);
// getMember returns an empty buffer if the member was already
@@ -311,6 +318,10 @@ std::unique_ptr<InputFile> Lazy::getMemb
return createObjectFile(MBRef, File->getName());
}
+std::unique_ptr<InputFile> LazyObject::getFile() {
+ return createObjectFile(MBRef);
+}
+
// Returns the demangled C++ symbol name for Name.
std::string elf::demangle(StringRef Name) {
#if !defined(HAVE_CXXABI_H)
Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=265710&r1=265709&r2=265710&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Thu Apr 7 14:24:51 2016
@@ -59,7 +59,8 @@ public:
DefinedLast = DefinedSyntheticKind,
UndefinedElfKind,
UndefinedBitcodeKind,
- LazyKind
+ LazyArchiveKind,
+ LazyObjectKind,
};
Kind kind() const { return static_cast<Kind>(SymbolKind); }
@@ -70,7 +71,9 @@ public:
}
bool isDefined() const { return SymbolKind <= DefinedLast; }
bool isCommon() const { return SymbolKind == DefinedCommonKind; }
- bool isLazy() const { return SymbolKind == LazyKind; }
+ bool isLazy() const {
+ return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
+ }
bool isShared() const { return SymbolKind == SharedKind; }
bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
@@ -339,22 +342,51 @@ public:
// the same name, it will ask the Lazy to load a file.
class Lazy : public SymbolBody {
public:
- Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S)
- : SymbolBody(LazyKind, S.getName(), llvm::ELF::STB_GLOBAL,
- llvm::ELF::STV_DEFAULT, /* Type */ 0),
- File(F), Sym(S) {}
+ Lazy(SymbolBody::Kind K, StringRef Name)
+ : SymbolBody(K, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
+ /* Type */ 0) {}
- static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
+ static bool classof(const SymbolBody *S) { return S->isLazy(); }
// Returns an object file for this symbol, or a nullptr if the file
// was already returned.
- std::unique_ptr<InputFile> getMember();
+ std::unique_ptr<InputFile> getFile();
+};
+
+// LazyArchive symbols represents symbols in archive files.
+class LazyArchive : public Lazy {
+public:
+ LazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S)
+ : Lazy(LazyArchiveKind, S.getName()), File(F), Sym(S) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == LazyArchiveKind;
+ }
+
+ std::unique_ptr<InputFile> getFile();
private:
ArchiveFile *File;
const llvm::object::Archive::Symbol Sym;
};
+// LazyObject symbols represents symbols in object files between
+// --start-lib and --end-lib options.
+class LazyObject : public Lazy {
+public:
+ LazyObject(StringRef Name, MemoryBufferRef M)
+ : Lazy(LazyObjectKind, Name), MBRef(M) {}
+
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == LazyObjectKind;
+ }
+
+ std::unique_ptr<InputFile> getFile();
+
+private:
+ MemoryBufferRef MBRef;
+};
+
// Some linker-generated symbols need to be created as
// DefinedRegular symbols.
template <class ELFT> struct ElfSym {
Added: lld/trunk/test/ELF/lto/Inputs/start-lib.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/Inputs/start-lib.ll?rev=265710&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/Inputs/start-lib.ll (added)
+++ lld/trunk/test/ELF/lto/Inputs/start-lib.ll Thu Apr 7 14:24:51 2016
@@ -0,0 +1,6 @@
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_bar() {
+ ret void
+}
Added: lld/trunk/test/ELF/lto/start-lib.ll
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/lto/start-lib.ll?rev=265710&view=auto
==============================================================================
--- lld/trunk/test/ELF/lto/start-lib.ll (added)
+++ lld/trunk/test/ELF/lto/start-lib.ll Thu Apr 7 14:24:51 2016
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+;
+; RUN: llvm-as %s -o %t1.o
+; RUN: llvm-as %p/Inputs/start-lib.ll -o %t2.o
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o %t2.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+; ADDED: Name: _bar
+;
+; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o --start-lib %t2.o
+; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=LIB %s
+; LIB-NOT: Name: _bar
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @_start() {
+ ret void
+}
Added: lld/trunk/test/ELF/start-lib.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/start-lib.s?rev=265710&view=auto
==============================================================================
--- lld/trunk/test/ELF/start-lib.s (added)
+++ lld/trunk/test/ELF/start-lib.s Thu Apr 7 14:24:51 2016
@@ -0,0 +1,16 @@
+// REQUIRES: x86
+
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \
+// RUN: %p/Inputs/whole-archive.s -o %t2.o
+
+// RUN: ld.lld -o %t3 %t1.o %t2.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
+// ADDED: Name: _bar
+
+// RUN: ld.lld -o %t3 %t1.o --start-lib %t2.o
+// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=LIB %s
+// LIB-NOT: Name: _bar
+
+.globl _start
+_start:
More information about the llvm-commits
mailing list