summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lld/COFF/DebugTypes.cpp2
-rw-r--r--lld/COFF/Driver.cpp60
-rw-r--r--lld/COFF/Driver.h5
-rw-r--r--lld/COFF/InputFiles.cpp62
-rw-r--r--lld/COFF/InputFiles.h37
-rw-r--r--lld/COFF/Options.td4
-rw-r--r--lld/COFF/SymbolTable.cpp77
-rw-r--r--lld/COFF/SymbolTable.h5
-rw-r--r--lld/COFF/Symbols.cpp6
-rw-r--r--lld/COFF/Symbols.h41
-rw-r--r--lld/COFF/Writer.cpp3
-rw-r--r--lld/test/COFF/Inputs/start-lib1.ll13
-rw-r--r--lld/test/COFF/Inputs/start-lib2.ll9
-rw-r--r--lld/test/COFF/start-lib-cmd-diagnostics.ll19
-rw-r--r--lld/test/COFF/start-lib.ll43
15 files changed, 316 insertions, 70 deletions
diff --git a/lld/COFF/DebugTypes.cpp b/lld/COFF/DebugTypes.cpp
index 78c1c78b408..c41c49cc319 100644
--- a/lld/COFF/DebugTypes.cpp
+++ b/lld/COFF/DebugTypes.cpp
@@ -231,7 +231,7 @@ void TypeServerSource::enqueue(const ObjFile *dependentFile,
if (!it.second)
return; // another OBJ already scheduled this PDB for load
- driver->enqueuePath(*p, false);
+ driver->enqueuePath(*p, false, false);
}
// Create an instance of TypeServerSource or an error string if the PDB couldn't
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 312c161f869..6e27edbecad 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -170,7 +170,7 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> mb) {
}
void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
- bool wholeArchive) {
+ bool wholeArchive, bool lazy) {
StringRef filename = mb->getBufferIdentifier();
MemoryBufferRef mbref = takeBuffer(std::move(mb));
@@ -195,11 +195,17 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
symtab->addFile(make<ArchiveFile>(mbref));
break;
case file_magic::bitcode:
- symtab->addFile(make<BitcodeFile>(mbref, "", 0));
+ if (lazy)
+ symtab->addFile(make<LazyObjFile>(mbref));
+ else
+ symtab->addFile(make<BitcodeFile>(mbref, "", 0));
break;
case file_magic::coff_object:
case file_magic::coff_import_library:
- symtab->addFile(make<ObjFile>(mbref));
+ if (lazy)
+ symtab->addFile(make<LazyObjFile>(mbref));
+ else
+ symtab->addFile(make<ObjFile>(mbref));
break;
case file_magic::pdb:
loadTypeServerSource(mbref);
@@ -220,7 +226,7 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb,
}
}
-void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
+void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive, bool lazy) {
auto future =
std::make_shared<std::future<MBErrPair>>(createFutureForFile(path));
std::string pathStr = path;
@@ -240,7 +246,7 @@ void LinkerDriver::enqueuePath(StringRef path, bool wholeArchive) {
else
error(msg + "; did you mean '" + nearest + "'");
} else
- driver->addBuffer(std::move(mbOrErr.first), wholeArchive);
+ driver->addBuffer(std::move(mbOrErr.first), wholeArchive, lazy);
});
}
@@ -359,7 +365,7 @@ void LinkerDriver::parseDirectives(InputFile *file) {
break;
case OPT_defaultlib:
if (Optional<StringRef> path = findLib(arg->getValue()))
- enqueuePath(*path, false);
+ enqueuePath(*path, false, false);
break;
case OPT_entry:
config->entry = addUndefined(mangle(arg->getValue()));
@@ -1553,19 +1559,45 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
return false;
};
- // Create a list of input files. Files can be given as arguments
- // for /defaultlib option.
- for (auto *arg : args.filtered(OPT_INPUT, OPT_wholearchive_file))
- if (Optional<StringRef> path = findFile(arg->getValue()))
- enqueuePath(*path, isWholeArchive(*path));
+ // Create a list of input files. These can be given as OPT_INPUT options
+ // and OPT_wholearchive_file options, and we also need to track OPT_start_lib
+ // and OPT_end_lib.
+ bool inLib = false;
+ for (auto *arg : args) {
+ switch (arg->getOption().getID()) {
+ case OPT_end_lib:
+ if (!inLib)
+ error("stray " + arg->getSpelling());
+ inLib = false;
+ break;
+ case OPT_start_lib:
+ if (inLib)
+ error("nested " + arg->getSpelling());
+ inLib = true;
+ break;
+ case OPT_wholearchive_file:
+ if (Optional<StringRef> path = findFile(arg->getValue()))
+ enqueuePath(*path, true, inLib);
+ break;
+ case OPT_INPUT:
+ if (Optional<StringRef> path = findFile(arg->getValue()))
+ enqueuePath(*path, isWholeArchive(*path), inLib);
+ break;
+ default:
+ // Ignore other options.
+ break;
+ }
+ }
+ // Process files specified as /defaultlib. These should be enequeued after
+ // other files, which is why they are in a separate loop.
for (auto *arg : args.filtered(OPT_defaultlib))
if (Optional<StringRef> path = findLib(arg->getValue()))
- enqueuePath(*path, false);
+ enqueuePath(*path, false, false);
// Windows specific -- Create a resource file containing a manifest file.
if (config->manifest == Configuration::Embed)
- addBuffer(createManifestRes(), false);
+ addBuffer(createManifestRes(), false, false);
// Read all input files given via the command line.
run();
@@ -1782,7 +1814,7 @@ void LinkerDriver::link(ArrayRef<const char *> argsArr) {
if (args.hasArg(OPT_include_optional)) {
// Handle /includeoptional
for (auto *arg : args.filtered(OPT_include_optional))
- if (dyn_cast_or_null<Lazy>(symtab->find(arg->getValue())))
+ if (dyn_cast_or_null<LazyArchive>(symtab->find(arg->getValue())))
addUndefined(arg->getValue());
while (run());
}
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 42aaea33319..0fd61759540 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -77,7 +77,7 @@ public:
MemoryBufferRef takeBuffer(std::unique_ptr<MemoryBuffer> mb);
- void enqueuePath(StringRef path, bool wholeArchive);
+ void enqueuePath(StringRef path, bool wholeArchive, bool lazy);
private:
std::unique_ptr<llvm::TarWriter> tar; // for /linkrepro
@@ -124,7 +124,8 @@ private:
StringRef findDefaultEntry();
WindowsSubsystem inferSubsystem();
- void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive);
+ void addBuffer(std::unique_ptr<MemoryBuffer> mb, bool wholeArchive,
+ bool lazy);
void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName,
StringRef parentName, uint64_t offsetInArchive);
diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp
index c24b59deb39..7bdeee9b361 100644
--- a/lld/COFF/InputFiles.cpp
+++ b/lld/COFF/InputFiles.cpp
@@ -73,6 +73,10 @@ static void checkAndSetWeakAlias(SymbolTable *symtab, InputFile *f,
}
}
+static bool ignoredSymbolName(StringRef name) {
+ return name == "@feat.00" || name == "@comp.id";
+}
+
ArchiveFile::ArchiveFile(MemoryBufferRef m) : InputFile(ArchiveKind, m) {}
void ArchiveFile::parse() {
@@ -81,7 +85,7 @@ void ArchiveFile::parse() {
// Read the symbol table to construct Lazy objects.
for (const Archive::Symbol &sym : file->symbols())
- symtab->addLazy(this, sym);
+ symtab->addLazyArchive(this, sym);
}
// Returns a buffer pointing to a member file containing a given symbol.
@@ -116,6 +120,49 @@ std::vector<MemoryBufferRef> getArchiveMembers(Archive *file) {
return v;
}
+void LazyObjFile::fetch() {
+ if (mb.getBuffer().empty())
+ return;
+
+ InputFile *file;
+ if (isBitcode(mb))
+ file = make<BitcodeFile>(mb, "", 0, std::move(symbols));
+ else
+ file = make<ObjFile>(mb, std::move(symbols));
+ mb = {};
+ symtab->addFile(file);
+}
+
+void LazyObjFile::parse() {
+ if (isBitcode(this->mb)) {
+ // Bitcode file.
+ std::unique_ptr<lto::InputFile> obj =
+ CHECK(lto::InputFile::create(this->mb), this);
+ for (const lto::InputFile::Symbol &sym : obj->symbols()) {
+ if (!sym.isUndefined())
+ symtab->addLazyObject(this, sym.getName());
+ }
+ return;
+ }
+
+ // Native object file.
+ COFFObjectFile *coffObj =
+ dyn_cast<COFFObjectFile>(CHECK(createBinary(mb), this).get());
+ uint32_t numSymbols = coffObj->getNumberOfSymbols();
+ for (uint32_t i = 0; i < numSymbols; ++i) {
+ COFFSymbolRef coffSym = check(coffObj->getSymbol(i));
+ if (coffSym.isUndefined() || !coffSym.isExternal() ||
+ coffSym.isWeakExternal())
+ continue;
+ StringRef name;
+ coffObj->getSymbolName(coffSym, name);
+ if (coffSym.isAbsolute() && ignoredSymbolName(name))
+ continue;
+ symtab->addLazyObject(this, name);
+ i += coffSym.getNumberOfAuxSymbols();
+ }
+}
+
void ObjFile::parse() {
// Parse a memory buffer as a COFF file.
std::unique_ptr<Binary> bin = CHECK(createBinary(mb), this);
@@ -526,13 +573,11 @@ Optional<Symbol *> ObjFile::createDefined(
if (sym.isAbsolute()) {
StringRef name = getName();
- // Skip special symbols.
- if (name == "@comp.id")
- return nullptr;
- if (name == "@feat.00") {
+ if (name == "@feat.00")
feat00Flags = sym.getValue();
+ // Skip special symbols.
+ if (ignoredSymbolName(name))
return nullptr;
- }
if (sym.isExternal())
return symtab->addAbsolute(name, sym);
@@ -782,8 +827,9 @@ void ImportFile::parse() {
}
BitcodeFile::BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive)
- : InputFile(BitcodeKind, mb) {
+ uint64_t offsetInArchive,
+ std::vector<Symbol *> &&symbols)
+ : InputFile(BitcodeKind, mb), symbols(std::move(symbols)) {
std::string path = mb.getBufferIdentifier().str();
if (config->thinLTOIndexOnly)
path = replaceThinLTOSuffix(mb.getBufferIdentifier());
diff --git a/lld/COFF/InputFiles.h b/lld/COFF/InputFiles.h
index d822685dc86..108a4caacd6 100644
--- a/lld/COFF/InputFiles.h
+++ b/lld/COFF/InputFiles.h
@@ -14,6 +14,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
+#include "llvm/BinaryFormat/Magic.h"
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
#include "llvm/LTO/LTO.h"
#include "llvm/Object/Archive.h"
@@ -55,7 +56,13 @@ class TpiSource;
// The root class of input files.
class InputFile {
public:
- enum Kind { ArchiveKind, ObjectKind, ImportKind, BitcodeKind };
+ enum Kind {
+ ArchiveKind,
+ ObjectKind,
+ LazyObjectKind,
+ ImportKind,
+ BitcodeKind
+ };
Kind kind() const { return fileKind; }
virtual ~InputFile() {}
@@ -102,10 +109,28 @@ private:
llvm::DenseSet<uint64_t> seen;
};
+// .obj or .o file between -start-lib and -end-lib.
+class LazyObjFile : public InputFile {
+public:
+ explicit LazyObjFile(MemoryBufferRef m) : InputFile(LazyObjectKind, m) {}
+ static bool classof(const InputFile *f) {
+ return f->kind() == LazyObjectKind;
+ }
+ // Makes this object file part of the link.
+ void fetch();
+ // Adds the symbols in this file to the symbol table as LazyObject symbols.
+ void parse() override;
+
+private:
+ std::vector<Symbol *> symbols;
+};
+
// .obj or .o file. This may be a member of an archive file.
class ObjFile : public InputFile {
public:
explicit ObjFile(MemoryBufferRef m) : InputFile(ObjectKind, m) {}
+ explicit ObjFile(MemoryBufferRef m, std::vector<Symbol *> &&symbols)
+ : InputFile(ObjectKind, m), symbols(std::move(symbols)) {}
static bool classof(const InputFile *f) { return f->kind() == ObjectKind; }
void parse() override;
MachineTypes getMachineType() override;
@@ -301,7 +326,11 @@ public:
class BitcodeFile : public InputFile {
public:
BitcodeFile(MemoryBufferRef mb, StringRef archiveName,
- uint64_t offsetInArchive);
+ uint64_t offsetInArchive)
+ : BitcodeFile(mb, archiveName, offsetInArchive, {}) {}
+ explicit BitcodeFile(MemoryBufferRef m, StringRef archiveName,
+ uint64_t offsetInArchive,
+ std::vector<Symbol *> &&symbols);
static bool classof(const InputFile *f) { return f->kind() == BitcodeKind; }
ArrayRef<Symbol *> getSymbols() { return symbols; }
MachineTypes getMachineType() override;
@@ -314,6 +343,10 @@ private:
std::vector<Symbol *> symbols;
};
+inline bool isBitcode(MemoryBufferRef mb) {
+ return identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode;
+}
+
std::string replaceThinLTOSuffix(StringRef path);
} // namespace coff
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index 6b9b26923fb..59e69ea5439 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -162,6 +162,8 @@ def help : F<"help">;
def help_q : Flag<["/??", "-??", "/?", "-?"], "">, Alias<help>;
// LLD extensions
+def end_lib : F<"end-lib">,
+ HelpText<"End a grouping of objects that should be treated as if they were together in an archive">;
def exclude_all_symbols : F<"exclude-all-symbols">;
def export_all_symbols : F<"export-all-symbols">;
defm demangle : B<"demangle",
@@ -176,6 +178,8 @@ def pdb_source_path : P<"pdbsourcepath",
"Base path used to make relative source file path absolute in PDB">;
def rsp_quoting : Joined<["--"], "rsp-quoting=">,
HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">;
+def start_lib : F<"start-lib">,
+ HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">;
def thinlto_emit_imports_files :
F<"thinlto-emit-imports-files">,
HelpText<"Emit .imports files with -thinlto-index-only">;
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 865791ca8e1..4b75d667bd4 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -61,6 +61,24 @@ static void errorOrWarn(const Twine &s) {
error(s);
}
+// Causes the file associated with a lazy symbol to be linked in.
+static void forceLazy(Symbol *s) {
+ s->pendingArchiveLoad = true;
+ switch (s->kind()) {
+ case Symbol::Kind::LazyArchiveKind: {
+ auto *l = cast<LazyArchive>(s);
+ l->file->addMember(l->sym);
+ break;
+ }
+ case Symbol::Kind::LazyObjectKind:
+ cast<LazyObject>(s)->file->fetch();
+ break;
+ default:
+ llvm_unreachable(
+ "symbol passed to forceLazy is not a LazyArchive or LazyObject");
+ }
+}
+
// Returns the symbol in SC whose value is <= Addr that is closest to Addr.
// This is generally the global variable or function whose definition contains
// Addr.
@@ -192,16 +210,15 @@ void SymbolTable::loadMinGWAutomaticImports() {
if (name.startswith("__imp_"))
continue;
- // If we have an undefined symbol, but we have a Lazy representing a
- // symbol we could load from file, make sure to load that.
- Lazy *l = dyn_cast_or_null<Lazy>(find(("__imp_" + name).str()));
- if (!l || l->pendingArchiveLoad)
+ // If we have an undefined symbol, but we have a lazy symbol we could
+ // load, load it.
+ Symbol *l = find(("__imp_" + name).str());
+ if (!l || l->pendingArchiveLoad || !l->isLazy())
continue;
- log("Loading lazy " + l->getName() + " from " + l->file->getName() +
+ log("Loading lazy " + l->getName() + " from " + l->getFile()->getName() +
" for automatic import");
- l->pendingArchiveLoad = true;
- l->file->addMember(l->sym);
+ forceLazy(l);
}
}
@@ -435,26 +452,22 @@ Symbol *SymbolTable::addUndefined(StringRef name, InputFile *f,
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(name, f);
- if (wasInserted || (isa<Lazy>(s) && isWeakAlias)) {
+ if (wasInserted || (s->isLazy() && isWeakAlias)) {
replaceSymbol<Undefined>(s, name);
return s;
}
- if (auto *l = dyn_cast<Lazy>(s)) {
- if (!s->pendingArchiveLoad) {
- s->pendingArchiveLoad = true;
- l->file->addMember(l->sym);
- }
- }
+ if (s->isLazy())
+ forceLazy(s);
return s;
}
-void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol &sym) {
+void SymbolTable::addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym) {
StringRef name = sym.getName();
Symbol *s;
bool wasInserted;
std::tie(s, wasInserted) = insert(name);
if (wasInserted) {
- replaceSymbol<Lazy>(s, f, sym);
+ replaceSymbol<LazyArchive>(s, f, sym);
return;
}
auto *u = dyn_cast<Undefined>(s);
@@ -464,6 +477,21 @@ void SymbolTable::addLazy(ArchiveFile *f, const Archive::Symbol &sym) {
f->addMember(sym);
}
+void SymbolTable::addLazyObject(LazyObjFile *f, StringRef n) {
+ Symbol *s;
+ bool wasInserted;
+ std::tie(s, wasInserted) = insert(n, f);
+ if (wasInserted) {
+ replaceSymbol<LazyObject>(s, f, n);
+ return;
+ }
+ auto *u = dyn_cast<Undefined>(s);
+ if (!u || u->weakAlias || s->pendingArchiveLoad)
+ return;
+ s->pendingArchiveLoad = true;
+ f->fetch();
+}
+
void SymbolTable::reportDuplicate(Symbol *existing, InputFile *newFile) {
std::string msg = "duplicate symbol: " + toString(*existing) + " in " +
toString(existing->getFile()) + " and in " +
@@ -480,7 +508,7 @@ Symbol *SymbolTable::addAbsolute(StringRef n, COFFSymbolRef sym) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ if (wasInserted || isa<Undefined>(s) || s->isLazy())
replaceSymbol<DefinedAbsolute>(s, n, sym);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
@@ -492,7 +520,7 @@ Symbol *SymbolTable::addAbsolute(StringRef n, uint64_t va) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ if (wasInserted || isa<Undefined>(s) || s->isLazy())
replaceSymbol<DefinedAbsolute>(s, n, va);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
@@ -504,7 +532,7 @@ Symbol *SymbolTable::addSynthetic(StringRef n, Chunk *c) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s))
+ if (wasInserted || isa<Undefined>(s) || s->isLazy())
replaceSymbol<DefinedSynthetic>(s, n, c);
else if (!isa<DefinedCOFF>(s))
reportDuplicate(s, nullptr);
@@ -560,7 +588,7 @@ Symbol *SymbolTable::addImportData(StringRef n, ImportFile *f) {
bool wasInserted;
std::tie(s, wasInserted) = insert(n, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+ if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
replaceSymbol<DefinedImportData>(s, n, f);
return s;
}
@@ -575,7 +603,7 @@ Symbol *SymbolTable::addImportThunk(StringRef name, DefinedImportData *id,
bool wasInserted;
std::tie(s, wasInserted) = insert(name, nullptr);
s->isUsedInRegularObj = true;
- if (wasInserted || isa<Undefined>(s) || isa<Lazy>(s)) {
+ if (wasInserted || isa<Undefined>(s) || s->isLazy()) {
replaceSymbol<DefinedImportThunk>(s, name, id, machine);
return s;
}
@@ -589,9 +617,12 @@ void SymbolTable::addLibcall(StringRef name) {
if (!sym)
return;
- if (Lazy *l = dyn_cast<Lazy>(sym)) {
+ if (auto *l = dyn_cast<LazyArchive>(sym)) {
MemoryBufferRef mb = l->getMemberBuffer();
- if (identify_magic(mb.getBuffer()) == llvm::file_magic::bitcode)
+ if (isBitcode(mb))
+ addUndefined(sym->getName());
+ } else if (LazyObject *o = dyn_cast<LazyObject>(sym)) {
+ if (isBitcode(o->file->mb))
addUndefined(sym->getName());
}
}
diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h
index 52eb8901e61..4ae818ef292 100644
--- a/lld/COFF/SymbolTable.h
+++ b/lld/COFF/SymbolTable.h
@@ -29,7 +29,7 @@ class Defined;
class DefinedAbsolute;
class DefinedRegular;
class DefinedRelative;
-class Lazy;
+class LazyArchive;
class SectionChunk;
class Symbol;
@@ -86,7 +86,8 @@ public:
Symbol *addAbsolute(StringRef n, uint64_t va);
Symbol *addUndefined(StringRef name, InputFile *f, bool isWeakAlias);
- void addLazy(ArchiveFile *f, const Archive::Symbol &sym);
+ void addLazyArchive(ArchiveFile *f, const Archive::Symbol &sym);
+ void addLazyObject(LazyObjFile *f, StringRef n);
Symbol *addAbsolute(StringRef n, COFFSymbolRef s);
Symbol *addRegular(InputFile *f, StringRef n,
const llvm::object::coff_symbol_generic *s = nullptr,
diff --git a/lld/COFF/Symbols.cpp b/lld/COFF/Symbols.cpp
index 1af11820a7e..ccdbc255347 100644
--- a/lld/COFF/Symbols.cpp
+++ b/lld/COFF/Symbols.cpp
@@ -61,7 +61,9 @@ StringRef Symbol::getName() {
InputFile *Symbol::getFile() {
if (auto *sym = dyn_cast<DefinedCOFF>(this))
return sym->file;
- if (auto *sym = dyn_cast<Lazy>(this))
+ if (auto *sym = dyn_cast<LazyArchive>(this))
+ return sym->file;
+ if (auto *sym = dyn_cast<LazyObject>(this))
return sym->file;
return nullptr;
}
@@ -119,7 +121,7 @@ Defined *Undefined::getWeakAlias() {
return nullptr;
}
-MemoryBufferRef Lazy::getMemberBuffer() {
+MemoryBufferRef LazyArchive::getMemberBuffer() {
Archive::Child c =
CHECK(sym.getMember(),
"could not get the member for symbol " + toCOFFString(sym));
diff --git a/lld/COFF/Symbols.h b/lld/COFF/Symbols.h
index 78c357aa2a5..fd79bd5065b 100644
--- a/lld/COFF/Symbols.h
+++ b/lld/COFF/Symbols.h
@@ -59,7 +59,8 @@ public:
DefinedSyntheticKind,
UndefinedKind,
- LazyKind,
+ LazyArchiveKind,
+ LazyObjectKind,
LastDefinedCOFFKind = DefinedCommonKind,
LastDefinedKind = DefinedSyntheticKind,
@@ -79,6 +80,10 @@ public:
// after calling markLive.
bool isLive() const;
+ bool isLazy() const {
+ return symbolKind == LazyArchiveKind || symbolKind == LazyObjectKind;
+ }
+
protected:
friend SymbolTable;
explicit Symbol(Kind k, StringRef n = "")
@@ -256,26 +261,29 @@ private:
// This class represents a symbol defined in an archive file. It is
// created from an archive file header, and it knows how to load an
// object file from an archive to replace itself with a defined
-// symbol. If the resolver finds both Undefined and Lazy for
-// the same name, it will ask the Lazy to load a file.
-class Lazy : public Symbol {
+// symbol. If the resolver finds both Undefined and LazyArchive for
+// the same name, it will ask the LazyArchive to load a file.
+class LazyArchive : public Symbol {
public:
- Lazy(ArchiveFile *f, const Archive::Symbol s)
- : Symbol(LazyKind, s.getName()), file(f), sym(s) {}
+ LazyArchive(ArchiveFile *f, const Archive::Symbol s)
+ : Symbol(LazyArchiveKind, s.getName()), file(f), sym(s) {}
- static bool classof(const Symbol *s) { return s->kind() == LazyKind; }
+ static bool classof(const Symbol *s) { return s->kind() == LazyArchiveKind; }
MemoryBufferRef getMemberBuffer();
ArchiveFile *file;
-
-private:
- friend SymbolTable;
-
-private:
const Archive::Symbol sym;
};
+class LazyObject : public Symbol {
+public:
+ LazyObject(LazyObjFile *f, StringRef n)
+ : Symbol(LazyObjectKind, n), file(f) {}
+ static bool classof(const Symbol *s) { return s->kind() == LazyObjectKind; }
+ LazyObjFile *file;
+};
+
// Undefined symbols.
class Undefined : public Symbol {
public:
@@ -381,7 +389,8 @@ inline uint64_t Defined::getRVA() {
return cast<DefinedCommon>(this)->getRVA();
case DefinedRegularKind:
return cast<DefinedRegular>(this)->getRVA();
- case LazyKind:
+ case LazyArchiveKind:
+ case LazyObjectKind:
case UndefinedKind:
llvm_unreachable("Cannot get the address for an undefined symbol.");
}
@@ -404,7 +413,8 @@ inline Chunk *Defined::getChunk() {
return cast<DefinedLocalImport>(this)->getChunk();
case DefinedCommonKind:
return cast<DefinedCommon>(this)->getChunk();
- case LazyKind:
+ case LazyArchiveKind:
+ case LazyObjectKind:
case UndefinedKind:
llvm_unreachable("Cannot get the chunk of an undefined symbol.");
}
@@ -419,11 +429,12 @@ union SymbolUnion {
alignas(DefinedCommon) char b[sizeof(DefinedCommon)];
alignas(DefinedAbsolute) char c[sizeof(DefinedAbsolute)];
alignas(DefinedSynthetic) char d[sizeof(DefinedSynthetic)];
- alignas(Lazy) char e[sizeof(Lazy)];
+ alignas(LazyArchive) char e[sizeof(LazyArchive)];
alignas(Undefined) char f[sizeof(Undefined)];
alignas(DefinedImportData) char g[sizeof(DefinedImportData)];
alignas(DefinedImportThunk) char h[sizeof(DefinedImportThunk)];
alignas(DefinedLocalImport) char i[sizeof(DefinedLocalImport)];
+ alignas(LazyObject) char j[sizeof(LazyObject)];
};
template <typename T, typename... ArgT>
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 0adf155e633..a98af439d04 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1519,7 +1519,8 @@ static void maybeAddAddressTakenFunction(SymbolRVASet &addressTakenSyms,
// Absolute is never code, synthetic generally isn't and usually isn't
// determinable.
break;
- case Symbol::LazyKind:
+ case Symbol::LazyArchiveKind:
+ case Symbol::LazyObjectKind:
case Symbol::UndefinedKind:
// Undefined symbols resolve to zero, so they don't have an RVA. Lazy
// symbols shouldn't have relocations.
diff --git a/lld/test/COFF/Inputs/start-lib1.ll b/lld/test/COFF/Inputs/start-lib1.ll
new file mode 100644
index 00000000000..3d4fe19daab
--- /dev/null
+++ b/lld/test/COFF/Inputs/start-lib1.ll
@@ -0,0 +1,13 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+declare i32 @bar()
+
+define i32 @foo() {
+ %1 = call i32 () @bar()
+ %2 = add i32 %1, 1
+ ret i32 %2
+}
+
+!llvm.linker.options = !{!0}
+!0 = !{!"/INCLUDE:foo"}
diff --git a/lld/test/COFF/Inputs/start-lib2.ll b/lld/test/COFF/Inputs/start-lib2.ll
new file mode 100644
index 00000000000..830ec1d6d19
--- /dev/null
+++ b/lld/test/COFF/Inputs/start-lib2.ll
@@ -0,0 +1,9 @@
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define i32 @bar() {
+ ret i32 1
+}
+
+!llvm.linker.options = !{!0}
+!0 = !{!"/INCLUDE:bar"}
diff --git a/lld/test/COFF/start-lib-cmd-diagnostics.ll b/lld/test/COFF/start-lib-cmd-diagnostics.ll
new file mode 100644
index 00000000000..b193ff6bb21
--- /dev/null
+++ b/lld/test/COFF/start-lib-cmd-diagnostics.ll
@@ -0,0 +1,19 @@
+; REQUIRES: x86
+;
+; We need an input file to lld, so create one.
+; RUN: llc -filetype=obj %s -o %t.obj
+
+; RUN: not lld-link %t.obj -end-lib 2>&1 \
+; RUN: | FileCheck --check-prefix=STRAY_END %s
+; STRAY_END: stray -end-lib
+
+; RUN: not lld-link -start-lib -start-lib %t.obj 2>&1 \
+; RUN: | FileCheck --check-prefix=NESTED_START %s
+; NESTED_START: nested -start-lib
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @main() {
+ ret void
+}
diff --git a/lld/test/COFF/start-lib.ll b/lld/test/COFF/start-lib.ll
new file mode 100644
index 00000000000..c48c167ff1b
--- /dev/null
+++ b/lld/test/COFF/start-lib.ll
@@ -0,0 +1,43 @@
+; REQUIRES: x86
+;
+; RUN: llc -filetype=obj %s -o %t.obj
+; RUN: llc -filetype=obj %p/Inputs/start-lib1.ll -o %t1.obj
+; RUN: llc -filetype=obj %p/Inputs/start-lib2.ll -o %t2.obj
+; RUN: opt -thinlto-bc %s -o %t.bc
+; RUN: opt -thinlto-bc %p/Inputs/start-lib1.ll -o %t1.bc
+; RUN: opt -thinlto-bc %p/Inputs/start-lib2.ll -o %t2.bc
+;
+; RUN: lld-link -out:%t1.exe -entry:main -opt:noref -lldmap:%t1.map \
+; RUN: %t.obj %t1.obj %t2.obj
+; RUN: FileCheck --check-prefix=TEST1 %s < %t1.map
+; RUN: lld-link -out:%t1.exe -entry:main -opt:noref -lldmap:%t1.thinlto.map \
+; RUN: %t.bc %t1.bc %t2.bc
+; RUN: FileCheck --check-prefix=TEST1 %s < %t1.thinlto.map
+; TEST1: foo
+; TEST1: bar
+;
+; RUN: lld-link -out:%t2.exe -entry:main -opt:noref -lldmap:%t2.map \
+; RUN: %t.obj -start-lib %t1.obj -end-lib %t2.obj
+; RUN: FileCheck --check-prefix=TEST2 %s < %t2.map
+; RUN: lld-link -out:%t2.exe -entry:main -opt:noref -lldmap:%t2.thinlto.map \
+; RUN: %t.bc -start-lib %t1.bc -end-lib %t2.bc
+; RUN: FileCheck --check-prefix=TEST2 %s < %t2.thinlto.map
+; TEST2-NOT: Name: foo
+; TEST2: bar
+; TEST2-NOT: Name: foo
+;
+; RUN: lld-link -out:%t3.exe -entry:main -opt:noref -lldmap:%t3.map \
+; RUN: %t.obj -start-lib %t1.obj %t2.obj
+; RUN: FileCheck --check-prefix=TEST3 %s < %t3.map
+; RUN: lld-link -out:%t3.exe -entry:main -opt:noref -lldmap:%t3.thinlto.map \
+; RUN: %t.bc -start-lib %t1.bc %t2.bc
+; RUN: FileCheck --check-prefix=TEST3 %s < %t3.thinlto.map
+; TEST3-NOT: foo
+; TEST3-NOT: bar
+
+target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-pc-windows-msvc"
+
+define void @main() {
+ ret void
+}
OpenPOWER on IntegriCloud