Skip to content

Commit f8baa66

Browse files
committedApr 7, 2016
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 llvm-svn: 265710
1 parent 43b7b5b commit f8baa66

13 files changed

+231
-19
lines changed
 

‎lld/ELF/Driver.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,10 @@ void LinkerDriver::addFile(StringRef Path) {
129129
Files.push_back(createSharedFile(MBRef));
130130
return;
131131
default:
132-
Files.push_back(createObjectFile(MBRef));
132+
if (InLib)
133+
Files.push_back(make_unique<LazyObjectFile>(MBRef));
134+
else
135+
Files.push_back(createObjectFile(MBRef));
133136
}
134137
}
135138

@@ -359,6 +362,12 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) {
359362
case OPT_no_whole_archive:
360363
WholeArchive = false;
361364
break;
365+
case OPT_start_lib:
366+
InLib = true;
367+
break;
368+
case OPT_end_lib:
369+
InLib = false;
370+
break;
362371
}
363372
}
364373

‎lld/ELF/Driver.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,13 @@ class LinkerDriver {
3333
void createFiles(llvm::opt::InputArgList &Args);
3434
template <class ELFT> void link(llvm::opt::InputArgList &Args);
3535

36-
llvm::BumpPtrAllocator Alloc;
36+
// True if we are in --whole-archive and --no-whole-archive.
3737
bool WholeArchive = false;
38+
39+
// True if we are in --start-lib and --end-lib.
40+
bool InLib = false;
41+
42+
llvm::BumpPtrAllocator Alloc;
3843
std::vector<std::unique_ptr<InputFile>> Files;
3944
std::vector<std::unique_ptr<MemoryBuffer>> OwningMBs;
4045
};

‎lld/ELF/InputFiles.cpp

+60
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,66 @@ std::unique_ptr<InputFile> elf::createSharedFile(MemoryBufferRef MB) {
564564
return createELFFile<SharedFile>(MB);
565565
}
566566

567+
void LazyObjectFile::parse() {
568+
for (StringRef Sym : getSymbols())
569+
LazySymbols.emplace_back(Sym, this->MB);
570+
}
571+
572+
template <class ELFT> std::vector<StringRef> LazyObjectFile::getElfSymbols() {
573+
typedef typename ELFT::Shdr Elf_Shdr;
574+
typedef typename ELFT::Sym Elf_Sym;
575+
typedef typename ELFT::SymRange Elf_Sym_Range;
576+
577+
const ELFFile<ELFT> Obj = createELFObj<ELFT>(this->MB);
578+
for (const Elf_Shdr &Sec : Obj.sections()) {
579+
if (Sec.sh_type != SHT_SYMTAB)
580+
continue;
581+
Elf_Sym_Range Syms = Obj.symbols(&Sec);
582+
uint32_t FirstNonLocal = Sec.sh_info;
583+
StringRef StringTable = check(Obj.getStringTableForSymtab(Sec));
584+
std::vector<StringRef> V;
585+
for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal))
586+
V.push_back(check(Sym.getName(StringTable)));
587+
return V;
588+
}
589+
return {};
590+
}
591+
592+
std::vector<StringRef> LazyObjectFile::getBitcodeSymbols() {
593+
LLVMContext Context;
594+
std::unique_ptr<IRObjectFile> Obj =
595+
check(IRObjectFile::create(this->MB, Context));
596+
std::vector<StringRef> V;
597+
for (const BasicSymbolRef &Sym : Obj->symbols()) {
598+
if (BitcodeFile::shouldSkip(Sym))
599+
continue;
600+
SmallString<64> Name;
601+
raw_svector_ostream OS(Name);
602+
Sym.printName(OS);
603+
V.push_back(Saver.save(StringRef(Name)));
604+
}
605+
return V;
606+
}
607+
608+
// Returns a vector of globally-visible symbol names.
609+
std::vector<StringRef> LazyObjectFile::getSymbols() {
610+
using namespace sys::fs;
611+
612+
StringRef Buf = this->MB.getBuffer();
613+
if (identify_magic(Buf) == file_magic::bitcode)
614+
return getBitcodeSymbols();
615+
616+
std::pair<unsigned char, unsigned char> Type = getElfArchType(Buf);
617+
if (Type.first == ELF::ELFCLASS32) {
618+
if (Type.second == ELF::ELFDATA2LSB)
619+
return getElfSymbols<ELF32LE>();
620+
return getElfSymbols<ELF32BE>();
621+
}
622+
if (Type.second == ELF::ELFDATA2LSB)
623+
return getElfSymbols<ELF64LE>();
624+
return getElfSymbols<ELF64BE>();
625+
}
626+
567627
template class elf::ELFFileBase<ELF32LE>;
568628
template class elf::ELFFileBase<ELF32BE>;
569629
template class elf::ELFFileBase<ELF64LE>;

‎lld/ELF/InputFiles.h

+40-3
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,14 @@ class SymbolBody;
3636
// The root class of input files.
3737
class InputFile {
3838
public:
39-
enum Kind { ObjectKind, SharedKind, ArchiveKind, BitcodeKind };
39+
enum Kind {
40+
ObjectKind,
41+
SharedKind,
42+
LazyObjectKind,
43+
ArchiveKind,
44+
BitcodeKind,
45+
};
46+
4047
Kind kind() const { return FileKind; }
4148

4249
StringRef getName() const { return MB.getBufferIdentifier(); }
@@ -154,6 +161,36 @@ template <class ELFT> class ObjectFile : public ELFFileBase<ELFT> {
154161
llvm::SpecificBumpPtrAllocator<EHInputSection<ELFT>> EHAlloc;
155162
};
156163

164+
// LazyObjectFile is analogous to ArchiveFile in the sense that
165+
// the file contains lazy symbols. The difference is that
166+
// LazyObjectFile wraps a single file instead of multiple files.
167+
//
168+
// This class is used for --start-lib and --end-lib options which
169+
// instruct the linker to link object files between them with the
170+
// archive file semantics.
171+
class LazyObjectFile : public InputFile {
172+
public:
173+
explicit LazyObjectFile(MemoryBufferRef M) : InputFile(LazyObjectKind, M) {}
174+
175+
static bool classof(const InputFile *F) {
176+
return F->kind() == LazyObjectKind;
177+
}
178+
179+
void parse();
180+
181+
llvm::MutableArrayRef<LazyObject> getLazySymbols() { return LazySymbols; }
182+
183+
private:
184+
std::vector<StringRef> getSymbols();
185+
template <class ELFT> std::vector<StringRef> getElfSymbols();
186+
std::vector<StringRef> getBitcodeSymbols();
187+
188+
llvm::BumpPtrAllocator Alloc;
189+
llvm::StringSaver Saver{Alloc};
190+
std::vector<LazyObject> LazySymbols;
191+
};
192+
193+
// An ArchiveFile object represents a .a file.
157194
class ArchiveFile : public InputFile {
158195
public:
159196
explicit ArchiveFile(MemoryBufferRef M) : InputFile(ArchiveKind, M) {}
@@ -165,11 +202,11 @@ class ArchiveFile : public InputFile {
165202
// (So that we don't instantiate same members more than once.)
166203
MemoryBufferRef getMember(const Archive::Symbol *Sym);
167204

168-
llvm::MutableArrayRef<Lazy> getLazySymbols() { return LazySymbols; }
205+
llvm::MutableArrayRef<LazyArchive> getLazySymbols() { return LazySymbols; }
169206

170207
private:
171208
std::unique_ptr<Archive> File;
172-
std::vector<Lazy> LazySymbols;
209+
std::vector<LazyArchive> LazySymbols;
173210
llvm::DenseSet<uint64_t> Seen;
174211
};
175212

‎lld/ELF/Options.td

+6
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ def eh_frame_hdr : Flag<["--"], "eh-frame-hdr">,
4848
def enable_new_dtags : Flag<["--"], "enable-new-dtags">,
4949
HelpText<"Enable new dynamic tags">;
5050

51+
def end_lib : Flag<["--"], "end-lib">,
52+
HelpText<"End a library">;
53+
5154
def entry : Separate<["--", "-"], "entry">, MetaVarName<"<entry>">,
5255
HelpText<"Name of entry point symbol">;
5356

@@ -121,6 +124,9 @@ def shared : Flag<["-"], "shared">,
121124
def soname : Joined<["-"], "soname=">,
122125
HelpText<"Set DT_SONAME">;
123126

127+
def start_lib : Flag<["--"], "start-lib">,
128+
HelpText<"Start a library">;
129+
124130
def strip_all : Flag<["--"], "strip-all">,
125131
HelpText<"Strip all symbols">;
126132

‎lld/ELF/OutputSections.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1501,7 +1501,8 @@ SymbolTableSection<ELFT>::getOutputSection(SymbolBody *Sym) {
15011501
break;
15021502
case SymbolBody::UndefinedElfKind:
15031503
case SymbolBody::UndefinedBitcodeKind:
1504-
case SymbolBody::LazyKind:
1504+
case SymbolBody::LazyArchiveKind:
1505+
case SymbolBody::LazyObjectKind:
15051506
break;
15061507
case SymbolBody::DefinedBitcodeKind:
15071508
llvm_unreachable("should have been replaced");

‎lld/ELF/SymbolTable.cpp

+12-3
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
7575
return;
7676
}
7777

78-
// LLVM bitcode file.
78+
// LLVM bitcode file
7979
if (auto *F = dyn_cast<BitcodeFile>(FileP)) {
8080
BitcodeFiles.emplace_back(cast<BitcodeFile>(File.release()));
8181
F->parse(ComdatGroups);
@@ -85,7 +85,16 @@ void SymbolTable<ELFT>::addFile(std::unique_ptr<InputFile> File) {
8585
return;
8686
}
8787

88-
// .o file
88+
// Lazy object file
89+
if (auto *F = dyn_cast<LazyObjectFile>(FileP)) {
90+
LazyObjectFiles.emplace_back(cast<LazyObjectFile>(File.release()));
91+
F->parse();
92+
for (Lazy &Sym : F->getLazySymbols())
93+
addLazy(&Sym);
94+
return;
95+
}
96+
97+
// Regular object file
8998
auto *F = cast<ObjectFile<ELFT>>(FileP);
9099
ObjectFiles.emplace_back(cast<ObjectFile<ELFT>>(File.release()));
91100
F->parse(ComdatGroups);
@@ -306,7 +315,7 @@ void SymbolTable<ELFT>::addMemberFile(SymbolBody *Undef, Lazy *L) {
306315

307316
// Fetch a member file that has the definition for L.
308317
// getMember returns nullptr if the member was already read from the library.
309-
if (std::unique_ptr<InputFile> File = L->getMember())
318+
if (std::unique_ptr<InputFile> File = L->getFile())
310319
addFile(std::move(File));
311320
}
312321

‎lld/ELF/SymbolTable.h

+1
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ template <class ELFT> class SymbolTable {
8989
// The symbol table owns all file objects.
9090
std::vector<std::unique_ptr<ArchiveFile>> ArchiveFiles;
9191
std::vector<std::unique_ptr<ObjectFile<ELFT>>> ObjectFiles;
92+
std::vector<std::unique_ptr<LazyObjectFile>> LazyObjectFiles;
9293
std::vector<std::unique_ptr<SharedFile<ELFT>>> SharedFiles;
9394
std::vector<std::unique_ptr<BitcodeFile>> BitcodeFiles;
9495

‎lld/ELF/Symbols.cpp

+13-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ static typename ELFT::uint getSymVA(const SymbolBody &Body,
7878
case SymbolBody::UndefinedElfKind:
7979
case SymbolBody::UndefinedBitcodeKind:
8080
return 0;
81-
case SymbolBody::LazyKind:
81+
case SymbolBody::LazyArchiveKind:
82+
case SymbolBody::LazyObjectKind:
8283
assert(Body.isUsedInRegularObj() && "lazy symbol reached writer");
8384
return 0;
8485
case SymbolBody::DefinedBitcodeKind:
@@ -301,7 +302,13 @@ DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment,
301302
: Defined(SymbolBody::DefinedCommonKind, N, Binding, StOther, Type),
302303
Alignment(Alignment), Size(Size) {}
303304

304-
std::unique_ptr<InputFile> Lazy::getMember() {
305+
std::unique_ptr<InputFile> Lazy::getFile() {
306+
if (auto *S = dyn_cast<LazyArchive>(this))
307+
return S->getFile();
308+
return cast<LazyObject>(this)->getFile();
309+
}
310+
311+
std::unique_ptr<InputFile> LazyArchive::getFile() {
305312
MemoryBufferRef MBRef = File->getMember(&Sym);
306313

307314
// getMember returns an empty buffer if the member was already
@@ -311,6 +318,10 @@ std::unique_ptr<InputFile> Lazy::getMember() {
311318
return createObjectFile(MBRef, File->getName());
312319
}
313320

321+
std::unique_ptr<InputFile> LazyObject::getFile() {
322+
return createObjectFile(MBRef);
323+
}
324+
314325
// Returns the demangled C++ symbol name for Name.
315326
std::string elf::demangle(StringRef Name) {
316327
#if !defined(HAVE_CXXABI_H)

‎lld/ELF/Symbols.h

+40-8
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,8 @@ class SymbolBody {
5959
DefinedLast = DefinedSyntheticKind,
6060
UndefinedElfKind,
6161
UndefinedBitcodeKind,
62-
LazyKind
62+
LazyArchiveKind,
63+
LazyObjectKind,
6364
};
6465

6566
Kind kind() const { return static_cast<Kind>(SymbolKind); }
@@ -70,7 +71,9 @@ class SymbolBody {
7071
}
7172
bool isDefined() const { return SymbolKind <= DefinedLast; }
7273
bool isCommon() const { return SymbolKind == DefinedCommonKind; }
73-
bool isLazy() const { return SymbolKind == LazyKind; }
74+
bool isLazy() const {
75+
return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind;
76+
}
7477
bool isShared() const { return SymbolKind == SharedKind; }
7578
bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
7679
bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
@@ -339,22 +342,51 @@ template <class ELFT> class SharedSymbol : public Defined {
339342
// the same name, it will ask the Lazy to load a file.
340343
class Lazy : public SymbolBody {
341344
public:
342-
Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S)
343-
: SymbolBody(LazyKind, S.getName(), llvm::ELF::STB_GLOBAL,
344-
llvm::ELF::STV_DEFAULT, /* Type */ 0),
345-
File(F), Sym(S) {}
345+
Lazy(SymbolBody::Kind K, StringRef Name)
346+
: SymbolBody(K, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT,
347+
/* Type */ 0) {}
346348

347-
static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
349+
static bool classof(const SymbolBody *S) { return S->isLazy(); }
348350

349351
// Returns an object file for this symbol, or a nullptr if the file
350352
// was already returned.
351-
std::unique_ptr<InputFile> getMember();
353+
std::unique_ptr<InputFile> getFile();
354+
};
355+
356+
// LazyArchive symbols represents symbols in archive files.
357+
class LazyArchive : public Lazy {
358+
public:
359+
LazyArchive(ArchiveFile *F, const llvm::object::Archive::Symbol S)
360+
: Lazy(LazyArchiveKind, S.getName()), File(F), Sym(S) {}
361+
362+
static bool classof(const SymbolBody *S) {
363+
return S->kind() == LazyArchiveKind;
364+
}
365+
366+
std::unique_ptr<InputFile> getFile();
352367

353368
private:
354369
ArchiveFile *File;
355370
const llvm::object::Archive::Symbol Sym;
356371
};
357372

373+
// LazyObject symbols represents symbols in object files between
374+
// --start-lib and --end-lib options.
375+
class LazyObject : public Lazy {
376+
public:
377+
LazyObject(StringRef Name, MemoryBufferRef M)
378+
: Lazy(LazyObjectKind, Name), MBRef(M) {}
379+
380+
static bool classof(const SymbolBody *S) {
381+
return S->kind() == LazyObjectKind;
382+
}
383+
384+
std::unique_ptr<InputFile> getFile();
385+
386+
private:
387+
MemoryBufferRef MBRef;
388+
};
389+
358390
// Some linker-generated symbols need to be created as
359391
// DefinedRegular symbols.
360392
template <class ELFT> struct ElfSym {

‎lld/test/ELF/lto/Inputs/start-lib.ll

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
2+
target triple = "x86_64-unknown-linux-gnu"
3+
4+
define void @_bar() {
5+
ret void
6+
}

‎lld/test/ELF/lto/start-lib.ll

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
; REQUIRES: x86
2+
;
3+
; RUN: llvm-as %s -o %t1.o
4+
; RUN: llvm-as %p/Inputs/start-lib.ll -o %t2.o
5+
;
6+
; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o %t2.o
7+
; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=ADDED %s
8+
; ADDED: Name: _bar
9+
;
10+
; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o --start-lib %t2.o
11+
; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=LIB %s
12+
; LIB-NOT: Name: _bar
13+
14+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
15+
target triple = "x86_64-unknown-linux-gnu"
16+
17+
define void @_start() {
18+
ret void
19+
}

0 commit comments

Comments
 (0)
Please sign in to comment.