Skip to content

Commit 7dc5e7a

Browse files
committed
reland "[lld-link] implement -start-lib and -end-lib"
Summary: This is a re-land of r370487 with a fix for the use-after-free bug that rev contained. This implements -start-lib and -end-lib flags for lld-link, analogous to the similarly named options in ld.lld. Object files after -start-lib are included in the link only when needed to resolve undefined symbols. The -end-lib flag goes back to the normal behavior of always including object files in the link. This mimics the semantics of static libraries, but without needing to actually create the archive file. Reviewers: ruiu, smeenai, MaskRay Reviewed By: ruiu, MaskRay Subscribers: akhuang, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66848 llvm-svn: 370816
1 parent a0a2ca6 commit 7dc5e7a

15 files changed

+316
-70
lines changed

lld/COFF/DebugTypes.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ void TypeServerSource::enqueue(const ObjFile *dependentFile,
231231
if (!it.second)
232232
return; // another OBJ already scheduled this PDB for load
233233

234-
driver->enqueuePath(*p, false);
234+
driver->enqueuePath(*p, false, false);
235235
}
236236

237237
// Create an instance of TypeServerSource or an error string if the PDB couldn't

lld/COFF/Driver.cpp

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {
170170
}
171171

172172
void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
173-
bool wholeArchive) {
173+
bool wholeArchive, bool lazy) {
174174
StringRef filename = mb->getBufferIdentifier();
175175

176176
MemoryBufferRef mbref = takeBuffer(std::move(mb));
@@ -195,11 +195,17 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
195195
symtab->addFile(make<ArchiveFile>(mbref));
196196
break;
197197
case file_magic::bitcode:
198-
symtab->addFile(make<BitcodeFile>(mbref, "", 0));
198+
if (lazy)
199+
symtab->addFile(make<LazyObjFile>(mbref));
200+
else
201+
symtab->addFile(make<BitcodeFile>(mbref, "", 0));
199202
break;
200203
case file_magic::coff_object:
201204
case file_magic::coff_import_library:
202-
symtab->addFile(make<ObjFile>(mbref));
205+
if (lazy)
206+
symtab->addFile(make<LazyObjFile>(mbref));
207+
else
208+
symtab->addFile(make<ObjFile>(mbref));
203209
break;
204210
case file_magic::pdb:
205211
loadTypeServerSource(mbref);
@@ -220,7 +226,7 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
220226
}
221227
}
222228

223-
void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
229+
void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
224230
auto future =
225231
std::make_shared<std::future<MBErrPair>>(createFutureForFile(path));
226232
std::string pathStr = path;
@@ -240,7 +246,7 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
240246
else
241247
error(msg + "; did you mean '" + nearest + "'");
242248
} else
243-
driver->addBuffer(std::move(mbOrErr.first), wholeArchive);
249+
driver->addBuffer(std::move(mbOrErr.first), wholeArchive, lazy);
244250
});
245251
}
246252

@@ -359,7 +365,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
359365
break;
360366
case OPT_defaultlib:
361367
if (Optional<StringRef> path = findLib(arg->getValue()))
362-
enqueuePath(*path, false);
368+
enqueuePath(*path, false, false);
363369
break;
364370
case OPT_entry:
365371
config->entry = addUndefined(mangle(arg->getValue()));
@@ -1553,19 +1559,45 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
15531559
return false;
15541560
};
15551561

1556-
// Create a list of input files. Files can be given as arguments
1557-
// for /defaultlib option.
1558-
for (auto *arg : args.filtered(OPT_INPUT, OPT_wholearchive_file))
1559-
if (Optional<StringRef> path = findFile(arg->getValue()))
1560-
enqueuePath(*path, isWholeArchive(*path));
1562+
// Create a list of input files. These can be given as OPT_INPUT options
1563+
// and OPT_wholearchive_file options, and we also need to track OPT_start_lib
1564+
// and OPT_end_lib.
1565+
bool inLib = false;
1566+
for (auto *arg : args) {
1567+
switch (arg->getOption().getID()) {
1568+
case OPT_end_lib:
1569+
if (!inLib)
1570+
error("stray " + arg->getSpelling());
1571+
inLib = false;
1572+
break;
1573+
case OPT_start_lib:
1574+
if (inLib)
1575+
error("nested " + arg->getSpelling());
1576+
inLib = true;
1577+
break;
1578+
case OPT_wholearchive_file:
1579+
if (Optional<StringRef> path = findFile(arg->getValue()))
1580+
enqueuePath(*path, true, inLib);
1581+
break;
1582+
case OPT_INPUT:
1583+
if (Optional<StringRef> path = findFile(arg->getValue()))
1584+
enqueuePath(*path, isWholeArchive(*path), inLib);
1585+
break;
1586+
default:
1587+
// Ignore other options.
1588+
break;
1589+
}
1590+
}
15611591

1592+
// Process files specified as /defaultlib. These should be enequeued after
1593+
// other files, which is why they are in a separate loop.
15621594
for (auto *arg : args.filtered(OPT_defaultlib))
15631595
if (Optional<StringRef> path = findLib(arg->getValue()))
1564-
enqueuePath(*path, false);
1596+
enqueuePath(*path, false, false);
15651597

15661598
// Windows specific -- Create a resource file containing a manifest file.
15671599
if (config->manifest == Configuration::Embed)
1568-
addBuffer(createManifestRes(), false);
1600+
addBuffer(createManifestRes(), false, false);
15691601

15701602
// Read all input files given via the command line.
15711603
run();
@@ -1782,7 +1814,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
17821814
if (args.hasArg(OPT_include_optional)) {
17831815
// Handle /includeoptional
17841816
for (auto *arg : args.filtered(OPT_include_optional))
1785-
if (dyn_cast_or_null<Lazy>(symtab->find(arg->getValue())))
1817+
if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))
17861818
addUndefined(arg->getValue());
17871819
while (run());
17881820
}

lld/COFF/Driver.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class LinkerDriver {
7777

7878
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
7979

80-
void enqueuePath(StringRef path, bool wholeArchive);
80+
void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
8181

8282
private:
8383
std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
@@ -124,7 +124,8 @@ class LinkerDriver {
124124
StringRef findDefaultEntry();
125125
WindowsSubsystem inferSubsystem();
126126

127-
void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive);
127+
void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
128+
bool lazy);
128129
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
129130
StringRef parentName, uint64_t offsetInArchive);
130131

lld/COFF/InputFiles.cpp

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f,
7373
}
7474
}
7575

76+
static bool ignoredSymbolName(StringRef name) {
77+
return name == "@feat.00" || name == "@comp.id";
78+
}
79+
7680
ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
7781

7882
void ArchiveFile::parse() {
@@ -81,7 +85,7 @@ void ArchiveFile::parse() {
8185

8286
// Read the symbol table to construct Lazy objects.
8387
for (const Archive::Symbol &sym : file->symbols())
84-
symtab->addLazy(this, sym);
88+
symtab->addLazyArchive(this, sym);
8589
}
8690

8791
// Returns a buffer pointing to a member file containing a given symbol.
@@ -116,6 +120,49 @@ std::vector<MemoryBufferRef> getArchiveMembers(Archive *file) {
116120
return v;
117121
}
118122

123+
void LazyObjFile::fetch() {
124+
if (mb.getBuffer().empty())
125+
return;
126+
127+
InputFile *file;
128+
if (isBitcode(mb))
129+
file = make<BitcodeFile>(mb, "", 0, std::move(symbols));
130+
else
131+
file = make<ObjFile>(mb, std::move(symbols));
132+
mb = {};
133+
symtab->addFile(file);
134+
}
135+
136+
void LazyObjFile::parse() {
137+
if (isBitcode(this->mb)) {
138+
// Bitcode file.
139+
std::unique_ptr<lto::InputFile> obj =
140+
CHECK(lto::InputFile::create(this->mb), this);
141+
for (const lto::InputFile::Symbol &sym : obj->symbols()) {
142+
if (!sym.isUndefined())
143+
symtab->addLazyObject(this, sym.getName());
144+
}
145+
return;
146+
}
147+
148+
// Native object file.
149+
std::unique_ptr<Binary> coffObjPtr = CHECK(createBinary(mb), this);
150+
COFFObjectFile *coffObj = cast<COFFObjectFile>(coffObjPtr.get());
151+
uint32_t numSymbols = coffObj->getNumberOfSymbols();
152+
for (uint32_t i = 0; i < numSymbols; ++i) {
153+
COFFSymbolRef coffSym = check(coffObj->getSymbol(i));
154+
if (coffSym.isUndefined() || !coffSym.isExternal() ||
155+
coffSym.isWeakExternal())
156+
continue;
157+
StringRef name;
158+
coffObj->getSymbolName(coffSym, name);
159+
if (coffSym.isAbsolute() && ignoredSymbolName(name))
160+
continue;
161+
symtab->addLazyObject(this, name);
162+
i += coffSym.getNumberOfAuxSymbols();
163+
}
164+
}
165+
119166
void ObjFile::parse() {
120167
// Parse a memory buffer as a COFF file.
121168
std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this);
@@ -526,13 +573,11 @@ Optional<Symbol *> ObjFile::createDefined(
526573
if (sym.isAbsolute()) {
527574
StringRef name = getName();
528575

529-
// Skip special symbols.
530-
if (name == "@comp.id")
531-
return nullptr;
532-
if (name == "@feat.00") {
576+
if (name == "@feat.00")
533577
feat00Flags = sym.getValue();
578+
// Skip special symbols.
579+
if (ignoredSymbolName(name))
534580
return nullptr;
535-
}
536581

537582
if (sym.isExternal())
538583
return symtab->addAbsolute(name, sym);
@@ -782,8 +827,9 @@ void ImportFile::parse() {
782827
}
783828

784829
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
785-
uint64_t offsetInArchive)
786-
: InputFile(BitcodeKind, mb) {
830+
uint64_t offsetInArchive,
831+
std::vector<Symbol *> &&symbols)
832+
: InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {
787833
std::string path = mb.getBufferIdentifier().str();
788834
if (config->thinLTOIndexOnly)
789835
path = replaceThinLTOSuffix(mb.getBufferIdentifier());

lld/COFF/InputFiles.h

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "llvm/ADT/ArrayRef.h"
1515
#include "llvm/ADT/DenseMap.h"
1616
#include "llvm/ADT/DenseSet.h"
17+
#include "llvm/BinaryFormat/Magic.h"
1718
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
1819
#include "llvm/LTO/LTO.h"
1920
#include "llvm/Object/Archive.h"
@@ -55,7 +56,13 @@ class TpiSource;
5556
// The root class of input files.
5657
class InputFile {
5758
public:
58-
enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
59+
enum Kind {
60+
ArchiveKind,
61+
ObjectKind,
62+
LazyObjectKind,
63+
ImportKind,
64+
BitcodeKind
65+
};
5966
Kind kind() const { return fileKind; }
6067
virtual ~InputFile() {}
6168

@@ -102,10 +109,28 @@ class ArchiveFile : public InputFile {
102109
llvm::DenseSet<uint64_t> seen;
103110
};
104111

112+
// .obj or .o file between -start-lib and -end-lib.
113+
class LazyObjFile : public InputFile {
114+
public:
115+
explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}
116+
static bool classof(const InputFile *f) {
117+
return f->kind() == LazyObjectKind;
118+
}
119+
// Makes this object file part of the link.
120+
void fetch();
121+
// Adds the symbols in this file to the symbol table as LazyObject symbols.
122+
void parse() override;
123+
124+
private:
125+
std::vector<Symbol *> symbols;
126+
};
127+
105128
// .obj or .o file. This may be a member of an archive file.
106129
class ObjFile : public InputFile {
107130
public:
108131
explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
132+
explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)
133+
: InputFile(ObjectKind, m), symbols(std::move(symbols)) {}
109134
static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
110135
void parse() override;
111136
MachineTypes getMachineType() override;
@@ -301,7 +326,11 @@ class ImportFile : public InputFile {
301326
class BitcodeFile : public InputFile {
302327
public:
303328
BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
304-
uint64_t offsetInArchive);
329+
uint64_t offsetInArchive)
330+
: BitcodeFile(mb, archiveName, offsetInArchive, {}) {}
331+
explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,
332+
uint64_t offsetInArchive,
333+
std::vector<Symbol *> &&symbols);
305334
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
306335
ArrayRef<Symbol *> getSymbols() { return symbols; }
307336
MachineTypes getMachineType() override;
@@ -314,6 +343,10 @@ class BitcodeFile : public InputFile {
314343
std::vector<Symbol *> symbols;
315344
};
316345

346+
inline bool isBitcode(MemoryBufferRef mb) {
347+
return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
348+
}
349+
317350
std::string replaceThinLTOSuffix(StringRef path);
318351
} // namespace coff
319352

lld/COFF/Options.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,8 @@ def help : F<"help">;
162162
def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias<help>;
163163

164164
// LLD extensions
165+
def end_lib : F<"end-lib">,
166+
HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
165167
def exclude_all_symbols : F<"exclude-all-symbols">;
166168
def export_all_symbols : F<"export-all-symbols">;
167169
defm demangle : B<"demangle",
@@ -176,6 +178,8 @@ def pdb_source_path : P<"pdbsourcepath",
176178
"Base path used to make relative source file path absolute in PDB">;
177179
def rsp_quoting : Joined<["--"], "rsp-quoting=">,
178180
HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;
181+
def start_lib : F<"start-lib">,
182+
HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
179183
def thinlto_emit_imports_files :
180184
F<"thinlto-emit-imports-files">,
181185
HelpText<"Emit .imports files with -thinlto-index-only">;

0 commit comments

Comments
 (0)