summaryrefslogtreecommitdiff
path: root/lld
diff options
context:
space:
mode:
Diffstat (limited to 'lld')
-rw-r--r--lld/COFF/COFFLinkerContext.h4
-rw-r--r--lld/COFF/Chunks.cpp2
-rw-r--r--lld/COFF/Config.h6
-rw-r--r--lld/COFF/Driver.cpp18
-rw-r--r--lld/COFF/Driver.h1
-rw-r--r--lld/COFF/DriverUtils.cpp37
-rw-r--r--lld/COFF/LTO.cpp2
-rw-r--r--lld/COFF/MinGW.cpp13
-rw-r--r--lld/COFF/Options.td9
-rw-r--r--lld/COFF/PDB.cpp67
-rw-r--r--lld/COFF/PDB.h13
-rw-r--r--lld/COFF/SymbolTable.cpp8
-rw-r--r--lld/COFF/Writer.cpp103
-rw-r--r--lld/Common/DriverDispatcher.cpp2
-rw-r--r--lld/ELF/InputSection.cpp1
-rw-r--r--lld/ELF/Target.h9
-rw-r--r--lld/MachO/Config.h1
-rw-r--r--lld/MachO/Driver.cpp179
-rw-r--r--lld/MachO/ExportTrie.cpp35
-rw-r--r--lld/MachO/ExportTrie.h3
-rw-r--r--lld/MachO/InputFiles.cpp13
-rw-r--r--lld/MachO/Options.td3
-rw-r--r--lld/test/COFF/Inputs/sectionlayout.yaml25
-rw-r--r--lld/test/COFF/color-diagnostics.test2
-rw-r--r--lld/test/COFF/exdllcharacteristics.test142
-rw-r--r--lld/test/COFF/linkrepro-res.test4
-rw-r--r--lld/test/COFF/linkrepro.test4
-rw-r--r--lld/test/COFF/lto-cache-warnings.ll12
-rw-r--r--lld/test/COFF/options.test10
-rw-r--r--lld/test/COFF/pdb-type-server-simple.test23
-rw-r--r--lld/test/COFF/precomp-link-samename.test7
-rw-r--r--lld/test/COFF/precomp-link.test41
-rw-r--r--lld/test/COFF/precomp-summary-fail.test23
-rw-r--r--lld/test/COFF/reloc-discarded.s2
-rw-r--r--lld/test/COFF/reloc-undefined-weak.s52
-rw-r--r--lld/test/COFF/sectionlayout.test129
-rw-r--r--lld/test/COFF/wrap-dllimport.s34
-rw-r--r--lld/test/ELF/arm-exidx-range.s4
-rw-r--r--lld/test/ELF/color-diagnostics.test2
-rw-r--r--lld/test/ELF/emulation-hexagon.s2
-rw-r--r--lld/test/ELF/file-access.s3
-rw-r--r--lld/test/ELF/linkerscript/invalid.test2
-rw-r--r--lld/test/ELF/loongarch-call36.s6
-rw-r--r--lld/test/ELF/lto/cache-warnings.ll12
-rw-r--r--lld/test/ELF/lto/comdat-nodeduplicate.ll14
-rw-r--r--lld/test/ELF/lto/resolution-err.ll2
-rw-r--r--lld/test/ELF/msp430.s2
-rw-r--r--lld/test/ELF/weak-shared-gc.s2
-rw-r--r--lld/test/ELF/weak-undef-lib.s2
-rw-r--r--lld/test/MachO/cgdata-generate-merge.s12
-rw-r--r--lld/test/MachO/cgdata-generate.s12
-rw-r--r--lld/test/MachO/color-diagnostics.test2
-rw-r--r--lld/test/MachO/framework.s3
-rw-r--r--lld/test/MachO/implicit-and-allowable-clients.test5
-rwxr-xr-xlld/test/MachO/invalid/Inputs/macho-trie-node-loopbin0 -> 8752 bytes
-rw-r--r--lld/test/MachO/invalid/export-trie-node-loop.s9
-rw-r--r--lld/test/MachO/link-search-at-loader-path-symlink.s4
-rw-r--r--lld/test/MachO/lto-cache-warnings.ll12
-rw-r--r--lld/test/MachO/read-workers.s16
-rw-r--r--lld/test/MachO/reexport-with-symlink.s3
-rw-r--r--lld/test/MachO/reexport-without-rpath.s4
-rw-r--r--lld/test/MachO/reproduce.s4
-rw-r--r--lld/test/MachO/stabs.s89
-rw-r--r--lld/test/MachO/tapi-rpath.s4
-rw-r--r--lld/test/MinGW/driver.test1
-rw-r--r--lld/test/lit.cfg.py13
-rw-r--r--lld/test/wasm/libsearch.s5
-rw-r--r--lld/test/wasm/lto/cache-warnings.ll12
-rw-r--r--lld/test/wasm/reproduce.s3
-rw-r--r--lld/wasm/Driver.cpp3
70 files changed, 1068 insertions, 240 deletions
diff --git a/lld/COFF/COFFLinkerContext.h b/lld/COFF/COFFLinkerContext.h
index f45b754384ef..0f8f2062b9f2 100644
--- a/lld/COFF/COFFLinkerContext.h
+++ b/lld/COFF/COFFLinkerContext.h
@@ -14,6 +14,7 @@
#include "DebugTypes.h"
#include "Driver.h"
#include "InputFiles.h"
+#include "PDB.h"
#include "SymbolTable.h"
#include "Writer.h"
#include "lld/Common/CommonLinkerContext.h"
@@ -61,6 +62,7 @@ public:
std::vector<ObjFile *> objFileInstances;
std::map<std::string, PDBInputFile *> pdbInputFileInstances;
std::vector<ImportFile *> importFileInstances;
+ std::int64_t consumedInputsSize = 0;
MergeChunk *mergeChunkInstances[Log2MaxSectionAlignment + 1] = {};
@@ -112,6 +114,8 @@ public:
Timer tpiStreamLayoutTimer;
Timer diskCommitTimer;
+ std::optional<PDBStats> pdbStats;
+
Configuration config;
DynamicRelocsChunk *dynamicRelocs = nullptr;
diff --git a/lld/COFF/Chunks.cpp b/lld/COFF/Chunks.cpp
index 39fc25047f3b..cb5cba5c414a 100644
--- a/lld/COFF/Chunks.cpp
+++ b/lld/COFF/Chunks.cpp
@@ -564,7 +564,7 @@ void SectionChunk::getBaserels(std::vector<Baserel> *res) {
if (ty == IMAGE_REL_BASED_ABSOLUTE)
continue;
Symbol *target = file->getSymbol(rel.SymbolTableIndex);
- if (!target || isa<DefinedAbsolute>(target))
+ if (!isa_and_nonnull<Defined>(target) || isa<DefinedAbsolute>(target))
continue;
res->emplace_back(rva + rel.VirtualAddress, ty);
}
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index a03bb5764167..a71476adcc49 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -212,6 +212,8 @@ struct Configuration {
// Used for /section=.name,{DEKPRSW} to set section attributes.
std::map<StringRef, uint32_t> section;
+ // Used for /sectionlayout: to layout sections in specified order.
+ std::map<std::string, int> sectionOrder;
// Options for manifest files.
ManifestKind manifest = Default;
@@ -310,6 +312,10 @@ struct Configuration {
bool dynamicBase = true;
bool allowBind = true;
bool cetCompat = false;
+ bool cetCompatStrict = false;
+ bool cetCompatIpValidationRelaxed = false;
+ bool cetCompatDynamicApisInProcOnly = false;
+ bool hotpatchCompat = false;
bool nxCompat = true;
bool allowIsolation = true;
bool terminalServerAware = true;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index ff616d0ce2bf..acba156ce341 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -205,6 +205,7 @@ void LinkerDriver::addFile(InputFile *file) {
else
cast<ObjFile>(file)->parseLazy();
} else {
+ ctx.consumedInputsSize += file->mb.getBufferSize();
file->parse();
if (auto *f = dyn_cast<ObjFile>(file)) {
ctx.objFileInstances.push_back(f);
@@ -2049,6 +2050,9 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Handle /section
for (auto *arg : args.filtered(OPT_section))
parseSection(arg->getValue());
+ // Handle /sectionlayout
+ if (auto *arg = args.getLastArg(OPT_sectionlayout))
+ parseSectionLayout(arg->getValue());
// Handle /align
if (auto *arg = args.getLastArg(OPT_align)) {
@@ -2139,6 +2143,14 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
config->integrityCheck =
args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
config->cetCompat = args.hasFlag(OPT_cetcompat, OPT_cetcompat_no, false);
+ config->cetCompatStrict =
+ args.hasFlag(OPT_cetcompatstrict, OPT_cetcompatstrict_no, false);
+ config->cetCompatIpValidationRelaxed = args.hasFlag(
+ OPT_cetipvalidationrelaxed, OPT_cetipvalidationrelaxed_no, false);
+ config->cetCompatDynamicApisInProcOnly = args.hasFlag(
+ OPT_cetdynamicapisinproc, OPT_cetdynamicapisinproc_no, false);
+ config->hotpatchCompat =
+ args.hasFlag(OPT_hotpatchcompatible, OPT_hotpatchcompatible_no, false);
config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
for (auto *arg : args.filtered(OPT_swaprun))
parseSwaprun(arg->getValue());
@@ -2292,6 +2304,12 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
parseFunctionPadMin(arg);
+ // MS link.exe compatibility, at least 6 bytes of function padding is
+ // required if hotpatchable
+ if (config->hotpatchCompat && config->functionPadMin < 6)
+ Err(ctx)
+ << "/hotpatchcompatible: requires at least 6 bytes of /functionpadmin";
+
// Handle /dependentloadflag
for (auto *arg :
args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt))
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index b500ac8bba56..14710d5853bc 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -213,6 +213,7 @@ private:
void parseMerge(StringRef);
void parsePDBPageSize(StringRef);
void parseSection(StringRef);
+ void parseSectionLayout(StringRef);
void parseSameAddress(StringRef);
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index dc4039f116f2..96ae2f0ddef6 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -214,6 +214,43 @@ void LinkerDriver::parseSection(StringRef s) {
ctx.config.section[name] = parseSectionAttributes(ctx, attrs);
}
+// Parses /sectionlayout: option argument.
+void LinkerDriver::parseSectionLayout(StringRef path) {
+ if (path.starts_with("@"))
+ path = path.substr(1);
+ std::unique_ptr<MemoryBuffer> layoutFile =
+ CHECK(MemoryBuffer::getFile(path), "could not open " + path);
+ StringRef content = layoutFile->getBuffer();
+ int index = 0;
+
+ while (!content.empty()) {
+ size_t pos = content.find_first_of("\r\n");
+ StringRef line;
+
+ if (pos == StringRef::npos) {
+ line = content;
+ content = StringRef();
+ } else {
+ line = content.substr(0, pos);
+ content = content.substr(pos).ltrim("\r\n");
+ }
+
+ line = line.trim();
+ if (line.empty())
+ continue;
+
+ StringRef sectionName = line.split(' ').first;
+
+ if (ctx.config.sectionOrder.count(sectionName.str())) {
+ Warn(ctx) << "duplicate section '" << sectionName.str()
+ << "' in section layout file, ignoring";
+ continue;
+ }
+
+ ctx.config.sectionOrder[sectionName.str()] = index++;
+ }
+}
+
void LinkerDriver::parseDosStub(StringRef path) {
std::unique_ptr<MemoryBuffer> stub =
CHECK(MemoryBuffer::getFile(path), "could not open " + path);
diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp
index 1050874a1b10..a988be610864 100644
--- a/lld/COFF/LTO.cpp
+++ b/lld/COFF/LTO.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/Caching.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstddef>
#include <memory>
@@ -176,6 +177,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
std::vector<InputFile *> BitcodeCompiler::compile() {
+ llvm::TimeTraceScope timeScope("Bitcode compile");
unsigned maxTasks = ltoObj->getMaxTasks();
buf.resize(maxTasks);
files.resize(maxTasks);
diff --git a/lld/COFF/MinGW.cpp b/lld/COFF/MinGW.cpp
index e7117cbea2e8..597c508115a3 100644
--- a/lld/COFF/MinGW.cpp
+++ b/lld/COFF/MinGW.cpp
@@ -269,10 +269,15 @@ void lld::coff::wrapSymbols(SymbolTable &symtab) {
// (We can't easily distinguish whether any object file actually
// referenced it or not, though.)
if (imp) {
- DefinedLocalImport *wrapimp = make<DefinedLocalImport>(
- symtab.ctx, saver().save("__imp_" + w.wrap->getName()), d);
- symtab.localImportChunks.push_back(wrapimp->getChunk());
- map[imp] = wrapimp;
+ if (Symbol *wrapimp =
+ symtab.find(("__imp_" + w.wrap->getName()).str())) {
+ map[imp] = wrapimp;
+ } else {
+ DefinedLocalImport *localwrapimp = make<DefinedLocalImport>(
+ symtab.ctx, saver().save("__imp_" + w.wrap->getName()), d);
+ symtab.localImportChunks.push_back(localwrapimp->getChunk());
+ map[imp] = localwrapimp;
+ }
}
}
}
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index 2c393cc94b5e..b5334de87b6a 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -102,6 +102,7 @@ def pdbstream : Joined<["/", "-", "/?", "-?"], "pdbstream:">,
MetaVarName<"<name>=<file>">,
HelpText<"Embed the contents of <file> in the PDB as named stream <name>">;
def section : P<"section", "Specify section attributes">;
+def sectionlayout : P<"sectionlayout", "Specifies the layout strategy for output sections">;
def stack : P<"stack", "Size of the stack">;
def stub : P<"stub", "Specify DOS stub file">;
def subsystem : P<"subsystem", "Specify subsystem">;
@@ -199,6 +200,12 @@ defm appcontainer : B<"appcontainer",
"Image can run outside an app container (default)">;
defm cetcompat : B<"cetcompat", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack",
"Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack (default)">;
+defm cetcompatstrict : B<"cetcompatstrict", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack in strict mode",
+ "Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack in strict mode (default)">;
+defm cetdynamicapisinproc : B<"cetdynamicapisinproc", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack in such a way that dynamic APIs allowed in process",
+ "Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack with dynamic APIs allowed in process (default)">;
+defm cetipvalidationrelaxed : B<"cetipvalidationrelaxed", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack with relaxed context IP validation",
+ "Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack with relaxed context IP validation (default)">;
defm dynamicbase : B<"dynamicbase", "Enable ASLR (default unless /fixed)",
"Disable ASLR (default when /fixed)">;
defm fixed : B<"fixed", "Disable base relocations",
@@ -206,6 +213,8 @@ defm fixed : B<"fixed", "Disable base relocations",
defm highentropyva : B<"highentropyva",
"Enable 64-bit ASLR (default on 64-bit)",
"Disable 64-bit ASLR">;
+defm hotpatchcompatible : B<"hotpatchcompatible", "Mark executable image as compatible with hotpatch",
+ "Don't mark executable image as compatible with hotpatch (default)">;
defm incremental : B<"incremental",
"Keep original import library if contents are unchanged",
"Overwrite import library even if contents are unchanged">;
diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp
index 94eeae279797..fd54d20da3cc 100644
--- a/lld/COFF/PDB.cpp
+++ b/lld/COFF/PDB.cpp
@@ -132,8 +132,8 @@ public:
/// Write the PDB to disk and store the Guid generated for it in *Guid.
void commit(codeview::GUID *guid);
- // Print statistics regarding the final PDB
- void printStats();
+ // Collect some statistics regarding the final PDB
+ void collectStats();
private:
void pdbMakeAbsolute(SmallVectorImpl<char> &fileName);
@@ -153,13 +153,6 @@ private:
DebugStringTableSubsection pdbStrTab;
llvm::SmallString<128> nativePath;
-
- // For statistics
- uint64_t globalSymbols = 0;
- uint64_t moduleSymbols = 0;
- uint64_t publicSymbols = 0;
- uint64_t nbTypeRecords = 0;
- uint64_t nbTypeRecordsBytes = 0;
};
/// Represents an unrelocated DEBUG_S_FRAMEDATA subsection.
@@ -609,7 +602,9 @@ void PDBLinker::analyzeSymbolSubsection(
addGlobalSymbol(builder.getGsiBuilder(),
file->moduleDBI->getModuleIndex(), moduleSymOffset,
storage);
- ++globalSymbols;
+
+ if (ctx.pdbStats.has_value())
+ ++ctx.pdbStats->globalSymbols;
}
// Update the module stream offset and record any string table index
@@ -618,7 +613,9 @@ void PDBLinker::analyzeSymbolSubsection(
if (symbolGoesInModuleStream(sym, scopeLevel)) {
recordStringTableReferences(sym, moduleSymOffset, stringTableFixups);
moduleSymOffset += alignedSize;
- ++moduleSymbols;
+
+ if (ctx.pdbStats.has_value())
+ ++ctx.pdbStats->moduleSymbols;
}
return Error::success();
@@ -1191,10 +1188,10 @@ void PDBLinker::addObjectsToPDB() {
}
}
- if (ctx.config.showSummary) {
+ if (ctx.pdbStats.has_value()) {
for (TpiSource *source : ctx.tpiSourceList) {
- nbTypeRecords += source->nbTypeRecords;
- nbTypeRecordsBytes += source->nbTypeRecordsBytes;
+ ctx.pdbStats->nbTypeRecords += source->nbTypeRecords;
+ ctx.pdbStats->nbTypeRecordsBytes += source->nbTypeRecordsBytes;
}
}
}
@@ -1230,39 +1227,24 @@ void PDBLinker::addPublicsToPDB() {
}
});
- if (!publics.empty()) {
- publicSymbols = publics.size();
+ if (ctx.pdbStats.has_value())
+ ctx.pdbStats->publicSymbols = publics.size();
+
+ if (!publics.empty())
gsiBuilder.addPublicSymbols(std::move(publics));
- }
}
-void PDBLinker::printStats() {
+void PDBLinker::collectStats() {
if (!ctx.config.showSummary)
return;
+ ctx.pdbStats->nbTPIrecords = builder.getTpiBuilder().getRecordCount();
+ ctx.pdbStats->nbIPIrecords = builder.getIpiBuilder().getRecordCount();
+ ctx.pdbStats->strTabSize = pdbStrTab.size();
+
SmallString<256> buffer;
raw_svector_ostream stream(buffer);
- stream << center_justify("Summary", 80) << '\n'
- << std::string(80, '-') << '\n';
-
- auto print = [&](uint64_t v, StringRef s) {
- stream << format_decimal(v, 15) << " " << s << '\n';
- };
-
- print(ctx.objFileInstances.size(),
- "Input OBJ files (expanded from all cmd-line inputs)");
- print(ctx.typeServerSourceMappings.size(), "PDB type server dependencies");
- print(ctx.precompSourceMappings.size(), "Precomp OBJ dependencies");
- print(nbTypeRecords, "Input type records");
- print(nbTypeRecordsBytes, "Input type records bytes");
- print(builder.getTpiBuilder().getRecordCount(), "Merged TPI records");
- print(builder.getIpiBuilder().getRecordCount(), "Merged IPI records");
- print(pdbStrTab.size(), "Output PDB strings");
- print(globalSymbols, "Global symbol records");
- print(moduleSymbols, "Module symbol records");
- print(publicSymbols, "Public symbol records");
-
auto printLargeInputTypeRecs = [&](StringRef name,
ArrayRef<uint32_t> recCounts,
TypeCollection &records) {
@@ -1313,9 +1295,9 @@ void PDBLinker::printStats() {
// FIXME: Reimplement for ghash.
printLargeInputTypeRecs("TPI", tMerger.tpiCounts, tMerger.getTypeTable());
printLargeInputTypeRecs("IPI", tMerger.ipiCounts, tMerger.getIDTable());
- }
- Msg(ctx) << buffer;
+ ctx.pdbStats->largeInputTypeRecs = buffer.str();
+ }
}
void PDBLinker::addNatvisFiles() {
@@ -1619,6 +1601,9 @@ void lld::coff::createPDB(COFFLinkerContext &ctx,
{
PDBLinker pdb(ctx);
+ if (ctx.config.showSummary)
+ ctx.pdbStats.emplace();
+
pdb.initialize(buildId);
pdb.addObjectsToPDB();
pdb.addImportFilesToPDB();
@@ -1635,8 +1620,8 @@ void lld::coff::createPDB(COFFLinkerContext &ctx,
memcpy(&buildId->PDB70.Signature, &guid, 16);
}
+ pdb.collectStats();
t1.stop();
- pdb.printStats();
// Manually start this profile point to measure ~PDBLinker().
if (getTimeTraceProfilerInstance() != nullptr)
diff --git a/lld/COFF/PDB.h b/lld/COFF/PDB.h
index 991805cc95b3..4a5df37c0fe6 100644
--- a/lld/COFF/PDB.h
+++ b/lld/COFF/PDB.h
@@ -30,6 +30,19 @@ void createPDB(COFFLinkerContext &ctx, llvm::ArrayRef<uint8_t> sectionTable,
std::optional<std::pair<llvm::StringRef, uint32_t>>
getFileLineCodeView(const SectionChunk *c, uint32_t addr);
+// For statistics
+struct PDBStats {
+ uint64_t globalSymbols = 0;
+ uint64_t moduleSymbols = 0;
+ uint64_t publicSymbols = 0;
+ uint64_t nbTypeRecords = 0;
+ uint64_t nbTypeRecordsBytes = 0;
+ uint64_t nbTPIrecords = 0;
+ uint64_t nbIPIrecords = 0;
+ uint64_t strTabSize = 0;
+ std::string largeInputTypeRecs;
+};
+
} // namespace coff
} // namespace lld
diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp
index 0a88807c00dd..26a2b4944dc6 100644
--- a/lld/COFF/SymbolTable.cpp
+++ b/lld/COFF/SymbolTable.cpp
@@ -1437,11 +1437,13 @@ void SymbolTable::compileBitcodeFiles() {
if (bitcodeFileInstances.empty())
return;
- llvm::TimeTraceScope timeScope("Compile bitcode");
ScopedTimer t(ctx.ltoTimer);
lto.reset(new BitcodeCompiler(ctx));
- for (BitcodeFile *f : bitcodeFileInstances)
- lto->add(*f);
+ {
+ llvm::TimeTraceScope addScope("Add bitcode file instances");
+ for (BitcodeFile *f : bitcodeFileInstances)
+ lto->add(*f);
+ }
for (InputFile *newObj : lto->compile()) {
ObjFile *obj = cast<ObjFile>(newObj);
obj->parse();
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 21ab9d17a26f..e0d0ac18ea5d 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -27,6 +27,8 @@
#include "llvm/MC/StringTableBuilder.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/TimeProfiler.h"
@@ -219,6 +221,7 @@ private:
void sortECChunks();
void appendECImportTables();
void removeUnusedSections();
+ void layoutSections();
void assignAddresses();
bool isInRange(uint16_t relType, uint64_t s, uint64_t p, int margin,
MachineTypes machine);
@@ -281,6 +284,8 @@ private:
template <typename T>
void prepareLoadConfig(SymbolTable &symtab, T *loadConfig);
+ void printSummary();
+
std::unique_ptr<FileOutputBuffer> &buffer;
std::map<PartialSectionKey, PartialSection *> partialSections;
StringTableBuilder strtab;
@@ -783,6 +788,7 @@ void Writer::run() {
appendECImportTables();
createDynamicRelocs();
removeUnusedSections();
+ layoutSections();
finalizeAddresses();
removeEmptySections();
assignOutputSectionIndices();
@@ -821,6 +827,8 @@ void Writer::run() {
writePEChecksum();
+ printSummary();
+
if (errorCount())
return;
@@ -1222,7 +1230,9 @@ void Writer::createMiscChunks() {
// Create Debug Information Chunks
debugInfoSec = config->mingw ? buildidSec : rdataSec;
if (config->buildIDHash != BuildIDHash::None || config->debug ||
- config->repro || config->cetCompat) {
+ config->repro || config->cetCompat || config->cetCompatStrict ||
+ config->cetCompatIpValidationRelaxed ||
+ config->cetCompatDynamicApisInProcOnly || config->hotpatchCompat) {
debugDirectory =
make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);
debugDirectory->setAlignment(4);
@@ -1243,10 +1253,26 @@ void Writer::createMiscChunks() {
});
}
- if (config->cetCompat) {
- debugRecords.emplace_back(COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,
- make<ExtendedDllCharacteristicsChunk>(
- IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT));
+ uint16_t ex_characteristics_flags = 0;
+ if (config->cetCompat)
+ ex_characteristics_flags |= IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT;
+ if (config->cetCompatStrict)
+ ex_characteristics_flags |=
+ IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE;
+ if (config->cetCompatIpValidationRelaxed)
+ ex_characteristics_flags |=
+ IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE;
+ if (config->cetCompatDynamicApisInProcOnly)
+ ex_characteristics_flags |=
+ IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY;
+ if (config->hotpatchCompat)
+ ex_characteristics_flags |=
+ IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE;
+
+ if (ex_characteristics_flags) {
+ debugRecords.emplace_back(
+ COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,
+ make<ExtendedDllCharacteristicsChunk>(ex_characteristics_flags));
}
// Align and add each chunk referenced by the debug data directory.
@@ -1413,6 +1439,33 @@ void Writer::removeUnusedSections() {
llvm::erase_if(ctx.outputSections, isUnused);
}
+void Writer::layoutSections() {
+ llvm::TimeTraceScope timeScope("Layout sections");
+ if (ctx.config.sectionOrder.empty())
+ return;
+
+ llvm::stable_sort(ctx.outputSections,
+ [this](const OutputSection *a, const OutputSection *b) {
+ auto itA = ctx.config.sectionOrder.find(a->name.str());
+ auto itB = ctx.config.sectionOrder.find(b->name.str());
+ bool aInOrder = itA != ctx.config.sectionOrder.end();
+ bool bInOrder = itB != ctx.config.sectionOrder.end();
+
+ // Put unspecified sections after all specified sections
+ if (aInOrder && bInOrder) {
+ return itA->second < itB->second;
+ } else if (aInOrder && !bInOrder) {
+ return true; // ordered sections come before unordered
+ } else {
+ // (!aInOrder && bInOrder): unordered comes after
+ // ordered
+ // (!aInOrder && !bInOrder): both unspecified, preserve
+ // the original order
+ return false;
+ }
+ });
+}
+
// The Windows loader doesn't seem to like empty sections,
// so we remove them if any.
void Writer::removeEmptySections() {
@@ -2999,3 +3052,43 @@ void Writer::prepareLoadConfig(SymbolTable &symtab, T *loadConfig) {
#undef CHECK_VA
#undef CHECK_ABSOLUTE
}
+
+void Writer::printSummary() {
+ if (!ctx.config.showSummary)
+ return;
+
+ SmallString<256> buffer;
+ raw_svector_ostream stream(buffer);
+
+ stream << center_justify("Summary", 80) << '\n'
+ << std::string(80, '-') << '\n';
+
+ auto print = [&](uint64_t v, StringRef s) {
+ stream << formatv("{0}",
+ fmt_align(formatv("{0:N}", v), AlignStyle::Right, 20))
+ << " " << s << '\n';
+ };
+
+ bool hasStats = ctx.pdbStats.has_value();
+
+ print(ctx.objFileInstances.size(),
+ "Input OBJ files (expanded from all cmd-line inputs)");
+ print(ctx.consumedInputsSize,
+ "Size of all consumed OBJ files (non-lazy), in bytes");
+ print(ctx.typeServerSourceMappings.size(), "PDB type server dependencies");
+ print(ctx.precompSourceMappings.size(), "Precomp OBJ dependencies");
+ print(hasStats ? ctx.pdbStats->nbTypeRecords : 0, "Input debug type records");
+ print(hasStats ? ctx.pdbStats->nbTypeRecordsBytes : 0,
+ "Size of all input debug type records, in bytes");
+ print(hasStats ? ctx.pdbStats->nbTPIrecords : 0, "Merged TPI records");
+ print(hasStats ? ctx.pdbStats->nbIPIrecords : 0, "Merged IPI records");
+ print(hasStats ? ctx.pdbStats->strTabSize : 0, "Output PDB strings");
+ print(hasStats ? ctx.pdbStats->globalSymbols : 0, "Global symbol records");
+ print(hasStats ? ctx.pdbStats->moduleSymbols : 0, "Module symbol records");
+ print(hasStats ? ctx.pdbStats->publicSymbols : 0, "Public symbol records");
+
+ if (hasStats)
+ stream << ctx.pdbStats->largeInputTypeRecs;
+
+ Msg(ctx) << buffer;
+}
diff --git a/lld/Common/DriverDispatcher.cpp b/lld/Common/DriverDispatcher.cpp
index 34f0ed24b3df..7c5f1cd3692e 100644
--- a/lld/Common/DriverDispatcher.cpp
+++ b/lld/Common/DriverDispatcher.cpp
@@ -45,7 +45,7 @@ static cl::TokenizerCallback getDefaultQuotingStyle() {
static bool isPETargetName(StringRef s) {
return s == "i386pe" || s == "i386pep" || s == "thumb2pe" || s == "arm64pe" ||
- s == "arm64ecpe" || s == "arm64xpe";
+ s == "arm64ecpe" || s == "arm64xpe" || s == "mipspe";
}
static std::optional<bool> isPETarget(llvm::ArrayRef<const char *> args) {
diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp
index 784ff7cc7991..ea6bcc5bb272 100644
--- a/lld/ELF/InputSection.cpp
+++ b/lld/ELF/InputSection.cpp
@@ -19,6 +19,7 @@
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Compression.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/xxhash.h"
#include <algorithm>
#include <optional>
diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h
index e121fa1183e9..bb8c24f052aa 100644
--- a/lld/ELF/Target.h
+++ b/lld/ELF/Target.h
@@ -326,15 +326,6 @@ inline void write64(Ctx &ctx, void *p, uint64_t v) {
llvm::support::endian::write64(p, v, ctx.arg.endianness);
}
-// Overwrite a ULEB128 value and keep the original length.
-inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) {
- while (*bufLoc & 0x80) {
- *bufLoc++ = 0x80 | (val & 0x7f);
- val >>= 7;
- }
- *bufLoc = val;
- return val;
-}
} // namespace elf
} // namespace lld
diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h
index a01e60efbe76..19dba790c1c7 100644
--- a/lld/MachO/Config.h
+++ b/lld/MachO/Config.h
@@ -186,6 +186,7 @@ struct Configuration {
bool interposable = false;
bool errorForArchMismatch = false;
bool ignoreAutoLink = false;
+ int readWorkers = 0;
// ld64 allows invalid auto link options as long as the link succeeds. LLD
// does not, but there are cases in the wild where the invalid linker options
// exist. This allows users to ignore the specific invalid options in the case
diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index f11c65a5583a..3db638e1ead9 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -44,8 +44,10 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Parallel.h"
#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
#include "llvm/Support/TarWriter.h"
#include "llvm/Support/TargetSelect.h"
+#include "llvm/Support/Threading.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/TextAPI/Architecture.h"
@@ -282,11 +284,117 @@ static void saveThinArchiveToRepro(ArchiveFile const *file) {
": Archive::children failed: " + toString(std::move(e)));
}
-static InputFile *addFile(StringRef path, LoadType loadType,
- bool isLazy = false, bool isExplicit = true,
- bool isBundleLoader = false,
- bool isForceHidden = false) {
- std::optional<MemoryBufferRef> buffer = readFile(path);
+struct DeferredFile {
+ StringRef path;
+ bool isLazy;
+ MemoryBufferRef buffer;
+};
+using DeferredFiles = std::vector<DeferredFile>;
+
+class SerialBackgroundQueue {
+ std::deque<std::function<void()>> queue;
+ std::thread *running;
+ std::mutex mutex;
+
+public:
+ void queueWork(std::function<void()> work) {
+ mutex.lock();
+ if (running && queue.empty()) {
+ mutex.unlock();
+ running->join();
+ mutex.lock();
+ delete running;
+ running = nullptr;
+ }
+
+ if (work) {
+ queue.emplace_back(std::move(work));
+ if (!running)
+ running = new std::thread([&]() {
+ while (true) {
+ mutex.lock();
+ if (queue.empty()) {
+ mutex.unlock();
+ break;
+ }
+ auto work = std::move(queue.front());
+ mutex.unlock();
+ work();
+ mutex.lock();
+ queue.pop_front();
+ mutex.unlock();
+ }
+ });
+ }
+ mutex.unlock();
+ }
+};
+
+// Most input files have been mapped but not yet paged in.
+// This code forces the page-ins on multiple threads so
+// the process is not stalled waiting on disk buffer i/o.
+void multiThreadedPageInBackground(DeferredFiles &deferred) {
+ static const size_t pageSize = Process::getPageSizeEstimate();
+ static const size_t largeArchive = 10 * 1024 * 1024;
+#ifndef NDEBUG
+ using namespace std::chrono;
+ std::atomic_int numDeferedFilesTouched = 0;
+ static std::atomic_uint64_t totalBytes = 0;
+ auto t0 = high_resolution_clock::now();
+#endif
+
+ auto preloadDeferredFile = [&](const DeferredFile &deferredFile) {
+ const StringRef &buff = deferredFile.buffer.getBuffer();
+ if (buff.size() > largeArchive)
+ return;
+#ifndef NDEBUG
+ totalBytes += buff.size();
+ numDeferedFilesTouched += 1;
+#endif
+
+ // Reference all file's mmap'd pages to load them into memory.
+ for (const char *page = buff.data(), *end = page + buff.size(); page < end;
+ page += pageSize)
+ LLVM_ATTRIBUTE_UNUSED volatile char t = *page;
+ };
+#if LLVM_ENABLE_THREADS
+ { // Create scope for waiting for the taskGroup
+ std::atomic_size_t index = 0;
+ llvm::parallel::TaskGroup taskGroup;
+ for (int w = 0; w < config->readWorkers; w++)
+ taskGroup.spawn([&index, &preloadDeferredFile, &deferred]() {
+ while (true) {
+ size_t localIndex = index.fetch_add(1);
+ if (localIndex >= deferred.size())
+ break;
+ preloadDeferredFile(deferred[localIndex]);
+ }
+ });
+ }
+#endif
+#ifndef NDEBUG
+ auto dt = high_resolution_clock::now() - t0;
+ if (Process::GetEnv("LLD_MULTI_THREAD_PAGE"))
+ llvm::dbgs() << "multiThreadedPageIn " << totalBytes << "/"
+ << numDeferedFilesTouched << "/" << deferred.size() << "/"
+ << duration_cast<milliseconds>(dt).count() / 1000. << "\n";
+#endif
+}
+
+static void multiThreadedPageIn(const DeferredFiles &deferred) {
+ static SerialBackgroundQueue pageInQueue;
+ pageInQueue.queueWork([=]() {
+ DeferredFiles files = deferred;
+ multiThreadedPageInBackground(files);
+ });
+}
+
+static InputFile *processFile(std::optional<MemoryBufferRef> buffer,
+ DeferredFiles *archiveContents, StringRef path,
+ LoadType loadType, bool isLazy = false,
+ bool isExplicit = true,
+ bool isBundleLoader = false,
+ bool isForceHidden = false) {
if (!buffer)
return nullptr;
MemoryBufferRef mbref = *buffer;
@@ -379,6 +487,8 @@ static InputFile *addFile(StringRef path, LoadType loadType,
continue;
}
+ if (archiveContents)
+ archiveContents->push_back({path, isLazy, *mb});
if (!hasObjCSection(*mb))
continue;
if (Error e = file->fetch(c, "-ObjC"))
@@ -390,7 +500,8 @@ static InputFile *addFile(StringRef path, LoadType loadType,
": Archive::children failed: " + toString(std::move(e)));
}
}
- file->addLazySymbols();
+ if (!archiveContents || archiveContents->empty())
+ file->addLazySymbols();
loadedArchives[path] = ArchiveFileInfo{file, isCommandLineLoad};
newFile = file;
break;
@@ -441,6 +552,24 @@ static InputFile *addFile(StringRef path, LoadType loadType,
return newFile;
}
+static InputFile *addFile(StringRef path, LoadType loadType,
+ bool isLazy = false, bool isExplicit = true,
+ bool isBundleLoader = false,
+ bool isForceHidden = false) {
+ return processFile(readFile(path), nullptr, path, loadType, isLazy,
+ isExplicit, isBundleLoader, isForceHidden);
+}
+
+static void deferFile(StringRef path, bool isLazy, DeferredFiles &deferred) {
+ std::optional<MemoryBufferRef> buffer = readFile(path);
+ if (!buffer)
+ return;
+ if (config->readWorkers)
+ deferred.push_back({path, isLazy, *buffer});
+ else
+ processFile(buffer, nullptr, path, LoadType::CommandLine, isLazy);
+}
+
static std::vector<StringRef> missingAutolinkWarnings;
static void addLibrary(StringRef name, bool isNeeded, bool isWeak,
bool isReexport, bool isHidden, bool isExplicit,
@@ -564,13 +693,14 @@ void macho::resolveLCLinkerOptions() {
}
}
-static void addFileList(StringRef path, bool isLazy) {
+static void addFileList(StringRef path, bool isLazy,
+ DeferredFiles &deferredFiles) {
std::optional<MemoryBufferRef> buffer = readFile(path);
if (!buffer)
return;
MemoryBufferRef mbref = *buffer;
for (StringRef path : args::getLines(mbref))
- addFile(rerootPath(path), LoadType::CommandLine, isLazy);
+ deferFile(rerootPath(path), isLazy, deferredFiles);
}
// We expect sub-library names of the form "libfoo", which will match a dylib
@@ -1222,6 +1352,8 @@ static void createFiles(const InputArgList &args) {
bool isLazy = false;
// If we've processed an opening --start-lib, without a matching --end-lib
bool inLib = false;
+ DeferredFiles deferredFiles;
+
for (const Arg *arg : args) {
const Option &opt = arg->getOption();
warnIfDeprecatedOption(opt);
@@ -1229,7 +1361,7 @@ static void createFiles(const InputArgList &args) {
switch (opt.getID()) {
case OPT_INPUT:
- addFile(rerootPath(arg->getValue()), LoadType::CommandLine, isLazy);
+ deferFile(rerootPath(arg->getValue()), isLazy, deferredFiles);
break;
case OPT_needed_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
@@ -1249,7 +1381,7 @@ static void createFiles(const InputArgList &args) {
dylibFile->forceWeakImport = true;
break;
case OPT_filelist:
- addFileList(arg->getValue(), isLazy);
+ addFileList(arg->getValue(), isLazy, deferredFiles);
break;
case OPT_force_load:
addFile(rerootPath(arg->getValue()), LoadType::CommandLineForce);
@@ -1295,6 +1427,24 @@ static void createFiles(const InputArgList &args) {
break;
}
}
+
+ if (config->readWorkers) {
+ multiThreadedPageIn(deferredFiles);
+
+ DeferredFiles archiveContents;
+ std::vector<ArchiveFile *> archives;
+ for (auto &file : deferredFiles) {
+ auto inputFile = processFile(file.buffer, &archiveContents, file.path,
+ LoadType::CommandLine, file.isLazy);
+ if (ArchiveFile *archive = dyn_cast<ArchiveFile>(inputFile))
+ archives.push_back(archive);
+ }
+
+ if (!archiveContents.empty())
+ multiThreadedPageIn(archiveContents);
+ for (auto *archive : archives)
+ archive->addLazySymbols();
+ }
}
static void gatherInputSections() {
@@ -1681,6 +1831,15 @@ bool link(ArrayRef<const char *> argsArr, llvm::raw_ostream &stdoutOS,
}
}
+ if (auto *arg = args.getLastArg(OPT_read_workers)) {
+ StringRef v(arg->getValue());
+ unsigned workers = 0;
+ if (!llvm::to_integer(v, workers, 0))
+ error(arg->getSpelling() +
+ ": expected a non-negative integer, but got '" + arg->getValue() +
+ "'");
+ config->readWorkers = workers;
+ }
if (auto *arg = args.getLastArg(OPT_threads_eq)) {
StringRef v(arg->getValue());
unsigned threads = 0;
diff --git a/lld/MachO/ExportTrie.cpp b/lld/MachO/ExportTrie.cpp
index 303eda416c23..34478f4c6cf4 100644
--- a/lld/MachO/ExportTrie.cpp
+++ b/lld/MachO/ExportTrie.cpp
@@ -41,6 +41,7 @@
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/Support/LEB128.h"
#include <optional>
+#include <unordered_set>
using namespace llvm;
using namespace lld;
@@ -296,13 +297,19 @@ namespace {
// Parse a serialized trie and invoke a callback for each entry.
class TrieParser {
public:
- TrieParser(const uint8_t *buf, size_t size, const TrieEntryCallback &callback)
- : start(buf), end(start + size), callback(callback) {}
+ TrieParser(const std::string &fileName, const uint8_t *buf, size_t size,
+ const TrieEntryCallback &callback)
+ : fileName(fileName), start(buf), end(start + size), callback(callback) {}
- void parse(const uint8_t *buf, const Twine &cumulativeString);
+ void parse(const uint8_t *buf, const Twine &cumulativeString,
+ std::unordered_set<size_t> &visited);
- void parse() { parse(start, ""); }
+ void parse() {
+ std::unordered_set<size_t> visited;
+ parse(start, "", visited);
+ }
+ const std::string fileName;
const uint8_t *start;
const uint8_t *end;
const TrieEntryCallback &callback;
@@ -310,9 +317,13 @@ public:
} // namespace
-void TrieParser::parse(const uint8_t *buf, const Twine &cumulativeString) {
+void TrieParser::parse(const uint8_t *buf, const Twine &cumulativeString,
+ std::unordered_set<size_t> &visited) {
if (buf >= end)
- fatal("Node offset points outside export section");
+ fatal(fileName + ": export trie node offset points outside export section");
+
+ size_t currentOffset = buf - start;
+ visited.insert(currentOffset);
unsigned ulebSize;
uint64_t terminalSize = decodeULEB128(buf, &ulebSize);
@@ -331,14 +342,18 @@ void TrieParser::parse(const uint8_t *buf, const Twine &cumulativeString) {
buf += substring.size() + 1;
offset = decodeULEB128(buf, &ulebSize);
buf += ulebSize;
- parse(start + offset, cumulativeString + substring);
+ if (visited.find(offset) != visited.end())
+ fatal(fileName + ": export trie child node infinite loop");
+ parse(start + offset, cumulativeString + substring, visited);
}
+
+ visited.erase(currentOffset);
}
-void macho::parseTrie(const uint8_t *buf, size_t size,
- const TrieEntryCallback &callback) {
+void macho::parseTrie(const std::string &fileName, const uint8_t *buf,
+ size_t size, const TrieEntryCallback &callback) {
if (size == 0)
return;
- TrieParser(buf, size, callback).parse();
+ TrieParser(fileName, buf, size, callback).parse();
}
diff --git a/lld/MachO/ExportTrie.h b/lld/MachO/ExportTrie.h
index aa7e3b0d4a14..fa73fc4ef660 100644
--- a/lld/MachO/ExportTrie.h
+++ b/lld/MachO/ExportTrie.h
@@ -41,7 +41,8 @@ private:
using TrieEntryCallback =
llvm::function_ref<void(const llvm::Twine & /*name*/, uint64_t /*flags*/)>;
-void parseTrie(const uint8_t *buf, size_t size, const TrieEntryCallback &);
+void parseTrie(const std::string &fileName, const uint8_t *buf, size_t size,
+ const TrieEntryCallback &);
} // namespace lld::macho
diff --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index 3b3023a94166..442fc608865d 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -1789,12 +1789,13 @@ void DylibFile::parseExportedSymbols(uint32_t offset, uint32_t size) {
auto *buf = reinterpret_cast<const uint8_t *>(mb.getBufferStart());
std::vector<TrieEntry> entries;
// Find all the $ld$* symbols to process first.
- parseTrie(buf + offset, size, [&](const Twine &name, uint64_t flags) {
- StringRef savedName = saver().save(name);
- if (handleLDSymbol(savedName))
- return;
- entries.push_back({savedName, flags});
- });
+ parseTrie(toString(this), buf + offset, size,
+ [&](const Twine &name, uint64_t flags) {
+ StringRef savedName = saver().save(name);
+ if (handleLDSymbol(savedName))
+ return;
+ entries.push_back({savedName, flags});
+ });
// Process the "normal" symbols.
for (TrieEntry &entry : entries) {
diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td
index 4f0602f59812..8ae50f380741 100644
--- a/lld/MachO/Options.td
+++ b/lld/MachO/Options.td
@@ -396,6 +396,9 @@ def dead_strip : Flag<["-"], "dead_strip">,
def interposable : Flag<["-"], "interposable">,
HelpText<"Indirects access to all exported symbols in an image">,
Group<grp_opts>;
+def read_workers : Joined<["--"], "read-workers=">,
+ HelpText<"Approximate number of workers to use to eagerly preload input files content into memory. Use 0 to disable this feature. Default is disabled.">,
+ Group<grp_lld>;
def order_file : Separate<["-"], "order_file">,
MetaVarName<"<file>">,
HelpText<"Layout functions and data according to specification in <file>">,
diff --git a/lld/test/COFF/Inputs/sectionlayout.yaml b/lld/test/COFF/Inputs/sectionlayout.yaml
new file mode 100644
index 000000000000..f5a2a5e333b9
--- /dev/null
+++ b/lld/test/COFF/Inputs/sectionlayout.yaml
@@ -0,0 +1,25 @@
+--- !COFF
+header:
+ Machine: IMAGE_FILE_MACHINE_AMD64
+ Characteristics: []
+sections:
+ - Name: '.text1'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: B82A000000C3
+ - Name: '.text2'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: CC
+ - Name: '.text3'
+ Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ]
+ Alignment: 16
+ SectionData: CC
+symbols:
+ - Name: main
+ Value: 0
+ SectionNumber: 1
+ SimpleType: IMAGE_SYM_TYPE_NULL
+ ComplexType: IMAGE_SYM_DTYPE_FUNCTION
+ StorageClass: IMAGE_SYM_CLASS_EXTERNAL
+...
diff --git a/lld/test/COFF/color-diagnostics.test b/lld/test/COFF/color-diagnostics.test
index 210965d5267c..37583462f44f 100644
--- a/lld/test/COFF/color-diagnostics.test
+++ b/lld/test/COFF/color-diagnostics.test
@@ -1,5 +1,5 @@
# Windows command prompt doesn't support ANSI escape sequences.
-# REQUIRES: shell
+# UNSUPPORTED: system-windows
# RUN: not lld-link -xyz --color-diagnostics /nosuchfile 2>&1 \
# RUN: | FileCheck -check-prefix=COLOR %s
diff --git a/lld/test/COFF/exdllcharacteristics.test b/lld/test/COFF/exdllcharacteristics.test
new file mode 100644
index 000000000000..ef5a90ca9d51
--- /dev/null
+++ b/lld/test/COFF/exdllcharacteristics.test
@@ -0,0 +1,142 @@
+// ---- /cetcompat (image is CET compatible)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetcompat %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKCETCOMPAT %s
+
+CHECKCETCOMPAT: DebugEntry {
+CHECKCETCOMPAT: Characteristics: 0x0
+CHECKCETCOMPAT: Type: ExtendedDLLCharacteristics (0x14)
+CHECKCETCOMPAT: ExtendedCharacteristics [ (0x1)
+CHECKCETCOMPAT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT (0x1)
+CHECKCETCOMPAT: ]
+CHECKCETCOMPAT: RawData (
+CHECKCETCOMPAT: 0000: 01000000 |....|
+CHECKCETCOMPAT: )
+CHECKCETCOMPAT: }
+
+// ---- /cetcompat:no (image is not CET compatible)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetcompat:no %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKNOCETCOMPAT %s
+
+CHECKNOCETCOMPAT-NOT: Type: ExtendedDLLCharacteristics (0x14)
+CHECKNOCETCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT (0x1)
+
+// ---- /cetcompatstrict (CET in strict mode)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetcompatstrict %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKCETCOMPATSTRICT %s
+
+CHECKCETCOMPATSTRICT: DebugEntry {
+CHECKCETCOMPATSTRICT: Characteristics: 0x0
+CHECKCETCOMPATSTRICT: Type: ExtendedDLLCharacteristics (0x14)
+CHECKCETCOMPATSTRICT: ExtendedCharacteristics [ (0x2)
+CHECKCETCOMPATSTRICT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE (0x2)
+CHECKCETCOMPATSTRICT: ]
+CHECKCETCOMPATSTRICT: RawData (
+CHECKCETCOMPATSTRICT: 0000: 02000000 |....|
+CHECKCETCOMPATSTRICT: )
+CHECKCETCOMPATSTRICT: }
+
+// ---- /cetcompatstrict:no (image is not CET strict mode)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetcompatstrict:no %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKNOCETSTRICT %s
+
+CHECKNOCETSTRICT-NOT: Type: ExtendedDLLCharacteristics (0x14)
+CHECKNOCETSTRICT-NOT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE (0x2)
+
+// ---- /cetdynamicapisinproc
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetdynamicapisinproc %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKCETDYNAPI %s
+
+CHECKCETDYNAPI: DebugEntry {
+CHECKCETDYNAPI: Characteristics: 0x0
+CHECKCETDYNAPI: Type: ExtendedDLLCharacteristics (0x14)
+CHECKCETDYNAPI: ExtendedCharacteristics [ (0x8)
+CHECKCETDYNAPI: IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY (0x8)
+CHECKCETDYNAPI: ]
+CHECKCETDYNAPI: RawData (
+CHECKCETDYNAPI: 0000: 08000000 |....|
+CHECKCETDYNAPI: )
+CHECKCETDYNAPI: }
+
+// ---- /cetdynamicapisinproc:no (image is not CET dynamic apis allowed in proc)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetdynamicapisinproc:no %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKNOCETDYNAPI %s
+
+CHECKNOCETDYNAPI-NOT: Type: ExtendedDLLCharacteristics (0x14)
+CHECKNOCETDYNAPI-NOT: Type: IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY (0x8)
+
+// ---- /cetipvalidationrelaxed (image is not CET in context ip validation relaxed mode)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetipvalidationrelaxed %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKCETIPRELAXED %s
+
+CHECKCETIPRELAXED: DebugEntry {
+CHECKCETIPRELAXED: Characteristics: 0x0
+CHECKCETIPRELAXED: Type: ExtendedDLLCharacteristics (0x14)
+CHECKCETIPRELAXED: ExtendedCharacteristics [ (0x4)
+CHECKCETIPRELAXED: IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE (0x4)
+CHECKCETIPRELAXED: ]
+CHECKCETIPRELAXED: RawData (
+CHECKCETIPRELAXED: 0000: 04000000 |....|
+CHECKCETIPRELAXED: )
+CHECKCETIPRELAXED: }
+
+// ---- /cetipvalidationrelaxed:no (image is not CET in IP validation relaxed mode)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /cetipvalidationrelaxed:no %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKNOCETIPRELAXED %s
+
+CHECKNOCETIPRELAXED-NOT: Type: ExtendedDLLCharacteristics (0x14)
+CHECKNOCETIPRELAXED-NOT: Type: IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE (0x4)
+
+// ---- /hotpatchcompatible requires /functionpadmin:6
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /hotpatchcompatible /functionpadmin:6 %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKHOTPATCHABLE %s
+
+CHECKHOTPATCHABLE: DebugEntry {
+CHECKHOTPATCHABLE: Characteristics: 0x0
+CHECKHOTPATCHABLE: Type: ExtendedDLLCharacteristics (0x14)
+CHECKHOTPATCHABLE: ExtendedCharacteristics [ (0x80)
+CHECKHOTPATCHABLE: IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE (0x80)
+CHECKHOTPATCHABLE: ]
+CHECKHOTPATCHABLE: RawData (
+CHECKHOTPATCHABLE: 0000: 80000000 |....|
+CHECKHOTPATCHABLE: )
+CHECKHOTPATCHABLE: }
+
+// ---- /hotpatchcompatible:no (image is not hotpatch compatible)
+RUN: yaml2obj %p/Inputs/ret42.yaml -o %t.obj
+RUN: lld-link /out:%t.exe /entry:main /hotpatchcompatible:no %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKNOHOTPATCHABLE %s
+
+CHECKNOHOTPATCHABLE-NOT: Type: ExtendedDLLCharacteristics (0x14)
+CHECKNOHOTPATCHABLE-NOT: Type: IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE (0x80)
+
+// ---- /hotpatchcompatible more than 6 bytes is accepted
+RUN: lld-link /out:%t.exe /entry:main /hotpatchcompatible /functionpadmin:10 %t.obj
+RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CHECKHOTPATCHABLE2 %s
+
+CHECKHOTPATCHABLE2: DebugEntry {
+CHECKHOTPATCHABLE2: Characteristics: 0x0
+CHECKHOTPATCHABLE2: Type: ExtendedDLLCharacteristics (0x14)
+CHECKHOTPATCHABLE2: ExtendedCharacteristics [ (0x80)
+CHECKHOTPATCHABLE2: IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE (0x80)
+CHECKHOTPATCHABLE2: ]
+CHECKHOTPATCHABLE2: RawData (
+CHECKHOTPATCHABLE2: 0000: 80000000 |....|
+CHECKHOTPATCHABLE2: )
+CHECKHOTPATCHABLE2: }
+
+// ---- /hotpatchcompatible requires at least 6 bytes function padding
+RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /hotpatchcompatible /functionpadmin:5 %t.obj 2>&1 | FileCheck -check-prefix=CHECKHOTPATCHNOT %s
+CHECKHOTPATCHNOT: lld-link: error: /hotpatchcompatible: requires at least 6 bytes of /functionpadmin
+
+// ---- /hotpatchcompatible requires at least 6 bytes function padding -- without /functionpadmin should raise an error
+RUN: env LLD_IN_TEST=1 not lld-link /out:%t.exe /entry:main /hotpatchcompatible %t.obj 2>&1 | FileCheck -check-prefix=CHECKHOTPATCHNOT2 %s
+CHECKHOTPATCHNOT2: lld-link: error: /hotpatchcompatible: requires at least 6 bytes of /functionpadmin
diff --git a/lld/test/COFF/linkrepro-res.test b/lld/test/COFF/linkrepro-res.test
index cf0aa1636ce2..fe564e977611 100644
--- a/lld/test/COFF/linkrepro-res.test
+++ b/lld/test/COFF/linkrepro-res.test
@@ -1,4 +1,6 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
+# Unsupported on Windows due to maximum path length limitations.
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t.dir
# RUN: mkdir -p %t.dir/build
diff --git a/lld/test/COFF/linkrepro.test b/lld/test/COFF/linkrepro.test
index a5779a9ec82e..b1195cccb0e8 100644
--- a/lld/test/COFF/linkrepro.test
+++ b/lld/test/COFF/linkrepro.test
@@ -1,4 +1,6 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
+# Unsupported on Windows due to maximum path length limitations.
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t.dir
# RUN: split-file %s %t.dir
diff --git a/lld/test/COFF/lto-cache-warnings.ll b/lld/test/COFF/lto-cache-warnings.ll
index debec53d47fe..488e4bb68fb2 100644
--- a/lld/test/COFF/lto-cache-warnings.ll
+++ b/lld/test/COFF/lto-cache-warnings.ll
@@ -1,4 +1,4 @@
-; REQUIRES: x86, shell
+; REQUIRES: x86
; RUN: opt -module-hash -module-summary %s -o %t.o
; RUN: opt -module-hash -module-summary %p/Inputs/lto-cache.ll -o %t2.o
@@ -20,13 +20,17 @@
;; Get the total size of created cache files.
; RUN: rm -rf %t && mkdir %t && cd %t
; RUN: lld-link /lldltocache:%t /lldltocachepolicy:prune_interval=0s:cache_size_bytes=32k /out:%t3 /entry:main %t2.o %t.o 2>&1
-; RUN: %python -c "import os, sys; print(sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')))" > %t.size.txt
+; RUN: %python -c "import os, sys; size=sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')); print(size+5); print(size-5)" > %t.size.txt
;; Case 2: If the total size of the cache files created by the current link job is less than the maximum size for the cache directory in bytes, there is no warning.
-; RUN: lld-link /verbose /lldltocache:%t /lldltocachepolicy:prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) + 5)) /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s --implicit-check-not=warning:
+; RUN: echo -n "/lldltocachepolicy:prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: head -1 %t.size.txt >> %t.response
+; RUN: lld-link /verbose /lldltocache:%t @%t.response /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s --implicit-check-not=warning:
;; Case 3: If the total size of the cache files created by the current link job exceeds the maximum size for the cache directory in bytes, a warning is given.
-; RUN: lld-link /verbose /lldltocache:%t /lldltocachepolicy:prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) - 5)) /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s --check-prefix=SIZE
+; RUN: echo -n "/lldltocachepolicy:prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: tail -1 %t.size.txt >> %t.response
+; RUN: lld-link /verbose /lldltocache:%t @%t.response /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s --check-prefix=SIZE
;; Check emit two warnings if pruning happens due to reach both the size and number limits.
; RUN: lld-link /lldltocache:%t /lldltocachepolicy:prune_interval=0s:cache_size_files=1:cache_size_bytes=1 /out:%t3 /entry:main %t2.o %t.o 2>&1 | FileCheck %s --check-prefixes=NUM,SIZE
diff --git a/lld/test/COFF/options.test b/lld/test/COFF/options.test
index 0dd889042869..c21ae9685a85 100644
--- a/lld/test/COFF/options.test
+++ b/lld/test/COFF/options.test
@@ -50,16 +50,6 @@ NXCOMPAT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
# RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=NONXCOMPAT %s
NONXCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_NX_COMPAT
-# RUN: lld-link /out:%t.exe /entry:main /cetcompat %t.obj
-# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CETCOMPAT %s
-CETCOMPAT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT
-
-# RUN: lld-link /out:%t.exe /entry:main %t.obj
-# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETCOMPAT %s
-# RUN: lld-link /out:%t.exe /entry:main /cetcompat:no %t.obj
-# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETCOMPAT %s
-NONCETCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT
-
# RUN: lld-link /out:%t.exe /entry:main /swaprun:CD %t.obj
# RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=SWAPCD %s
# RUN: lld-link /out:%t.exe /entry:main /swaprun:cd,net %t.obj
diff --git a/lld/test/COFF/pdb-type-server-simple.test b/lld/test/COFF/pdb-type-server-simple.test
index 93d66cde4f71..693bd9b482da 100644
--- a/lld/test/COFF/pdb-type-server-simple.test
+++ b/lld/test/COFF/pdb-type-server-simple.test
@@ -106,17 +106,18 @@ CHECK-LABEL: Mod 0002 | `* Linker *`:
SUMMARY: Summary
SUMMARY-NEXT: --------------------------------------------------------------------------------
-SUMMARY-NEXT: 2 Input OBJ files (expanded from all cmd-line inputs)
-SUMMARY-NEXT: 1 PDB type server dependencies
-SUMMARY-NEXT: 0 Precomp OBJ dependencies
-SUMMARY-NEXT: 25 Input type records
-SUMMARY-NEXT: 868 Input type records bytes
-SUMMARY-NEXT: 9 Merged TPI records
-SUMMARY-NEXT: 16 Merged IPI records
-SUMMARY-NEXT: 3 Output PDB strings
-SUMMARY-NEXT: 4 Global symbol records
-SUMMARY-NEXT: 14 Module symbol records
-SUMMARY-NEXT: 2 Public symbol records
+SUMMARY-NEXT: 2 Input OBJ files (expanded from all cmd-line inputs)
+SUMMARY-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
+SUMMARY-NEXT: 1 PDB type server dependencies
+SUMMARY-NEXT: 0 Precomp OBJ dependencies
+SUMMARY-NEXT: 25 Input debug type records
+SUMMARY-NEXT: 868 Size of all input debug type records, in bytes
+SUMMARY-NEXT: 9 Merged TPI records
+SUMMARY-NEXT: 16 Merged IPI records
+SUMMARY-NEXT: 3 Output PDB strings
+SUMMARY-NEXT: 4 Global symbol records
+SUMMARY-NEXT: 14 Module symbol records
+SUMMARY-NEXT: 2 Public symbol records
SUMMARY: Top 10 types responsible for the most TPI input:
SUMMARY-NEXT: index total bytes count size
diff --git a/lld/test/COFF/precomp-link-samename.test b/lld/test/COFF/precomp-link-samename.test
index f44abf289d86..c80774c5d539 100644
--- a/lld/test/COFF/precomp-link-samename.test
+++ b/lld/test/COFF/precomp-link-samename.test
@@ -12,9 +12,10 @@ CHECK-NOT: LF_ENDPRECOMP
SUMMARY: Summary
SUMMARY-NEXT: --------------------------------------------------------------------------------
-SUMMARY-NEXT: 4 Input OBJ files (expanded from all cmd-line inputs)
-SUMMARY-NEXT: 0 PDB type server dependencies
-SUMMARY-NEXT: 2 Precomp OBJ dependencies
+SUMMARY-NEXT: 4 Input OBJ files (expanded from all cmd-line inputs)
+SUMMARY-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
+SUMMARY-NEXT: 0 PDB type server dependencies
+SUMMARY-NEXT: 2 Precomp OBJ dependencies
// precompa/precomp.cpp
#include "precomp.h"
diff --git a/lld/test/COFF/precomp-link.test b/lld/test/COFF/precomp-link.test
index ce90603d0bb8..389747920ffc 100644
--- a/lld/test/COFF/precomp-link.test
+++ b/lld/test/COFF/precomp-link.test
@@ -3,6 +3,9 @@ RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /debug:ghash /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY
RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY-NODEBUG
+RUN: lld-link %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj %S/Inputs/precomp.obj /nodefaultlib /entry:main /out:%t.exe /opt:ref /opt:icf /summary | FileCheck %s -check-prefix SUMMARY-NODEBUG
+
RUN: lld-link %S/Inputs/precomp.obj %S/Inputs/precomp-a.obj %S/Inputs/precomp-b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb /out:%t.exe /opt:ref /opt:icf
RUN: llvm-pdbutil dump -types %t.pdb | FileCheck %s
@@ -59,17 +62,33 @@ CHECK-NOT: LF_ENDPRECOMP
SUMMARY: Summary
SUMMARY-NEXT: --------------------------------------------------------------------------------
-SUMMARY-NEXT: 3 Input OBJ files (expanded from all cmd-line inputs)
-SUMMARY-NEXT: 0 PDB type server dependencies
-SUMMARY-NEXT: 1 Precomp OBJ dependencies
-SUMMARY-NEXT: 1066 Input type records
-SUMMARY-NEXT: 55968 Input type records bytes
-SUMMARY-NEXT: 874 Merged TPI records
-SUMMARY-NEXT: 170 Merged IPI records
-SUMMARY-NEXT: 5 Output PDB strings
-SUMMARY-NEXT: 167 Global symbol records
-SUMMARY-NEXT: 20 Module symbol records
-SUMMARY-NEXT: 3 Public symbol records
+SUMMARY-NEXT: 3 Input OBJ files (expanded from all cmd-line inputs)
+SUMMARY-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
+SUMMARY-NEXT: 0 PDB type server dependencies
+SUMMARY-NEXT: 1 Precomp OBJ dependencies
+SUMMARY-NEXT: 1,066 Input debug type records
+SUMMARY-NEXT: 55,968 Size of all input debug type records, in bytes
+SUMMARY-NEXT: 874 Merged TPI records
+SUMMARY-NEXT: 170 Merged IPI records
+SUMMARY-NEXT: 5 Output PDB strings
+SUMMARY-NEXT: 167 Global symbol records
+SUMMARY-NEXT: 20 Module symbol records
+SUMMARY-NEXT: 3 Public symbol records
+
+SUMMARY-NODEBUG: Summary
+SUMMARY-NODEBUG-NEXT: --------------------------------------------------------------------------------
+SUMMARY-NODEBUG-NEXT: 3 Input OBJ files (expanded from all cmd-line inputs)
+SUMMARY-NODEBUG-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
+SUMMARY-NODEBUG-NEXT: 0 PDB type server dependencies
+SUMMARY-NODEBUG-NEXT: 0 Precomp OBJ dependencies
+SUMMARY-NODEBUG-NEXT: 0 Input debug type records
+SUMMARY-NODEBUG-NEXT: 0 Size of all input debug type records, in bytes
+SUMMARY-NODEBUG-NEXT: 0 Merged TPI records
+SUMMARY-NODEBUG-NEXT: 0 Merged IPI records
+SUMMARY-NODEBUG-NEXT: 0 Output PDB strings
+SUMMARY-NODEBUG-NEXT: 0 Global symbol records
+SUMMARY-NODEBUG-NEXT: 0 Module symbol records
+SUMMARY-NODEBUG-NEXT: 0 Public symbol records
// precomp.h
#pragma once
diff --git a/lld/test/COFF/precomp-summary-fail.test b/lld/test/COFF/precomp-summary-fail.test
index 5ebba9a1d3c7..5568316ff63c 100644
--- a/lld/test/COFF/precomp-summary-fail.test
+++ b/lld/test/COFF/precomp-summary-fail.test
@@ -11,14 +11,15 @@ RUN: /dll /out:%t.dll /debug /summary | FileCheck %s -check-prefix SUMMARY
SUMMARY: Summary
SUMMARY-NEXT: --------------------------------------------------------------------------------
-SUMMARY-NEXT: 2 Input OBJ files (expanded from all cmd-line inputs)
-SUMMARY-NEXT: 0 PDB type server dependencies
-SUMMARY-NEXT: 1 Precomp OBJ dependencies
-SUMMARY-NEXT: 8 Input type records
-SUMMARY-NEXT: 232 Input type records bytes
-SUMMARY-NEXT: 3 Merged TPI records
-SUMMARY-NEXT: 2 Merged IPI records
-SUMMARY-NEXT: 1 Output PDB strings
-SUMMARY-NEXT: 0 Global symbol records
-SUMMARY-NEXT: 4 Module symbol records
-SUMMARY-NEXT: 0 Public symbol records
+SUMMARY-NEXT: 2 Input OBJ files (expanded from all cmd-line inputs)
+SUMMARY-NEXT: Size of all consumed OBJ files (non-lazy), in bytes
+SUMMARY-NEXT: 0 PDB type server dependencies
+SUMMARY-NEXT: 1 Precomp OBJ dependencies
+SUMMARY-NEXT: 8 Input debug type records
+SUMMARY-NEXT: 232 Size of all input debug type records, in bytes
+SUMMARY-NEXT: 3 Merged TPI records
+SUMMARY-NEXT: 2 Merged IPI records
+SUMMARY-NEXT: 1 Output PDB strings
+SUMMARY-NEXT: 0 Global symbol records
+SUMMARY-NEXT: 4 Module symbol records
+SUMMARY-NEXT: 0 Public symbol records
diff --git a/lld/test/COFF/reloc-discarded.s b/lld/test/COFF/reloc-discarded.s
index 667df0faeb5a..404f7978f726 100644
--- a/lld/test/COFF/reloc-discarded.s
+++ b/lld/test/COFF/reloc-discarded.s
@@ -1,5 +1,5 @@
# REQUIRES: x86
-# RUN: echo -e '.section .bss,"bw",discard,main_global\n.global main_global\n main_global:\n .long 0' | \
+# RUN: printf '.section .bss,"bw",discard,main_global\n.global main_global\n main_global:\n .long 0' | \
# RUN: llvm-mc - -filetype=obj -o %t1.obj -triple x86_64-windows-msvc
# RUN: llvm-mc %s -filetype=obj -o %t2.obj -triple x86_64-windows-msvc
diff --git a/lld/test/COFF/reloc-undefined-weak.s b/lld/test/COFF/reloc-undefined-weak.s
new file mode 100644
index 000000000000..dc0a230c37d4
--- /dev/null
+++ b/lld/test/COFF/reloc-undefined-weak.s
@@ -0,0 +1,52 @@
+// REQUIRES: x86
+
+// Check that base-relocations for unresolved weak symbols will be omitted.
+
+// RUN: rm -rf %t.dir && split-file %s %t.dir && cd %t.dir
+// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw main.s -o main.obj
+// RUN: llvm-mc -filetype=obj -triple=x86_64-mingw other.s -o other.obj
+
+// RUN: lld-link -lldmingw -machine:x64 -dll -out:other.dll other.obj -noentry -export:foo -implib:other.lib
+// RUN: lld-link -lldmingw -machine:x64 -out:main.exe main.obj other.lib -entry:entry -wrap:foo -debug:symtab
+// RUN: llvm-readobj --sections --symbols --coff-imports --coff-basereloc main.exe | FileCheck %s --implicit-check-not=other.dll
+
+// CHECK: Number: 3
+// CHECK-NEXT: Name: .data
+// CHECK-NEXT: VirtualSize:
+// CHECK-NEXT: VirtualAddress: 0x[[#%x,SECTOP:0x3000]]
+// CHECK: Name: ref_foo
+// CHECK-NEXT: Value: [[#%d,SYMVAL:]]
+// CHECK: BaseReloc [
+// CHECK-NOT: Address: 0x[[#%x,SECTOP+SYMVAL]]
+
+#--- main.s
+.global entry
+entry:
+ movq ref_foo(%rip), %rax
+ call *%rax
+
+.global __wrap_foo
+__wrap_foo:
+ ret
+
+.data
+.global ref_foo
+.p2align 3
+ref_foo:
+ .quad __real_foo
+
+.globl _pei386_runtime_relocator
+_pei386_runtime_relocator:
+ movl __RUNTIME_PSEUDO_RELOC_LIST__(%rip), %eax
+ movl __RUNTIME_PSEUDO_RELOC_LIST_END__(%rip), %eax
+
+.weak __real_foo
+.addrsig
+.addrsig_sym __real_foo
+.addrsig_sym ref_foo
+
+#--- other.s
+.global foo
+
+foo:
+ ret
diff --git a/lld/test/COFF/sectionlayout.test b/lld/test/COFF/sectionlayout.test
new file mode 100644
index 000000000000..109f35d992b1
--- /dev/null
+++ b/lld/test/COFF/sectionlayout.test
@@ -0,0 +1,129 @@
+RUN: yaml2obj %p/Inputs/sectionlayout.yaml -o %t.obj
+
+## Error on non-exist input layout file
+RUN: not lld-link /entry:main /sectionlayout:doesnotexist.txt %t.obj
+
+## Order in 1 -> 3 -> 2
+RUN: echo ".text1" > %t.layout.txt
+RUN: echo ".text3" >> %t.layout.txt
+RUN: echo ".text2" >> %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+## While /sectionlayout:abc is valid, /sectionlayout:@abc is also accepted (to align with MS link.exe)
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:@%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+## Ensure tokens after section name is ignored (for now, to align with MS link.exe)
+RUN: echo ".text1 ALIGN=1" > %t.layout.txt
+RUN: echo ".text3" >> %t.layout.txt
+RUN: echo ".text2" >> %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:@%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK1 %s
+
+CHECK1: Sections [
+CHECK1: Section {
+CHECK1: Number: 1
+CHECK1: Name: .text1
+CHECK1: }
+CHECK1: Section {
+CHECK1: Number: 2
+CHECK1: Name: .text3
+CHECK1: }
+CHECK1: Section {
+CHECK1: Number: 3
+CHECK1: Name: .text2
+CHECK1: }
+CHECK1: ]
+
+## Order in 3 -> 2 -> 1
+RUN: echo ".text3" > %t.layout.txt
+RUN: echo ".text2" >> %t.layout.txt
+RUN: echo ".text1" >> %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+CHECK2: Sections [
+CHECK2: Section {
+CHECK2: Number: 1
+CHECK2: Name: .text3
+CHECK2: }
+CHECK2: Section {
+CHECK2: Number: 2
+CHECK2: Name: .text2
+CHECK2: }
+CHECK2: Section {
+CHECK2: Number: 3
+CHECK2: Name: .text1
+CHECK2: }
+CHECK2: ]
+
+## Put non-exisist section in layout file has no effect; original order is respected
+RUN: echo "notexist" > %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK3 %s
+
+## Empty layout file has no effect
+RUN: echo "" > %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK3 %s
+
+## Empty layout file has no effect
+RUN: echo " " > %t.layout.txt
+RUN: echo " " >> %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK3 %s
+
+CHECK3: Sections [
+CHECK3: Section {
+CHECK3: Number: 1
+CHECK3: Name: .text1
+CHECK3: }
+CHECK3: Section {
+CHECK3: Number: 2
+CHECK3: Name: .text2
+CHECK3: }
+CHECK3: Section {
+CHECK3: Number: 3
+CHECK3: Name: .text3
+CHECK3: }
+CHECK3: ]
+
+## Order in 3 -> 1, but 2 remains unspecified
+RUN: echo ".text3" > %t.layout.txt
+RUN: echo ".text1" >> %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK4 %s
+
+CHECK4: Sections [
+CHECK4: Section {
+CHECK4: Number: 1
+CHECK4: Name: .text3
+CHECK4: }
+CHECK4: Section {
+CHECK4: Number: 2
+CHECK4: Name: .text1
+CHECK4: }
+CHECK4: Section {
+CHECK4: Number: 3
+CHECK4: Name: .text2
+CHECK4: }
+CHECK4: ]
+
+## Order in 3 -> 2, but 1 remains unspecified.
+## 1 should be the first, as the original order (1 -> 2 -> 3) is respected
+RUN: echo ".text3" > %t.layout.txt
+RUN: echo ".text2" >> %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK2 %s
+
+## Order in 3 -> 2 -> 1, multiple specification has no effect (the first one is used)
+RUN: echo ".text3" > %t.layout.txt
+RUN: echo ".text3" >> %t.layout.txt
+RUN: echo ".text3" >> %t.layout.txt
+RUN: echo ".text2" >> %t.layout.txt
+RUN: echo ".text2" >> %t.layout.txt
+RUN: echo ".text1" >> %t.layout.txt
+RUN: echo ".text3" >> %t.layout.txt
+RUN: lld-link /out:%t.exe /entry:main /sectionlayout:%t.layout.txt %t.obj
+RUN: llvm-readobj --sections %t.exe | FileCheck -check-prefix=CHECK2 %s
diff --git a/lld/test/COFF/wrap-dllimport.s b/lld/test/COFF/wrap-dllimport.s
index d7662b29fdc7..a26e43b69896 100644
--- a/lld/test/COFF/wrap-dllimport.s
+++ b/lld/test/COFF/wrap-dllimport.s
@@ -1,42 +1,60 @@
// REQUIRES: x86
// Check that we can wrap a dllimported symbol, so that references to
-// __imp_<symbol> gets redirected to a defined local import instead.
+// __imp_<symbol> gets redirected to a symbol that already exists or a defined
+// local import instead.
// RUN: split-file %s %t.dir
// RUN: llvm-mc -filetype=obj -triple=i686-win32-gnu %t.dir/main.s -o %t.main.obj
// RUN: llvm-mc -filetype=obj -triple=i686-win32-gnu %t.dir/other.s -o %t.other.obj
-// RUN: lld-link -dll -out:%t.dll %t.other.obj -noentry -safeseh:no -export:foo -implib:%t.lib
-// RUN: lld-link -out:%t.exe %t.main.obj %t.lib -entry:entry -subsystem:console -debug:symtab -safeseh:no -wrap:foo -lldmap:%t.map
+// RUN: lld-link -dll -out:%t.dll %t.other.obj -noentry -safeseh:no -export:foo -export:bar -implib:%t.lib
+// RUN: lld-link -out:%t.exe %t.main.obj %t.lib -entry:entry -subsystem:console -debug:symtab -safeseh:no -wrap:foo -wrap:bar -lldmap:%t.map
// RUN: llvm-objdump -s -d --print-imm-hex %t.exe | FileCheck %s
// CHECK: Contents of section .rdata:
-// CHECK-NEXT: 402000 06104000
+// CHECK-NEXT: 402000 0c104000
// CHECK: Disassembly of section .text:
// CHECK-EMPTY:
// CHECK: 00401000 <_entry>:
// CHECK-NEXT: 401000: ff 25 00 20 40 00 jmpl *0x402000
+// CHECK-NEXT: 401006: ff 25 00 00 00 00 jmpl *0x0
// CHECK-EMPTY:
-// CHECK-NEXT: 00401006 <___wrap_foo>:
-// CHECK-NEXT: 401006: c3 retl
+// CHECK-NEXT: 0040100c <___wrap_foo>:
+// CHECK-NEXT: 40100c: c3 retl
+// CHECK-EMPTY:
+// CHECK-NEXT: 0040100d <___wrap_bar>:
+// CHECK-NEXT: 40100d: c3 retl
-// The jmpl instruction in _entry points at an address in 0x402000,
+// The first jmpl instruction in _entry points at an address in 0x402000,
// which is the first 4 bytes of the .rdata section (above), which is a
// pointer that points at ___wrap_foo.
+// The second jmpl instruction in _entry points to null because the referenced
+// symbol `__imp____wrap_bar` is declared as a weak reference to prevent pull a
+// reference from an external DLL.
+
#--- main.s
.global _entry
_entry:
jmpl *__imp__foo
+ jmpl *__imp__bar
.global ___wrap_foo
___wrap_foo:
ret
+.weak __imp____wrap_bar
+.global ___wrap_bar
+___wrap_bar:
+ ret
+
#--- other.s
.global _foo
-
_foo:
ret
+
+.global _bar
+_bar:
+ ret
diff --git a/lld/test/ELF/arm-exidx-range.s b/lld/test/ELF/arm-exidx-range.s
index 480910997358..b955b39e29f5 100644
--- a/lld/test/ELF/arm-exidx-range.s
+++ b/lld/test/ELF/arm-exidx-range.s
@@ -1,4 +1,6 @@
-// REQUIRES: arm, shell
+// REQUIRES: arm
+// Fails for unclear reasons on 32-bit windows
+// UNSUPPORTED: system-windows
// RUN: llvm-mc --arm-add-build-attributes --triple=armv7a-linux-gnueabihf -filetype=obj %s -o %t.o
// RUN: echo "SECTIONS { \
// RUN: . = 0x80000000; \
diff --git a/lld/test/ELF/color-diagnostics.test b/lld/test/ELF/color-diagnostics.test
index 6d87b1130bee..ad201fada283 100644
--- a/lld/test/ELF/color-diagnostics.test
+++ b/lld/test/ELF/color-diagnostics.test
@@ -1,5 +1,5 @@
# Windows command prompt doesn't support ANSI escape sequences.
-# REQUIRES: shell
+# UNSUPPORTED: system-windows
# RUN: not ld.lld -xyz --color-diagnostics /nosuchfile 2>&1 \
# RUN: | FileCheck -check-prefix=COLOR %s
diff --git a/lld/test/ELF/emulation-hexagon.s b/lld/test/ELF/emulation-hexagon.s
index 5bdd88941c26..df692ef99ef5 100644
--- a/lld/test/ELF/emulation-hexagon.s
+++ b/lld/test/ELF/emulation-hexagon.s
@@ -23,7 +23,7 @@
# CHECK-NEXT: Type: EXEC (Executable file)
# CHECK-NEXT: Machine: Qualcomm Hexagon
# CHECK-NEXT: Version: 0x1
-# CHECK-NEXT: Entry point address: 0x200B4
+# CHECK-NEXT: Entry point address: 0x200b4
# CHECK-NEXT: Start of program headers: 52 (bytes into file)
# CHECK-NEXT: Start of section headers:
# CHECK-NEXT: Flags: 0x73
diff --git a/lld/test/ELF/file-access.s b/lld/test/ELF/file-access.s
index 5a9e53b11140..8658f774682f 100644
--- a/lld/test/ELF/file-access.s
+++ b/lld/test/ELF/file-access.s
@@ -1,4 +1,5 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
+# UNSUPPORTED: system-windows
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
# RUN: ld.lld -r %t.o -o %t1.o
diff --git a/lld/test/ELF/linkerscript/invalid.test b/lld/test/ELF/linkerscript/invalid.test
index 73b761ce4d57..cb5e52c38dcc 100644
--- a/lld/test/ELF/linkerscript/invalid.test
+++ b/lld/test/ELF/linkerscript/invalid.test
@@ -5,7 +5,7 @@
## We can't write quoted strings that are interpreted the same way
## by all echo commands. So, we don't want to run this on Windows.
-# REQUIRES: shell
+# UNSUPPORTED: system-windows
# RUN: mkdir -p %t.dir
diff --git a/lld/test/ELF/loongarch-call36.s b/lld/test/ELF/loongarch-call36.s
index b593fdf1f604..5cc0f2f3827c 100644
--- a/lld/test/ELF/loongarch-call36.s
+++ b/lld/test/ELF/loongarch-call36.s
@@ -8,14 +8,14 @@
## hi20 = target - pc + (1 << 17) >> 18 = 0x60020 - 0x20010 + 0x20000 >> 18 = 1
## lo18 = target - pc & (1 << 18) - 1 = 0x60020 - 0x20010 & 0x3ffff = 16
# EXE1: 20010: pcaddu18i $t0, 1
-# EXE1-NEXT: 20014: jirl $zero, $t0, 16
+# EXE1-NEXT: 20014: jirl $zero, $t0, 16 <foo>
# RUN: ld.lld %t/a.o --section-start=.text=0x20010 --section-start=.sec.foo=0x40020 -o %t/exe2
# RUN: llvm-objdump --no-show-raw-insn -d %t/exe2 | FileCheck --match-full-lines %s --check-prefix=EXE2
## hi20 = target - pc + (1 << 17) >> 18 = 0x40020 - 0x20010 + 0x20000 >> 18 = 1
## lo18 = target - pc & (1 << 18) - 1 = 0x40020 - 0x20010 & 0x3ffff = -131056
# EXE2: 20010: pcaddu18i $t0, 1
-# EXE2-NEXT: 20014: jirl $zero, $t0, -131056
+# EXE2-NEXT: 20014: jirl $zero, $t0, -131056 <foo>
# RUN: ld.lld %t/a.o -shared -T %t/a.t -o %t/a.so
# RUN: llvm-readelf -x .got.plt %t/a.so | FileCheck --check-prefix=GOTPLT %s
@@ -34,7 +34,7 @@
## hi20 = foo@plt - pc + (1 << 17) >> 18 = 0x1234520 - 0x1274670 + 0x20000 >> 18 = -1
## lo18 = foo@plt - pc & (1 << 18) - 1 = 0x1234520 - 0x1274670 & 0x3ffff = -336
# SO-NEXT: pcaddu18i $t0, -1{{$}}
-# SO-NEXT: jirl $zero, $t0, -336{{$}}
+# SO-NEXT: jirl $zero, $t0, -336 <.plt+0x20>{{$}}
# GOTPLT: section '.got.plt':
# GOTPLT-NEXT: 0x01274730 00000000 00000000 00000000 00000000
diff --git a/lld/test/ELF/lto/cache-warnings.ll b/lld/test/ELF/lto/cache-warnings.ll
index d0224d5426ff..711d18e80910 100644
--- a/lld/test/ELF/lto/cache-warnings.ll
+++ b/lld/test/ELF/lto/cache-warnings.ll
@@ -1,4 +1,4 @@
-; REQUIRES: x86, shell
+; REQUIRES: x86
; UNSUPPORTED: main-run-twice
; RUN: opt -module-hash -module-summary %s -o %t.o
@@ -21,13 +21,17 @@
;; Get the total size of created cache files.
; RUN: rm -rf %t && mkdir %t && cd %t
; RUN: ld.lld --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=32k %t2.o %t.o -o %t3 2>&1
-; RUN: %python -c "import os, sys; print(sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')))" > %t.size.txt
+; RUN: %python -c "import os, sys; size=sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')); print(size+5); print(size-5)" > %t.size.txt
;; Case 2: If the total size of the cache files created by the current link job is less than the maximum size for the cache directory in bytes, there is no warning.
-; RUN: ld.lld --verbose --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) + 5)) %t2.o %t.o -o %t3 2>&1 | FileCheck %s --implicit-check-not=warning:
+; RUN: echo -n "--thinlto-cache-policy=prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: head -1 %t.size.txt >> %t.response
+; RUN: ld.lld --verbose --thinlto-cache-dir=%t @%t.response %t2.o %t.o -o %t3 2>&1 | FileCheck %s --implicit-check-not=warning:
;; Case 3: If the total size of the cache files created by the current link job exceeds the maximum size for the cache directory in bytes, a warning is given.
-; RUN: ld.lld --verbose --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) - 5)) %t2.o %t.o -o %t3 2>&1 | FileCheck %s --check-prefixes=SIZE,WARN
+; RUN: echo -n "--thinlto-cache-policy=prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: tail -1 %t.size.txt >> %t.response
+; RUN: ld.lld --verbose --thinlto-cache-dir=%t @%t.response %t2.o %t.o -o %t3 2>&1 | FileCheck %s --check-prefixes=SIZE,WARN
;; Check emit two warnings if pruning happens due to reach both the size and number limits.
; RUN: ld.lld --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_files=1:cache_size_bytes=1 %t2.o %t.o -o %t3 2>&1 | FileCheck %s --check-prefixes=NUM,SIZE,WARN
diff --git a/lld/test/ELF/lto/comdat-nodeduplicate.ll b/lld/test/ELF/lto/comdat-nodeduplicate.ll
index 13d4ab394813..928da5c82e51 100644
--- a/lld/test/ELF/lto/comdat-nodeduplicate.ll
+++ b/lld/test/ELF/lto/comdat-nodeduplicate.ll
@@ -1,4 +1,4 @@
-; REQUIRES: x86, shell
+; REQUIRES: x86
;; Keep __profd_foo in a nodeduplicate comdat, despite a comdat of the same name
;; in a previous object file.
@@ -36,19 +36,25 @@
; RUN: ld.lld --thinlto-index-only --save-temps -u foo %t/a.bc %t/b.bc -o %t/ab
; RUN: FileCheck %s --check-prefix=RESOL_AB < %t/ab.resolution.txt
-; RUN: (llvm-dis < %t/b.bc && llvm-dis < %t/b.bc.thinlto.bc) | FileCheck %s --check-prefix=IR_AB
+; RUN: llvm-dis < %t/b.bc > %t.out
+; RUN: llvm-dis < %t/b.bc.thinlto.bc >> %t.out
+; RUN: FileCheck %s --check-prefix=IR_AB --input-file %t.out
; RUN: ld.lld -u foo %t/a.bc %t/b.bc -o %t/ab
; RUN: llvm-readelf -x .data %t/ab | FileCheck %s --check-prefix=DATA
; RUN: ld.lld --thinlto-index-only --save-temps -u foo %t/a.bc --start-lib %t/b.bc --end-lib -o %t/ab
; RUN: FileCheck %s --check-prefix=RESOL_AB < %t/ab.resolution.txt
-; RUN: (llvm-dis < %t/b.bc && llvm-dis < %t/b.bc.thinlto.bc) | FileCheck %s --check-prefix=IR_AB
+; RUN: llvm-dis < %t/b.bc > %t.out
+; RUN: llvm-dis < %t/b.bc.thinlto.bc >> %t.out
+; RUN: FileCheck %s --check-prefix=IR_AB --input-file %t.out
; RUN: ld.lld -u foo %t/a.bc --start-lib %t/b.bc --end-lib -o %t/ab
; RUN: llvm-readelf -x .data %t/ab | FileCheck %s --check-prefix=DATA
; RUN: ld.lld --thinlto-index-only --save-temps -u foo -u c %t/a.bc --start-lib %t/b.bc %t/c.bc --end-lib -o %t/abc
; RUN: FileCheck %s --check-prefix=RESOL_ABC < %t/abc.resolution.txt
-; RUN: (llvm-dis < %t/b.bc && llvm-dis < %t/b.bc.thinlto.bc) | FileCheck %s --check-prefix=IR_ABC
+; RUN: llvm-dis < %t/b.bc > %t.out
+; RUN: llvm-dis < %t/b.bc.thinlto.bc >> %t.out
+; RUN: FileCheck %s --check-prefix=IR_ABC --input-file %t.out
; RUN: ld.lld -u foo %t/a.bc --start-lib %t/b.bc %t/c.bc --end-lib -o %t/abc
; RUN: llvm-readelf -x .data %t/abc | FileCheck %s --check-prefix=DATA
diff --git a/lld/test/ELF/lto/resolution-err.ll b/lld/test/ELF/lto/resolution-err.ll
index f9855abaff32..6bc0bfc2f200 100644
--- a/lld/test/ELF/lto/resolution-err.ll
+++ b/lld/test/ELF/lto/resolution-err.ll
@@ -1,5 +1,5 @@
; UNSUPPORTED: system-windows
-; REQUIRES: shell, non-root-user
+; REQUIRES: non-root-user
; RUN: llvm-as %s -o %t.bc
; RUN: touch %t.resolution.txt
; RUN: chmod u-w %t.resolution.txt
diff --git a/lld/test/ELF/msp430.s b/lld/test/ELF/msp430.s
index 39079ed59697..732af387d261 100644
--- a/lld/test/ELF/msp430.s
+++ b/lld/test/ELF/msp430.s
@@ -1,6 +1,6 @@
; REQUIRES: msp430
; RUN: llvm-mc -filetype=obj -triple=msp430-elf -o %t1.o %s
-; RUN: echo -e '.global _start\n _start: nop' | llvm-mc -filetype=obj -triple=msp430-elf -o %t2.o -
+; RUN: printf '.global _start\n _start: nop' | llvm-mc -filetype=obj -triple=msp430-elf -o %t2.o -
; RUN: ld.lld -o %t.exe --image-base=0x1000 --Tdata=0x2000 --Ttext=0x8000 --defsym=_byte=0x21 -z separate-code %t2.o %t1.o
; RUN: llvm-objdump -s -d %t.exe | FileCheck %s
diff --git a/lld/test/ELF/weak-shared-gc.s b/lld/test/ELF/weak-shared-gc.s
index 833d7b7ab409..2bba6341d750 100644
--- a/lld/test/ELF/weak-shared-gc.s
+++ b/lld/test/ELF/weak-shared-gc.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
-# RUN: echo -e '.globl __cxa_finalize\n__cxa_finalize:' | \
+# RUN: printf '.globl __cxa_finalize\n__cxa_finalize:' | \
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
# RUN: ld.lld %t2.o -o %t2.so -shared
# RUN: ld.lld %t1.o --as-needed --gc-sections %t2.so -o %t
diff --git a/lld/test/ELF/weak-undef-lib.s b/lld/test/ELF/weak-undef-lib.s
index 0ff1bc755f07..8f89c6f421ad 100644
--- a/lld/test/ELF/weak-undef-lib.s
+++ b/lld/test/ELF/weak-undef-lib.s
@@ -1,6 +1,6 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o
-# RUN: echo -e '.globl foo\nfoo: ret' | \
+# RUN: printf '.globl foo\nfoo: ret' | \
# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o
# RUN: ld.lld -shared -o %t.so %t1.o --start-lib %t2.o
diff --git a/lld/test/MachO/cgdata-generate-merge.s b/lld/test/MachO/cgdata-generate-merge.s
index 3f7fb6777bc3..4b6d4a5d824c 100644
--- a/lld/test/MachO/cgdata-generate-merge.s
+++ b/lld/test/MachO/cgdata-generate-merge.s
@@ -5,11 +5,15 @@
# Synthesize raw cgdata without the header (32 byte) from the indexed cgdata.
# RUN: llvm-cgdata --convert --format binary %t/raw-1.cgtext -o %t/raw-1.cgdata
-# RUN: od -t x1 -j 32 -An %t/raw-1.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-1-bytes.txt
-# RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-1-bytes.txt)/g" %t/merge-template.s > %t/merge-1.s
+# RUN: echo -n "s/<RAW_BYTES>/" > %t/raw-1-sed.txt
+# RUN: od -t x1 -j 32 -An %t/raw-1.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' >> %t/raw-1-sed.txt
+# RUN: echo "/g" >> %t/raw-1-sed.txt
+# RUN: sed -f %t/raw-1-sed.txt %t/merge-template.s > %t/merge-1.s
# RUN: llvm-cgdata --convert --format binary %t/raw-2.cgtext -o %t/raw-2.cgdata
-# RUN: od -t x1 -j 32 -An %t/raw-2.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-2-bytes.txt
-# RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-2-bytes.txt)/g" %t/merge-template.s > %t/merge-2.s
+# RUN: echo -n "s/<RAW_BYTES>/" > %t/raw-2-sed.txt
+# RUN: od -t x1 -j 32 -An %t/raw-2.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' >> %t/raw-2-sed.txt
+# RUN: echo "/g" >> %t/raw-2-sed.txt
+# RUN: sed -f %t/raw-2-sed.txt %t/merge-template.s > %t/merge-2.s
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-1.s -o %t/merge-1.o
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-2.s -o %t/merge-2.o
diff --git a/lld/test/MachO/cgdata-generate.s b/lld/test/MachO/cgdata-generate.s
index f942ae07f64e..63efc81cda17 100644
--- a/lld/test/MachO/cgdata-generate.s
+++ b/lld/test/MachO/cgdata-generate.s
@@ -5,11 +5,15 @@
# Synthesize raw cgdata without the header (32 byte) from the indexed cgdata.
# RUN: llvm-cgdata --convert --format binary %t/raw-1.cgtext -o %t/raw-1.cgdata
-# RUN: od -t x1 -j 32 -An %t/raw-1.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-1-bytes.txt
-# RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-1-bytes.txt)/g" %t/merge-template.s > %t/merge-1.s
+# RUN: echo -n "s/<RAW_BYTES>/" > %t/raw-1-sed.txt
+# RUN: od -t x1 -j 32 -An %t/raw-1.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' >> %t/raw-1-sed.txt
+# RUN: echo "/g" >> %t/raw-1-sed.txt
+# RUN: sed -f %t/raw-1-sed.txt %t/merge-template.s > %t/merge-1.s
# RUN: llvm-cgdata --convert --format binary %t/raw-2.cgtext -o %t/raw-2.cgdata
-# RUN: od -t x1 -j 32 -An %t/raw-2.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' > %t/raw-2-bytes.txt
-# RUN: sed "s/<RAW_BYTES>/$(cat %t/raw-2-bytes.txt)/g" %t/merge-template.s > %t/merge-2.s
+# RUN: echo -n "s/<RAW_BYTES>/" > %t/raw-2-sed.txt
+# RUN: od -t x1 -j 32 -An %t/raw-2.cgdata | tr -d '\n\r\t' | sed 's/[ ][ ]*/ /g; s/^[ ]*//; s/[ ]*$//; s/[ ]/,0x/g; s/^/0x/' >> %t/raw-2-sed.txt
+# RUN: echo "/g" >> %t/raw-2-sed.txt
+# RUN: sed -f %t/raw-2-sed.txt %t/merge-template.s > %t/merge-2.s
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-1.s -o %t/merge-1.o
# RUN: llvm-mc -filetype obj -triple arm64-apple-darwin %t/merge-2.s -o %t/merge-2.o
diff --git a/lld/test/MachO/color-diagnostics.test b/lld/test/MachO/color-diagnostics.test
index b079c82e1a43..465cba1750bc 100644
--- a/lld/test/MachO/color-diagnostics.test
+++ b/lld/test/MachO/color-diagnostics.test
@@ -1,5 +1,5 @@
# Windows command prompt doesn't support ANSI escape sequences.
-# REQUIRES: shell
+# UNSUPPORTED: system-windows
# RUN: not %lld --color-diagnostics /nosuchfile 2>&1 \
# RUN: | FileCheck -check-prefix=COLOR %s
diff --git a/lld/test/MachO/framework.s b/lld/test/MachO/framework.s
index 38925847935b..c62eb12d31e8 100644
--- a/lld/test/MachO/framework.s
+++ b/lld/test/MachO/framework.s
@@ -1,4 +1,5 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t; split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/foo.s -o %t/foo.o
# RUN: mkdir -p %t/Foo.framework/Versions/A
diff --git a/lld/test/MachO/implicit-and-allowable-clients.test b/lld/test/MachO/implicit-and-allowable-clients.test
index f627d242a007..f5c13c250ea4 100644
--- a/lld/test/MachO/implicit-and-allowable-clients.test
+++ b/lld/test/MachO/implicit-and-allowable-clients.test
@@ -1,4 +1,7 @@
-# REQUIRES: aarch64, shell
+# ln -s is not guaranteed to work on Windows
+# UNSUPPORTED: system-windows
+
+# REQUIRES: aarch64
# RUN: rm -rf %t; split-file %s %t
# RUN: ln -s Versions/A/FrameworkPublic.tbd %t/System/Library/Frameworks/FrameworkPublic.framework/
# RUN: ln -s Versions/A/FrameworkPrivate.tbd %t/System/Library/Frameworks/FrameworkPrivate.framework/
diff --git a/lld/test/MachO/invalid/Inputs/macho-trie-node-loop b/lld/test/MachO/invalid/Inputs/macho-trie-node-loop
new file mode 100755
index 000000000000..b94dfa2610e9
--- /dev/null
+++ b/lld/test/MachO/invalid/Inputs/macho-trie-node-loop
Binary files differ
diff --git a/lld/test/MachO/invalid/export-trie-node-loop.s b/lld/test/MachO/invalid/export-trie-node-loop.s
new file mode 100644
index 000000000000..fe991597fe5a
--- /dev/null
+++ b/lld/test/MachO/invalid/export-trie-node-loop.s
@@ -0,0 +1,9 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
+# RUN: not %lld -o %t %t.o %S/Inputs/macho-trie-node-loop 2>&1 | FileCheck %s
+# CHECK: error:
+# CHECK-SAME: /Inputs/macho-trie-node-loop: export trie child node infinite loop
+
+.globl _main
+_main:
+ ret
diff --git a/lld/test/MachO/link-search-at-loader-path-symlink.s b/lld/test/MachO/link-search-at-loader-path-symlink.s
index ff0f9481addf..8b0aeb7faf0b 100644
--- a/lld/test/MachO/link-search-at-loader-path-symlink.s
+++ b/lld/test/MachO/link-search-at-loader-path-symlink.s
@@ -1,4 +1,6 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
+# Windows does not support rpath
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t; split-file %s %t
diff --git a/lld/test/MachO/lto-cache-warnings.ll b/lld/test/MachO/lto-cache-warnings.ll
index 50fa5c16a41b..de6324ab60f1 100644
--- a/lld/test/MachO/lto-cache-warnings.ll
+++ b/lld/test/MachO/lto-cache-warnings.ll
@@ -1,4 +1,4 @@
-; REQUIRES: x86, shell
+; REQUIRES: x86
; RUN: rm -rf %t; split-file %s %t
; RUN: opt -module-hash -module-summary %t/foo.ll -o %t/foo.o
@@ -19,13 +19,17 @@
;; Get the total size of created cache files.
; RUN: cd %t
; RUN: %lld -cache_path_lto %t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=32k %t/foo.o %t/bar.o -o %t/test 2>&1
-; RUN: %python -c "import os, sys; print(sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')))" > %t.size.txt
+; RUN: %python -c "import os, sys; size=sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')); print(size+5); print(size-5)" > %t.size.txt
;; Case 2: If the total size of the cache files created by the current link job is less than the maximum size for the cache directory in bytes, there is no warning.
-; RUN: %lld -v -cache_path_lto %t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) + 5)) %t/foo.o %t/bar.o -o %t/test 2>&1 | FileCheck %s --implicit-check-not=warning:
+; RUN: echo -n "--thinlto-cache-policy=prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: head -1 %t.size.txt >> %t.response
+; RUN: %lld -v -cache_path_lto %t @%t.response %t/foo.o %t/bar.o -o %t/test 2>&1 | FileCheck %s --implicit-check-not=warning:
;; Case 3: If the total size of the cache files created by the current link job exceeds the maximum size for the cache directory in bytes, a warning is given.
-; RUN: %lld -v -cache_path_lto %t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) - 5)) %t/foo.o %t/bar.o -o %t/test 2>&1 | FileCheck %s --check-prefixes=SIZE,WARN
+; RUN: echo -n "--thinlto-cache-policy=prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: tail -1 %t.size.txt >> %t.response
+; RUN: %lld -v -cache_path_lto %t @%t.response %t/foo.o %t/bar.o -o %t/test 2>&1 | FileCheck %s --check-prefixes=SIZE,WARN
;; Check emit two warnings if pruning happens due to reach both the size and number limits.
; RUN: %lld -cache_path_lto %t --thinlto-cache-policy=prune_interval=0s:cache_size_files=1:cache_size_bytes=1 %t/foo.o %t/bar.o -o %t/test 2>&1 | FileCheck %s --check-prefixes=NUM,SIZE,WARN
diff --git a/lld/test/MachO/read-workers.s b/lld/test/MachO/read-workers.s
new file mode 100644
index 000000000000..6f0ea4d89440
--- /dev/null
+++ b/lld/test/MachO/read-workers.s
@@ -0,0 +1,16 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %s -o %t.o
+
+## A non-negative integer is allowed.
+# RUN: %lld --read-workers=0 %t.o -o /dev/null
+# RUN: %lld --read-workers=1 %t.o -o /dev/null
+# RUN: %lld --read-workers=2 %t.o -o /dev/null
+
+# RUN: not %lld --read-workers=all %t.o -o /dev/null 2>&1 | FileCheck %s -DN=all
+# RUN: not %lld --read-workers=-1 %t.o -o /dev/null 2>&1 | FileCheck %s -DN=-1
+
+# CHECK: error: --read-workers=: expected a non-negative integer, but got '[[N]]'
+
+.globl _main
+_main:
+ ret
diff --git a/lld/test/MachO/reexport-with-symlink.s b/lld/test/MachO/reexport-with-symlink.s
index a6b5992713f3..c9cde5bc4f18 100644
--- a/lld/test/MachO/reexport-with-symlink.s
+++ b/lld/test/MachO/reexport-with-symlink.s
@@ -1,4 +1,5 @@
-# REQUIRES: aarch64, shell
+# REQUIRES: aarch64
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t; split-file %s %t
# RUN: ln -s Versions/A/Developer %t/Developer/Library/Frameworks/Developer.framework/
# RUN: llvm-mc -filetype obj -triple arm64-apple-macos11.0 %t/test.s -o %t/test.o
diff --git a/lld/test/MachO/reexport-without-rpath.s b/lld/test/MachO/reexport-without-rpath.s
index 741c33e81630..a204c140c4a7 100644
--- a/lld/test/MachO/reexport-without-rpath.s
+++ b/lld/test/MachO/reexport-without-rpath.s
@@ -1,4 +1,6 @@
-# REQUIRES: aarch64, shell
+# REQUIRES: aarch64
+# Windows does not support rpath
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t; split-file %s %t
# RUN: ln -s Versions/A/Developer %t/Developer/Library/Frameworks/Developer.framework/
# RUN: ln -s Versions/A/DeveloperCore %t/Developer/Library/PrivateFrameworks/DeveloperCore.framework/
diff --git a/lld/test/MachO/reproduce.s b/lld/test/MachO/reproduce.s
index 6f2ec680e124..68d94cab2c7e 100644
--- a/lld/test/MachO/reproduce.s
+++ b/lld/test/MachO/reproduce.s
@@ -1,4 +1,6 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
+# Unsupported on Windows due to maximum path length limitations.
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t.dir
# RUN: mkdir -p %t.dir/build1
diff --git a/lld/test/MachO/stabs.s b/lld/test/MachO/stabs.s
index e32b9fc5b50d..065dccbe72b4 100644
--- a/lld/test/MachO/stabs.s
+++ b/lld/test/MachO/stabs.s
@@ -1,4 +1,4 @@
-# REQUIRES: x86, shell
+# REQUIRES: x86
# UNSUPPORTED: system-windows
# RUN: rm -rf %t; split-file %s %t
# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o
@@ -9,61 +9,69 @@
# RUN: env TZ=GMT touch -t "197001010000.32" %t/foo.o
# RUN: llvm-ar rcsU %t/foo.a %t/foo.o
-# RUN: ZERO_AR_DATE=0 %lld -lSystem %t/test.o %t/foo.o %t/no-debug.o -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
-# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20
+# RUN: env ZERO_AR_DATE=0 %lld -lSystem %t/test.o %t/foo.o %t/no-debug.o -o %t/test
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
+# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --input-file %t.out
## Check that we emit the right modtime even when the object file is in an
## archive.
-# RUN: ZERO_AR_DATE=0 %lld -lSystem %t/test.o %t/foo.a %t/no-debug.o -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
-# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20
+# RUN: env ZERO_AR_DATE=0 %lld -lSystem %t/test.o %t/foo.a %t/no-debug.o -o %t/test
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
+# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --input-file %t.out
## Check that we don't emit modtimes if ZERO_AR_DATE is set.
# RUN: env ZERO_AR_DATE=1 %lld -lSystem %t/test.o %t/foo.o %t/no-debug.o \
# RUN: -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
-# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
+# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0 --input-file %t.out
# RUN: env %lld -lSystem %t/test.o %t/foo.a %t/no-debug.o \
# RUN: -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
-# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
+# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0 --input-file %t.out
# RUN: env %lld -lSystem %t/test.o %t/no-debug.o \
# RUN: -all_load %t/foo.a -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
-# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
+# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0 --input-file %t.out
# RUN: env %lld -lSystem %t/test.o %t/no-debug.o \
# RUN: -force_load %t/foo.a -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
-# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
+# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0 --input-file %t.out
# RUN: env ZERO_AR_DATE=0 %lld -lSystem -reproducible %t/test.o %t/foo.o \
# RUN: %t/no-debug.o -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
-# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
+# RUN: -D#TEST_TIME=0 -D#FOO_TIME=0 --input-file %t.out
## Check that we emit absolute paths to the object files in our OSO entries
## even if our inputs are relative paths.
-# RUN: cd %t && ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -o test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
-# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20
+# RUN: cd %t && env ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -o test
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.o \
+# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --input-file %t.out
## Check that we emit relative path to object files in OSO entries
## when -oso_prefix <path> is used.
-# RUN: cd %t && ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "%t" -o %t/test-rel
+# RUN: cd %t && env ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "%t" -o %t/test-rel
# RUN: dsymutil -s %t/test-rel | grep 'N_OSO' | FileCheck %s -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --check-prefix=REL-PATH
-# RUN: cd %t && ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "%t/" -o %t/test-rel
+# RUN: cd %t && env ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "%t/" -o %t/test-rel
# RUN: dsymutil -s %t/test-rel | grep 'N_OSO' | FileCheck %s -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --check-prefix=REL-PATH-NO-SLASH
-# RUN: cd %t && ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "." -o %t/test-rel-dot
+# RUN: cd %t && env ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "." -o %t/test-rel-dot
# RUN: dsymutil -s %t/test-rel-dot | grep 'N_OSO' | FileCheck %s -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --check-prefix=REL-DOT
-# RUN: cd %t && ZERO_AR_DATE=0 %lld -lSystem ./test.o ./foo.o ./no-debug.o -oso_prefix "." -o %t/test-rel-dot
+# RUN: cd %t && env ZERO_AR_DATE=0 %lld -lSystem ./test.o ./foo.o ./no-debug.o -oso_prefix "." -o %t/test-rel-dot
# RUN: dsymutil -s %t/test-rel-dot | grep 'N_OSO' | FileCheck %s -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --check-prefix=REL-DOT-EXPLICIT
## Check that symlinks are not expanded when -oso_prefix . is used.
@@ -71,9 +79,9 @@
# RUN: cp %t/test.o %t/foo.o %t/no-debug.o %t/private/var/folders/tmp
# RUN: env TZ=GMT touch -t "197001010000.16" %t/private/var/folders/tmp/test.o
# RUN: env TZ=GMT touch -t "197001010000.32" %t/private/var/folders/tmp/foo.o
-# RUN: cd %t/var/folders/tmp && ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "." -o test-rel-symlink
+# RUN: cd %t/var/folders/tmp && env ZERO_AR_DATE=0 %lld -lSystem test.o foo.o no-debug.o -oso_prefix "." -o test-rel-symlink
# RUN: dsymutil -s %t/private/var/folders/tmp/test-rel-symlink | grep 'N_OSO' | FileCheck %s -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --check-prefix=REL-DOT
-# RUN: cd %t/var/folders/tmp && ZERO_AR_DATE=0 %lld -lSystem ./test.o ./foo.o ./no-debug.o -oso_prefix "." -o test-rel-symlink
+# RUN: cd %t/var/folders/tmp && env ZERO_AR_DATE=0 %lld -lSystem ./test.o ./foo.o ./no-debug.o -oso_prefix "." -o test-rel-symlink
# RUN: dsymutil -s %t/private/var/folders/tmp/test-rel-symlink | grep 'N_OSO' | FileCheck %s -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --check-prefix=REL-DOT-EXPLICIT
## Check that we don't emit DWARF or stabs when -S is used
@@ -82,10 +90,11 @@
## expect to not find any entries which requires the exit code to be negated.
# RUN: llvm-nm -ap %t/test-no-debug | not grep -e ' - '
-# RUN: cd %t && ZERO_AR_DATE=0 %lld -lSystem test.o foo.a no-debug.o -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | \
-# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
-# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20
+# RUN: cd %t && env ZERO_AR_DATE=0 %lld -lSystem test.o foo.a no-debug.o -o %t/test
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s -DDIR=%t -DFOO_PATH=%t/foo.a\(foo.o\) \
+# RUN: -D#TEST_TIME=0x10 -D#FOO_TIME=0x20 --input-file %t.out
# CHECK: Sections:
# CHECK-NEXT: Idx Name
@@ -159,7 +168,9 @@
## when forming N_SO.
# RUN: llvm-mc -filetype obj -triple=x86_64-apple-darwin %t/abs-path.s -o %t/abs-path.o
# RUN: %lld %t/abs-path.o -o %t/test
-# RUN: (llvm-objdump --section-headers %t/test; dsymutil -s %t/test) | FileCheck %s --check-prefix=ABS-PATH
+# RUN: llvm-objdump --section-headers %t/test > %t.out
+# RUN: dsymutil -s %t/test >> %t.out
+# RUN: FileCheck %s --check-prefix=ABS-PATH --input-file %t.out
# ABS-PATH: (N_SO ) 00 0000 0000000000000000 '/foo.cpp'
#--- test.s
diff --git a/lld/test/MachO/tapi-rpath.s b/lld/test/MachO/tapi-rpath.s
index 48032f28a6ce..23187e797466 100644
--- a/lld/test/MachO/tapi-rpath.s
+++ b/lld/test/MachO/tapi-rpath.s
@@ -1,4 +1,6 @@
-# REQUIRES: aarch64, shell
+# REQUIRES: aarch64
+# Windows does not support rpath
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t; split-file %s %t
# RUN: ln -s Versions/A/Developer %t/Developer/Library/Frameworks/Developer.framework/
# RUN: ln -s Versions/A/DeveloperCore %t/Developer/Library/PrivateFrameworks/DeveloperCore.framework/
diff --git a/lld/test/MinGW/driver.test b/lld/test/MinGW/driver.test
index 618b88850432..47809d8a8749 100644
--- a/lld/test/MinGW/driver.test
+++ b/lld/test/MinGW/driver.test
@@ -296,6 +296,7 @@ RUN: not ld.lld -m i386pep --foo 2>&1 | FileCheck -check-prefix UNKNOWN_ARG %s
UNKNOWN_ARG: error: unknown argument: --foo
RUN: not ld.lld -m i386pep 2>&1 | FileCheck -check-prefix NO_INPUT_FILES %s
+RUN: not ld.lld -m mipspe 2>&1 | FileCheck -check-prefix NO_INPUT_FILES %s
NO_INPUT_FILES: error: no input files
RUN: ld.lld -### -m i386pep foo.o 2>&1 | FileCheck -check-prefix ENABLE_AUTO_IMPORT %s
diff --git a/lld/test/lit.cfg.py b/lld/test/lit.cfg.py
index 10f556567cdc..336945729954 100644
--- a/lld/test/lit.cfg.py
+++ b/lld/test/lit.cfg.py
@@ -16,10 +16,21 @@ from lit.llvm import llvm_config
# name: The name of this test suite.
config.name = "lld"
+# TODO: Consolidate the logic for turning on the internal shell by default for all LLVM test suites.
+# See https://github.com/llvm/llvm-project/issues/106636 for more details.
+#
+# We prefer the lit internal shell which provides a better user experience on failures
+# and is faster unless the user explicitly disables it with LIT_USE_INTERNAL_SHELL=0
+# env var.
+use_lit_shell = True
+lit_shell_env = os.environ.get("LIT_USE_INTERNAL_SHELL")
+if lit_shell_env:
+ use_lit_shell = lit.util.pythonize_bool(lit_shell_env)
+
# testFormat: The test format to use to interpret tests.
#
# For now we require '&&' between commands, until they get globally killed and the test runner updated.
-config.test_format = lit.formats.ShTest(not llvm_config.use_lit_shell)
+config.test_format = lit.formats.ShTest(execute_external=not use_lit_shell)
# suffixes: A list of file extensions to treat as test files.
config.suffixes = [".ll", ".s", ".test", ".yaml", ".objtxt"]
diff --git a/lld/test/wasm/libsearch.s b/lld/test/wasm/libsearch.s
index 23336510748c..20f1e9b2bfa3 100644
--- a/lld/test/wasm/libsearch.s
+++ b/lld/test/wasm/libsearch.s
@@ -93,6 +93,11 @@
// RUN: wasm-ld -pie --experimental-pic --emit-relocs --no-gc-sections -o %t3 %t.o -L%t.dir -Bstatic -call_shared -lls
// RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=DYNAMIC %s
+/// -r implies -Bstatic and has precedence over -Bdynamic.
+// RUN: wasm-ld -r -Bdynamic %t.o -L%t.dir -lls -o %t3.ro
+// RUN: llvm-readobj -s -h %t3.ro | FileCheck --check-prefix=RELOCATABLE %s
+// RELOCATABLE: Name: _static
+
.globl _start, _bar
_start:
.functype _start () -> ()
diff --git a/lld/test/wasm/lto/cache-warnings.ll b/lld/test/wasm/lto/cache-warnings.ll
index 9175fc97a075..c21093b533c7 100644
--- a/lld/test/wasm/lto/cache-warnings.ll
+++ b/lld/test/wasm/lto/cache-warnings.ll
@@ -1,5 +1,3 @@
-; REQUIRES: shell
-
; RUN: opt -module-hash -module-summary %s -o %t.o
; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o
@@ -20,13 +18,17 @@
;; Get the total size of created cache files.
; RUN: rm -rf %t && mkdir %t && cd %t
; RUN: wasm-ld --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=32k %t2.o %t.o -o %t3 2>&1
-; RUN: %python -c "import os, sys; print(sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')))" > %t.size.txt
+; RUN: %python -c "import os, sys; size=sum(os.path.getsize(filename) for filename in os.listdir('.') if os.path.isfile(filename) and filename.startswith('llvmcache-')); print(size+5); print(size-5)" > %t.size.txt
;; Case 2: If the total size of the cache files created by the current link job is less than the maximum size for the cache directory in bytes, there is no warning.
-; RUN: wasm-ld --verbose --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) + 5)) %t2.o %t.o -o %t3 2>&1 | FileCheck %s --implicit-check-not=warning:
+; RUN: echo -n "--thinlto-cache-policy=prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: head -1 %t.size.txt >> %t.response
+; RUN: wasm-ld --verbose --thinlto-cache-dir=%t @%t.response %t2.o %t.o -o %t3 2>&1 | FileCheck %s --implicit-check-not=warning:
;; Case 3: If the total size of the cache files created by the current link job exceeds the maximum size for the cache directory in bytes, a warning is given.
-; RUN: wasm-ld --verbose --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_bytes=$(($(cat %t.size.txt) - 5)) %t2.o %t.o -o %t3 2>&1 | FileCheck %s --check-prefixes=SIZE,WARN
+; RUN: echo -n "--thinlto-cache-policy=prune_interval=0s:cache_size_bytes=" > %t.response
+; RUN: tail -1 %t.size.txt >> %t.response
+; RUN: wasm-ld --verbose --thinlto-cache-dir=%t @%t.response %t2.o %t.o -o %t3 2>&1 | FileCheck %s --check-prefixes=SIZE,WARN
;; Check emit two warnings if pruning happens due to reach both the size and number limits.
; RUN: wasm-ld --thinlto-cache-dir=%t --thinlto-cache-policy=prune_interval=0s:cache_size_files=1:cache_size_bytes=1 %t2.o %t.o -o %t3 2>&1 | FileCheck %s --check-prefixes=NUM,SIZE,WARN
diff --git a/lld/test/wasm/reproduce.s b/lld/test/wasm/reproduce.s
index a89843fe219e..40e9ad3794d5 100644
--- a/lld/test/wasm/reproduce.s
+++ b/lld/test/wasm/reproduce.s
@@ -1,4 +1,5 @@
-# REQUIRES: shell
+# Unsupported on Windows due to maximum path length limitations.
+# UNSUPPORTED: system-windows
# RUN: rm -rf %t.dir
# RUN: mkdir -p %t.dir
# RUN: llvm-mc -filetype=obj -triple=wasm32-unknown-unknown -o %t.dir/foo.o %s
diff --git a/lld/wasm/Driver.cpp b/lld/wasm/Driver.cpp
index 1c5d21c06f5a..b57d77457b83 100644
--- a/lld/wasm/Driver.cpp
+++ b/lld/wasm/Driver.cpp
@@ -406,7 +406,8 @@ void LinkerDriver::createFiles(opt::InputArgList &args) {
ctx.arg.isStatic = true;
break;
case OPT_Bdynamic:
- ctx.arg.isStatic = false;
+ if (!ctx.arg.relocatable)
+ ctx.arg.isStatic = false;
break;
case OPT_whole_archive:
inWholeArchive = true;