diff options
Diffstat (limited to 'lld')
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 Binary files differnew file mode 100755 index 000000000000..b94dfa2610e9 --- /dev/null +++ b/lld/test/MachO/invalid/Inputs/macho-trie-node-loop 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; |
