Skip to content

[LLD][COFF] Handle --start-lib/--end-lib group in the same way as other archives #136496

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 60 additions & 40 deletions lld/COFF/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,28 +200,13 @@ static bool compatibleMachineType(COFFLinkerContext &ctx, MachineTypes mt) {
}
}

void LinkerDriver::addFile(InputFile *file) {
Log(ctx) << "Reading " << toString(file);
if (file->lazy) {
if (auto *f = dyn_cast<BitcodeFile>(file))
f->parseLazy();
else
cast<ObjFile>(file)->parseLazy();
} else {
file->parse();
if (auto *f = dyn_cast<ObjFile>(file)) {
ctx.objFileInstances.push_back(f);
} else if (auto *f = dyn_cast<BitcodeFile>(file)) {
if (ltoCompilationDone) {
Err(ctx) << "LTO object file " << toString(file)
<< " linked in after "
"doing LTO compilation.";
}
f->symtab.bitcodeFileInstances.push_back(f);
} else if (auto *f = dyn_cast<ImportFile>(file)) {
ctx.importFileInstances.push_back(f);
}
void LinkerDriver::addFile(InputFile *file, CmdLineArchive *inCmdLineArchive) {
if (inCmdLineArchive) {
inCmdLineArchive->addInputFile(file); // schedule for lazy parsing
return;
}
Log(ctx) << "Reading " << toString(file);
file->maybeParse();

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

void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
bool wholeArchive, bool lazy) {
bool wholeArchive,
CmdLineArchive *inCmdLineArchive) {
StringRef filename = mb->getBufferIdentifier();

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

// File type is detected by contents, not by file extension.
switch (identify_magic(mbref.getBuffer())) {
case file_magic::windows_resource:
assert(!inCmdLineArchive &&
"Cannot specify a RES file inside a --start-lib/--end-lib group.");
resources.push_back(mbref);
break;
case file_magic::archive:
// FIXME: We could later support --start-lib/--end-lib groups, to allow for
// "extending" an existing archive/LIB.
assert(!inCmdLineArchive &&
"Cannot specify a LIB file inside a --start-lib/--end-lib group.");
if (wholeArchive) {
std::unique_ptr<Archive> file =
CHECK(Archive::create(mbref), filename + ": failed to parse archive");
Expand All @@ -284,13 +276,15 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
addFile(make<ArchiveFile>(ctx, mbref));
break;
case file_magic::bitcode:
addFile(BitcodeFile::create(ctx, mbref, "", 0, lazy));
addFile(BitcodeFile::create(ctx, mbref, "", 0), inCmdLineArchive);
break;
case file_magic::coff_object:
case file_magic::coff_import_library:
addFile(ObjFile::create(ctx, mbref, lazy));
addFile(ObjFile::create(ctx, mbref), inCmdLineArchive);
break;
case file_magic::pdb:
assert(!inCmdLineArchive &&
"Cannot specify a PDB file inside a --start-lib/--end-lib group.");
addFile(make<PDBInputFile>(ctx, mbref));
break;
case file_magic::coff_cl_gl_object:
Expand All @@ -299,6 +293,9 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
break;
case file_magic::pecoff_executable:
if (ctx.config.mingw) {
assert(
!inCmdLineArchive &&
"Cannot specify a PE/EXE file inside a --start-lib/--end-lib group.");
addFile(make<DLLFile>(ctx.symtab, mbref));
break;
}
Expand All @@ -315,7 +312,9 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
}
}

void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
void LinkerDriver::enqueuePath(
StringRef path, bool wholeArchive,
std::optional<std::shared_future<CmdLineArchive *>> inCmdLineArchive) {
auto future = std::make_shared<std::future<MBErrPair>>(
createFutureForFile(std::string(path)));
std::string pathStr = std::string(path);
Expand Down Expand Up @@ -354,7 +353,9 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
else
Err(ctx) << msg << "; did you mean '" << nearest << "'";
} else
ctx.driver.addBuffer(std::move(mb), wholeArchive, lazy);
ctx.driver.addBuffer(std::move(mb), wholeArchive,
inCmdLineArchive ? inCmdLineArchive->get()
: nullptr);
});
}

Expand All @@ -373,8 +374,7 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName,
if (magic == file_magic::coff_object) {
obj = ObjFile::create(ctx, mb);
} else if (magic == file_magic::bitcode) {
obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive,
/*lazy=*/false);
obj = BitcodeFile::create(ctx, mb, parentName, offsetInArchive);
} else if (magic == file_magic::coff_cl_gl_object) {
Err(ctx) << mb.getBufferIdentifier()
<< ": is not a native COFF file. Recompile without /GL?";
Expand Down Expand Up @@ -494,7 +494,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
break;
case OPT_defaultlib:
if (std::optional<StringRef> path = findLibIfNew(arg->getValue()))
enqueuePath(*path, false, false);
enqueuePath(*path);
break;
case OPT_entry:
if (!arg->getValue()[0])
Expand Down Expand Up @@ -2177,32 +2177,50 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// and OPT_end_lib.
{
llvm::TimeTraceScope timeScope2("Parse & queue inputs");
bool inLib = false;
std::optional<std::shared_future<CmdLineArchive *>> inCmdLineArchive;
for (auto *arg : args) {
switch (arg->getOption().getID()) {
case OPT_end_lib:
if (!inLib)
if (!inCmdLineArchive) {
Err(ctx) << "stray " << arg->getSpelling();
inLib = false;
} else {
enqueueTask([=]() { inCmdLineArchive->get()->maybeParse(); });
inCmdLineArchive = std::nullopt;
}
break;
case OPT_start_lib:
if (inLib)
if (inCmdLineArchive) {
Err(ctx) << "nested " << arg->getSpelling();
inLib = true;
} else {
auto a = std::make_shared<std::promise<CmdLineArchive *>>();
inCmdLineArchive = a->get_future().share();
enqueueTask([&, a]() {
// In is important to create a fake archive here so that we
// remember its placement on the command-line. This will be
// later needed to resolve symbols in the archive order required
// by the MSVC specification.
a->set_value(make<CmdLineArchive>(
ctx.symtab, MemoryBufferRef({}, "<cmdline-lib>")));
});
}
break;
case OPT_wholearchive_file:
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
enqueuePath(*path, true, inLib);
enqueuePath(*path, true, inCmdLineArchive);
break;
case OPT_INPUT:
if (std::optional<StringRef> path = findFileIfNew(arg->getValue()))
enqueuePath(*path, isWholeArchive(*path), inLib);
enqueuePath(*path, isWholeArchive(*path), inCmdLineArchive);
break;
default:
// Ignore other options.
break;
}
}
if (inCmdLineArchive) {
Warn(ctx) << "--start-lib with no --end-lib";
enqueueTask([=]() { inCmdLineArchive->get()->maybeParse(); });
}
}

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

if (args.hasArg(OPT_include_optional)) {
// Handle /includeoptional
for (auto *arg : args.filtered(OPT_include_optional))
if (isa_and_nonnull<LazyArchive>(symtab.find(arg->getValue())))
for (auto *arg : args.filtered(OPT_include_optional)) {
Symbol *sym = ctx.symtab.find(arg->getValue());
if (sym && (isa<LazyArchive>(sym) || isa<LazyObject>(sym)))
symtab.addGCRoot(arg->getValue());
}
}
});
} while (run());
Expand Down Expand Up @@ -2720,7 +2740,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// /manifestdependency: enables /manifest unless an explicit /manifest:no is
// also passed.
if (config->manifest == Configuration::Embed)
addBuffer(createManifestRes(), false, false);
addBuffer(createManifestRes(), false);
else if (config->manifest == Configuration::SideBySide ||
(config->manifest == Configuration::Default &&
!config->manifestDependencies.empty()))
Expand Down
18 changes: 11 additions & 7 deletions lld/COFF/Driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/WindowsDriver/MSVCPaths.h"
#include <future>
#include <memory>
#include <optional>
#include <set>
Expand Down Expand Up @@ -80,26 +81,31 @@ class LinkerDriver {

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

void addFile(InputFile *file);
void addFile(InputFile *file, CmdLineArchive *inCmdLineArchive = nullptr);

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

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

void enqueuePDB(StringRef Path) { enqueuePath(Path, false, false); }
void enqueuePDB(StringRef Path) { enqueuePath(Path); }

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

void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
// Schedule a input file for reading.
void enqueuePath(StringRef path, bool wholeArchive = false,
std::optional<std::shared_future<CmdLineArchive *>>
inCmdLineArchive = std::nullopt);

void pullArm64ECIcallHelper();

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

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

void pullArm64ECIcallHelper();
bool ltoCompilationDone = false;

private:
// Searches a file from search paths.
Expand Down Expand Up @@ -170,7 +176,7 @@ class LinkerDriver {
std::set<std::string> visitedLibs;

void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
bool lazy);
CmdLineArchive *inCmdLineArchive = nullptr);
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
StringRef parentName, uint64_t offsetInArchive);

Expand Down Expand Up @@ -258,8 +264,6 @@ class LinkerDriver {
// Create export thunks for exported and patchable Arm64EC function symbols.
void createECExportThunks();
void maybeCreateECExportThunk(StringRef name, Symbol *&sym);

bool ltoCompilationDone = false;
};

// Create enum with OPT_xxx values for each option in Options.td
Expand Down
44 changes: 29 additions & 15 deletions lld/COFF/InputFiles.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,19 @@ lld::coff::getArchiveMembers(COFFLinkerContext &ctx, Archive *file) {
return v;
}

ObjFile::ObjFile(SymbolTable &symtab, COFFObjectFile *coffObj, bool lazy)
: InputFile(symtab, ObjectKind, coffObj->getMemoryBufferRef(), lazy),
void CmdLineArchive::parse() {
for (InputFile *f : files) {
if (auto *o = dyn_cast<ObjFile>(f))
o->parseLazy();
else if (auto *b = dyn_cast<BitcodeFile>(f))
b->parseLazy();
}
}

void CmdLineArchive::addInputFile(InputFile *f) { files.push_back(f); }

ObjFile::ObjFile(SymbolTable &symtab, COFFObjectFile *coffObj)
: InputFile(symtab, ObjectKind, coffObj->getMemoryBufferRef()),
coffObj(coffObj) {}

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

bin->release();
return make<ObjFile>(ctx.getSymtab(MachineTypes(obj->getMachine())), obj,
lazy);
return make<ObjFile>(ctx.getSymtab(MachineTypes(obj->getMachine())), obj);
}

void ObjFile::parseLazy() {
Expand All @@ -257,8 +267,6 @@ void ObjFile::parseLazy() {
if (coffSym.isAbsolute() && ignoredSymbolName(name))
continue;
symtab.addLazyObject(this, name);
if (!lazy)
return;
i += coffSym.getNumberOfAuxSymbols();
}
}
Expand Down Expand Up @@ -299,6 +307,8 @@ void ObjFile::initializeECThunks() {
}

void ObjFile::parse() {
symtab.ctx.objFileInstances.push_back(this);

// Read section and symbol tables.
initializeChunks();
initializeSymbols();
Expand Down Expand Up @@ -1201,6 +1211,8 @@ ImportThunkChunk *ImportFile::makeImportThunk() {
}

void ImportFile::parse() {
symtab.ctx.importFileInstances.push_back(this);

const auto *hdr =
reinterpret_cast<const coff_import_header *>(mb.getBufferStart());

Expand Down Expand Up @@ -1307,14 +1319,14 @@ void ImportFile::parse() {
}

BitcodeFile::BitcodeFile(SymbolTable &symtab, MemoryBufferRef mb,
std::unique_ptr<lto::InputFile> &o, bool lazy)
: InputFile(symtab, BitcodeKind, mb, lazy) {
std::unique_ptr<lto::InputFile> &o)
: InputFile(symtab, BitcodeKind, mb) {
obj.swap(o);
}

BitcodeFile *BitcodeFile::create(COFFLinkerContext &ctx, MemoryBufferRef mb,
StringRef archiveName,
uint64_t offsetInArchive, bool lazy) {
uint64_t offsetInArchive) {
std::string path = mb.getBufferIdentifier().str();
if (ctx.config.thinLTOIndexOnly)
path = replaceThinLTOSuffix(mb.getBufferIdentifier(),
Expand All @@ -1335,13 +1347,18 @@ BitcodeFile *BitcodeFile::create(COFFLinkerContext &ctx, MemoryBufferRef mb,
utostr(offsetInArchive)));

std::unique_ptr<lto::InputFile> obj = check(lto::InputFile::create(mbref));
return make<BitcodeFile>(ctx.getSymtab(getMachineType(obj.get())), mb, obj,
lazy);
return make<BitcodeFile>(ctx.getSymtab(getMachineType(obj.get())), mb, obj);
}

BitcodeFile::~BitcodeFile() = default;

void BitcodeFile::parse() {
if (symtab.ctx.driver.ltoCompilationDone) {
Err(symtab.ctx) << "LTO object file " << toString(this)
<< " linked in after doing LTO compilation.";
}
symtab.bitcodeFileInstances.push_back(this);

llvm::StringSaver &saver = lld::saver();

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

void BitcodeFile::parseLazy() {
for (const lto::InputFile::Symbol &sym : obj->symbols())
if (!sym.isUndefined()) {
if (!sym.isUndefined())
symtab.addLazyObject(this, sym.getName());
if (!lazy)
return;
}
}

MachineTypes BitcodeFile::getMachineType(const llvm::lto::InputFile *obj) {
Expand Down
Loading
Loading