Skip to content

Commit c541eee

Browse files
committed
[LLD][COFF] Handle --start-lib/--end-lib group in the same way as other archives
1 parent eb68b91 commit c541eee

File tree

5 files changed

+144
-88
lines changed

5 files changed

+144
-88
lines changed

lld/COFF/Driver.cpp

Lines changed: 60 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -200,28 +200,13 @@ static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) {
200200
}
201201
}
202202

203-
void LinkerDriver::addFile(InputFile *file) {
204-
Log(ctx) << "Reading " << toString(file);
205-
if (file->lazy) {
206-
if (auto *f = dyn_cast<BitcodeFile>(file))
207-
f->parseLazy();
208-
else
209-
cast<ObjFile>(file)->parseLazy();
210-
} else {
211-
file->parse();
212-
if (auto *f = dyn_cast<ObjFile>(file)) {
213-
ctx.objFileInstances.push_back(f);
214-
} else if (auto *f = dyn_cast<BitcodeFile>(file)) {
215-
if (ltoCompilationDone) {
216-
Err(ctx) << "LTO object file " << toString(file)
217-
<< " linked in after "
218-
"doing LTO compilation.";
219-
}
220-
f->symtab.bitcodeFileInstances.push_back(f);
221-
} else if (auto *f = dyn_cast<ImportFile>(file)) {
222-
ctx.importFileInstances.push_back(f);
223-
}
203+
void LinkerDriver::addFile(InputFile *file, CmdLineArchive *inCmdLineArchive) {
204+
if (inCmdLineArchive) {
205+
inCmdLineArchive->addInputFile(file); // schedule for lazy parsing
206+
return;
224207
}
208+
Log(ctx) << "Reading " << toString(file);
209+
file->maybeParse();
225210

226211
MachineTypes mt = file->getMachineType();
227212
// The ARM64EC target must be explicitly specified and cannot be inferred.
@@ -259,17 +244,24 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {
259244
}
260245

261246
void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
262-
bool wholeArchive, bool lazy) {
247+
bool wholeArchive,
248+
CmdLineArchive *inCmdLineArchive) {
263249
StringRef filename = mb->getBufferIdentifier();
264250

265251
MemoryBufferRef mbref = takeBuffer(std::move(mb));
266252

267253
// File type is detected by contents, not by file extension.
268254
switch (identify_magic(mbref.getBuffer())) {
269255
case file_magic::windows_resource:
256+
assert(!inCmdLineArchive &&
257+
"Cannot specify a RES file inside a --start-lib/--end-lib group.");
270258
resources.push_back(mbref);
271259
break;
272260
case file_magic::archive:
261+
// FIXME: We could later support --start-lib/--end-lib groups, to allow for
262+
// "extending" an existing archive/LIB.
263+
assert(!inCmdLineArchive &&
264+
"Cannot specify a LIB file inside a --start-lib/--end-lib group.");
273265
if (wholeArchive) {
274266
std::unique_ptr<Archive> file =
275267
CHECK(Archive::create(mbref), filename + ": failed to parse archive");
@@ -284,13 +276,15 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
284276
addFile(make<ArchiveFile>(ctx, mbref));
285277
break;
286278
case file_magic::bitcode:
287-
addFile(BitcodeFile::create(ctx, mbref, "", 0, lazy));
279+
addFile(BitcodeFile::create(ctx, mbref, "", 0), inCmdLineArchive);
288280
break;
289281
case file_magic::coff_object:
290282
case file_magic::coff_import_library:
291-
addFile(ObjFile::create(ctx, mbref, lazy));
283+
addFile(ObjFile::create(ctx, mbref), inCmdLineArchive);
292284
break;
293285
case file_magic::pdb:
286+
assert(!inCmdLineArchive &&
287+
"Cannot specify a PDB file inside a --start-lib/--end-lib group.");
294288
addFile(make<PDBInputFile>(ctx, mbref));
295289
break;
296290
case file_magic::coff_cl_gl_object:
@@ -299,6 +293,9 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
299293
break;
300294
case file_magic::pecoff_executable:
301295
if (ctx.config.mingw) {
296+
assert(
297+
!inCmdLineArchive &&
298+
"Cannot specify a PE/EXE file inside a --start-lib/--end-lib group.");
302299
addFile(make<DLLFile>(ctx.symtab, mbref));
303300
break;
304301
}
@@ -315,7 +312,9 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
315312
}
316313
}
317314

318-
void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
315+
void LinkerDriver::enqueuePath(
316+
StringRef path, bool wholeArchive,
317+
std::optional<std::shared_future<CmdLineArchive *>> inCmdLineArchive) {
319318
auto future = std::make_shared<std::future<MBErrPair>>(
320319
createFutureForFile(std::string(path)));
321320
std::string pathStr = std::string(path);
@@ -354,7 +353,9 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
354353
else
355354
Err(ctx) << msg << "; did you mean '" << nearest << "'";
356355
} else
357-
ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy);
356+
ctx.driver.addBuffer(std::move(mb), wholeArchive,
357+
inCmdLineArchive ? inCmdLineArchive->get()
358+
: nullptr);
358359
});
359360
}
360361

@@ -373,8 +374,7 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
373374
if (magic == file_magic::coff_object) {
374375
obj = ObjFile::create(ctx, mb);
375376
} else if (magic == file_magic::bitcode) {
376-
obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive,
377-
/*lazy=*/false);
377+
obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive);
378378
} else if (magic == file_magic::coff_cl_gl_object) {
379379
Err(ctx) << mb.getBufferIdentifier()
380380
<< ": is not a native COFF file. Recompile without /GL?";
@@ -494,7 +494,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
494494
break;
495495
case OPT_defaultlib:
496496
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
497-
enqueuePath(*path, false, false);
497+
enqueuePath(*path);
498498
break;
499499
case OPT_entry:
500500
if (!arg->getValue()[0])
@@ -2177,32 +2177,50 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
21772177
// and OPT_end_lib.
21782178
{
21792179
llvm::TimeTraceScope timeScope2("Parse & queue inputs");
2180-
bool inLib = false;
2180+
std::optional<std::shared_future<CmdLineArchive *>> inCmdLineArchive;
21812181
for (auto *arg : args) {
21822182
switch (arg->getOption().getID()) {
21832183
case OPT_end_lib:
2184-
if (!inLib)
2184+
if (!inCmdLineArchive) {
21852185
Err(ctx) << "stray " << arg->getSpelling();
2186-
inLib = false;
2186+
} else {
2187+
enqueueTask([=]() { inCmdLineArchive->get()->maybeParse(); });
2188+
inCmdLineArchive = std::nullopt;
2189+
}
21872190
break;
21882191
case OPT_start_lib:
2189-
if (inLib)
2192+
if (inCmdLineArchive) {
21902193
Err(ctx) << "nested " << arg->getSpelling();
2191-
inLib = true;
2194+
} else {
2195+
auto a = std::make_shared<std::promise<CmdLineArchive *>>();
2196+
inCmdLineArchive = a->get_future().share();
2197+
enqueueTask([&, a]() {
2198+
// In is important to create a fake archive here so that we
2199+
// remember its placement on the command-line. This will be
2200+
// later needed to resolve symbols in the archive order required
2201+
// by the MSVC specification.
2202+
a->set_value(make<CmdLineArchive>(
2203+
ctx.symtab, MemoryBufferRef({}, "<cmdline-lib>")));
2204+
});
2205+
}
21922206
break;
21932207
case OPT_wholearchive_file:
21942208
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
2195-
enqueuePath(*path, true, inLib);
2209+
enqueuePath(*path, true, inCmdLineArchive);
21962210
break;
21972211
case OPT_INPUT:
21982212
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
2199-
enqueuePath(*path, isWholeArchive(*path), inLib);
2213+
enqueuePath(*path, isWholeArchive(*path), inCmdLineArchive);
22002214
break;
22012215
default:
22022216
// Ignore other options.
22032217
break;
22042218
}
22052219
}
2220+
if (inCmdLineArchive) {
2221+
Warn(ctx) << "--start-lib with no --end-lib";
2222+
enqueueTask([=]() { inCmdLineArchive->get()->maybeParse(); });
2223+
}
22062224
}
22072225

22082226
// Read all input files given via the command line.
@@ -2236,7 +2254,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
22362254
// addWinSysRootLibSearchPaths(), which is why they are in a separate loop.
22372255
for (auto *arg : args.filtered(OPT_defaultlib))
22382256
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
2239-
enqueuePath(*path, false, false);
2257+
enqueuePath(*path);
22402258
run();
22412259
if (errorCount())
22422260
return;
@@ -2553,9 +2571,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
25532571

25542572
if (args.hasArg(OPT_include_optional)) {
25552573
// Handle /includeoptional
2556-
for (auto *arg : args.filtered(OPT_include_optional))
2557-
if (isa_and_nonnull<LazyArchive>(symtab.find(arg->getValue())))
2574+
for (auto *arg : args.filtered(OPT_include_optional)) {
2575+
Symbol *sym = ctx.symtab.find(arg->getValue());
2576+
if (sym && (isa<LazyArchive>(sym) || isa<LazyObject>(sym)))
25582577
symtab.addGCRoot(arg->getValue());
2578+
}
25592579
}
25602580
});
25612581
} while (run());
@@ -2720,7 +2740,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
27202740
// /manifestdependency: enables /manifest unless an explicit /manifest:no is
27212741
// also passed.
27222742
if (config->manifest == Configuration::Embed)
2723-
addBuffer(createManifestRes(), false, false);
2743+
addBuffer(createManifestRes(), false);
27242744
else if (config->manifest == Configuration::SideBySide ||
27252745
(config->manifest == Configuration::Default &&
27262746
!config->manifestDependencies.empty()))

lld/COFF/Driver.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "llvm/Support/FileSystem.h"
2323
#include "llvm/Support/TarWriter.h"
2424
#include "llvm/WindowsDriver/MSVCPaths.h"
25+
#include <future>
2526
#include <memory>
2627
#include <optional>
2728
#include <set>
@@ -80,26 +81,31 @@ class LinkerDriver {
8081

8182
void linkerMain(llvm::ArrayRef<const char *> args);
8283

83-
void addFile(InputFile *file);
84+
void addFile(InputFile *file, CmdLineArchive *inCmdLineArchive = nullptr);
8485

8586
void addClangLibSearchPaths(const std::string &argv0);
8687

8788
// Used by ArchiveFile to enqueue members.
8889
void enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym,
8990
StringRef parentName);
9091

91-
void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false); }
92+
void enqueuePDB(StringRef Path) { enqueuePath(Path); }
9293

9394
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
9495

95-
void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
96+
// Schedule a input file for reading.
97+
void enqueuePath(StringRef path, bool wholeArchive = false,
98+
std::optional<std::shared_future<CmdLineArchive *>>
99+
inCmdLineArchive = std::nullopt);
100+
101+
void pullArm64ECIcallHelper();
96102

97103
// Returns a list of chunks of selected symbols.
98104
std::vector<Chunk *> getChunks() const;
99105

100106
std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
101107

102-
void pullArm64ECIcallHelper();
108+
bool ltoCompilationDone = false;
103109

104110
private:
105111
// Searches a file from search paths.
@@ -170,7 +176,7 @@ class LinkerDriver {
170176
std::set<std::string> visitedLibs;
171177

172178
void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
173-
bool lazy);
179+
CmdLineArchive *inCmdLineArchive = nullptr);
174180
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
175181
StringRef parentName, uint64_t offsetInArchive);
176182

@@ -258,8 +264,6 @@ class LinkerDriver {
258264
// Create export thunks for exported and patchable Arm64EC function symbols.
259265
void createECExportThunks();
260266
void maybeCreateECExportThunk(StringRef name, Symbol *&sym);
261-
262-
bool ltoCompilationDone = false;
263267
};
264268

265269
// Create enum with OPT_xxx values for each option in Options.td

lld/COFF/InputFiles.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,19 @@ lld::coff::getArchiveMembers(COFFLinkerContext &ctx, Archive *file) {
226226
return v;
227227
}
228228

229-
ObjFile::ObjFile(SymbolTable &symtab, COFFObjectFile *coffObj, bool lazy)
230-
: InputFile(symtab, ObjectKind, coffObj->getMemoryBufferRef(), lazy),
229+
void CmdLineArchive::parse() {
230+
for (InputFile *f : files) {
231+
if (auto *o = dyn_cast<ObjFile>(f))
232+
o->parseLazy();
233+
else if (auto *b = dyn_cast<BitcodeFile>(f))
234+
b->parseLazy();
235+
}
236+
}
237+
238+
void CmdLineArchive::addInputFile(InputFile *f) { files.push_back(f); }
239+
240+
ObjFile::ObjFile(SymbolTable &symtab, COFFObjectFile *coffObj)
241+
: InputFile(symtab, ObjectKind, coffObj->getMemoryBufferRef()),
231242
coffObj(coffObj) {}
232243

233244
ObjFile *ObjFile::create(COFFLinkerContext &ctx, MemoryBufferRef m, bool lazy) {
@@ -241,8 +252,7 @@ ObjFile *ObjFile::create(COFFLinkerContext &ctx, MemoryBufferRef m, bool lazy) {
241252
Fatal(ctx) << m.getBufferIdentifier() << " is not a COFF file";
242253

243254
bin->release();
244-
return make<ObjFile>(ctx.getSymtab(MachineTypes(obj->getMachine())), obj,
245-
lazy);
255+
return make<ObjFile>(ctx.getSymtab(MachineTypes(obj->getMachine())), obj);
246256
}
247257

248258
void ObjFile::parseLazy() {
@@ -257,8 +267,6 @@ void ObjFile::parseLazy() {
257267
if (coffSym.isAbsolute() && ignoredSymbolName(name))
258268
continue;
259269
symtab.addLazyObject(this, name);
260-
if (!lazy)
261-
return;
262270
i += coffSym.getNumberOfAuxSymbols();
263271
}
264272
}
@@ -299,6 +307,8 @@ void ObjFile::initializeECThunks() {
299307
}
300308

301309
void ObjFile::parse() {
310+
symtab.ctx.objFileInstances.push_back(this);
311+
302312
// Read section and symbol tables.
303313
initializeChunks();
304314
initializeSymbols();
@@ -1201,6 +1211,8 @@ ImportThunkChunk *ImportFile::makeImportThunk() {
12011211
}
12021212

12031213
void ImportFile::parse() {
1214+
symtab.ctx.importFileInstances.push_back(this);
1215+
12041216
const auto *hdr =
12051217
reinterpret_cast<const coff_import_header *>(mb.getBufferStart());
12061218

@@ -1307,14 +1319,14 @@ void ImportFile::parse() {
13071319
}
13081320

13091321
BitcodeFile::BitcodeFile(SymbolTable &symtab, MemoryBufferRef mb,
1310-
std::unique_ptr<lto::InputFile> &o, bool lazy)
1311-
: InputFile(symtab, BitcodeKind, mb, lazy) {
1322+
std::unique_ptr<lto::InputFile> &o)
1323+
: InputFile(symtab, BitcodeKind, mb) {
13121324
obj.swap(o);
13131325
}
13141326

13151327
BitcodeFile *BitcodeFile::create(COFFLinkerContext &ctx, MemoryBufferRef mb,
13161328
StringRef archiveName,
1317-
uint64_t offsetInArchive, bool lazy) {
1329+
uint64_t offsetInArchive) {
13181330
std::string path = mb.getBufferIdentifier().str();
13191331
if (ctx.config.thinLTOIndexOnly)
13201332
path = replaceThinLTOSuffix(mb.getBufferIdentifier(),
@@ -1335,13 +1347,18 @@ BitcodeFile *BitcodeFile::create(COFFLinkerContext &ctx, MemoryBufferRef mb,
13351347
utostr(offsetInArchive)));
13361348

13371349
std::unique_ptr<lto::InputFile> obj = check(lto::InputFile::create(mbref));
1338-
return make<BitcodeFile>(ctx.getSymtab(getMachineType(obj.get())), mb, obj,
1339-
lazy);
1350+
return make<BitcodeFile>(ctx.getSymtab(getMachineType(obj.get())), mb, obj);
13401351
}
13411352

13421353
BitcodeFile::~BitcodeFile() = default;
13431354

13441355
void BitcodeFile::parse() {
1356+
if (symtab.ctx.driver.ltoCompilationDone) {
1357+
Err(symtab.ctx) << "LTO object file " << toString(this)
1358+
<< " linked in after doing LTO compilation.";
1359+
}
1360+
symtab.bitcodeFileInstances.push_back(this);
1361+
13451362
llvm::StringSaver &saver = lld::saver();
13461363

13471364
std::vector<std::pair<Symbol *, bool>> comdat(obj->getComdatTable().size());
@@ -1406,11 +1423,8 @@ void BitcodeFile::parse() {
14061423

14071424
void BitcodeFile::parseLazy() {
14081425
for (const lto::InputFile::Symbol &sym : obj->symbols())
1409-
if (!sym.isUndefined()) {
1426+
if (!sym.isUndefined())
14101427
symtab.addLazyObject(this, sym.getName());
1411-
if (!lazy)
1412-
return;
1413-
}
14141428
}
14151429

14161430
MachineTypes BitcodeFile::getMachineType(const llvm::lto::InputFile *obj) {

0 commit comments

Comments
 (0)