diff options
Diffstat (limited to 'lld')
72 files changed, 1988 insertions, 538 deletions
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h index 79b63e5..91b6e63 100644 --- a/lld/COFF/Config.h +++ b/lld/COFF/Config.h @@ -192,6 +192,18 @@ struct Configuration { // Used for /lldltocachepolicy=policy llvm::CachePruningPolicy ltoCachePolicy; + // Used for /thinlto-distributor:<path> + StringRef dtltoDistributor; + + // Used for /thinlto-distributor-arg:<arg> + llvm::SmallVector<llvm::StringRef, 0> dtltoDistributorArgs; + + // Used for /thinlto-remote-compiler:<path> + StringRef dtltoCompiler; + + // Used for /thinlto-remote-compiler-arg:<arg> + llvm::SmallVector<llvm::StringRef, 0> dtltoCompilerArgs; + // Used for /opt:[no]ltodebugpassmanager bool ltoDebugPassManager = false; @@ -307,7 +319,7 @@ struct Configuration { bool warnDebugInfoUnusable = true; bool warnLongSectionNames = true; bool warnStdcallFixup = true; - bool warnExportedDllMain = true; + bool warnImportedDllMain = true; bool incremental = true; bool integrityCheck = false; bool killAt = false; diff --git a/lld/COFF/DLL.cpp b/lld/COFF/DLL.cpp index c327da2..3ce8853 100644 --- a/lld/COFF/DLL.cpp +++ b/lld/COFF/DLL.cpp @@ -244,40 +244,36 @@ static const uint8_t thunkX64[] = { }; static const uint8_t tailMergeX64[] = { - 0x51, // push rcx - 0x52, // push rdx - 0x41, 0x50, // push r8 - 0x41, 0x51, // push r9 - 0x48, 0x83, 0xEC, 0x48, // sub rsp, 48h - 0x66, 0x0F, 0x7F, 0x04, 0x24, // movdqa xmmword ptr [rsp], xmm0 - 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x10, // movdqa xmmword ptr [rsp+10h], xmm1 - 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm2 - 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm3 - 0x48, 0x8B, 0xD0, // mov rdx, rax - 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] - 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 - 0x66, 0x0F, 0x6F, 0x04, 0x24, // movdqa xmm0, xmmword ptr [rsp] - 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x10, // movdqa xmm1, xmmword ptr [rsp+10h] - 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x20, // movdqa xmm2, xmmword ptr [rsp+20h] - 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x30, // movdqa xmm3, xmmword ptr [rsp+30h] - 0x48, 0x83, 0xC4, 0x48, // add rsp, 48h - 0x41, 0x59, // pop r9 - 0x41, 0x58, // pop r8 - 0x5A, // pop rdx - 0x59, // pop rcx - 0xFF, 0xE0, // jmp rax + 0x48, 0x89, 0x4C, 0x24, 0x08, // mov qword ptr [rsp+8], rcx + 0x48, 0x89, 0x54, 0x24, 0x10, // mov qword ptr [rsp+10h], rdx + 0x4C, 0x89, 0x44, 0x24, 0x18, // mov qword ptr [rsp+18h], r8 + 0x4C, 0x89, 0x4C, 0x24, 0x20, // mov qword ptr [rsp+20h], r9 + 0x48, 0x83, 0xEC, 0x68, // sub rsp, 68h + 0x66, 0x0F, 0x7F, 0x44, 0x24, 0x20, // movdqa xmmword ptr [rsp+20h], xmm0 + 0x66, 0x0F, 0x7F, 0x4C, 0x24, 0x30, // movdqa xmmword ptr [rsp+30h], xmm1 + 0x66, 0x0F, 0x7F, 0x54, 0x24, 0x40, // movdqa xmmword ptr [rsp+40h], xmm2 + 0x66, 0x0F, 0x7F, 0x5C, 0x24, 0x50, // movdqa xmmword ptr [rsp+50h], xmm3 + 0x48, 0x8B, 0xD0, // mov rdx, rax + 0x48, 0x8D, 0x0D, 0, 0, 0, 0, // lea rcx, [___DELAY_IMPORT_...] + 0xE8, 0, 0, 0, 0, // call __delayLoadHelper2 + 0x66, 0x0F, 0x6F, 0x44, 0x24, 0x20, // movdqa xmm0, xmmword ptr [rsp+20h] + 0x66, 0x0F, 0x6F, 0x4C, 0x24, 0x30, // movdqa xmm1, xmmword ptr [rsp+30h] + 0x66, 0x0F, 0x6F, 0x54, 0x24, 0x40, // movdqa xmm2, xmmword ptr [rsp+40h] + 0x66, 0x0F, 0x6F, 0x5C, 0x24, 0x50, // movdqa xmm3, xmmword ptr [rsp+50h] + 0x48, 0x8B, 0x4C, 0x24, 0x70, // mov rcx, qword ptr [rsp+70h] + 0x48, 0x8B, 0x54, 0x24, 0x78, // mov rdx, qword ptr [rsp+78h] + 0x4C, 0x8B, 0x84, 0x24, 0x80, 0, 0, 0, // mov r8, qword ptr [rsp+80h] + 0x4C, 0x8B, 0x8C, 0x24, 0x88, 0, 0, 0, // mov r9, qword ptr [rsp+88h] + 0x48, 0x83, 0xC4, 0x68, // add rsp, 68h + 0xFF, 0xE0, // jmp rax }; static const uint8_t tailMergeUnwindInfoX64[] = { 0x01, // Version=1, Flags=UNW_FLAG_NHANDLER - 0x0a, // Size of prolog - 0x05, // Count of unwind codes + 0x18, // Size of prolog + 0x01, // Count of unwind codes 0x00, // No frame register - 0x0a, 0x82, // Offset 0xa: UWOP_ALLOC_SMALL(0x48) - 0x06, 0x02, // Offset 6: UWOP_ALLOC_SMALL(8) - 0x04, 0x02, // Offset 4: UWOP_ALLOC_SMALL(8) - 0x02, 0x02, // Offset 2: UWOP_ALLOC_SMALL(8) - 0x01, 0x02, // Offset 1: UWOP_ALLOC_SMALL(8) + 0x18, 0xC2, // Offset 0x18: UWOP_ALLOC_SMALL(0x68) 0x00, 0x00 // Padding to align on 32-bits }; @@ -378,8 +374,8 @@ public: void writeTo(uint8_t *buf) const override { memcpy(buf, tailMergeX64, sizeof(tailMergeX64)); - write32le(buf + 39, desc->getRVA() - rva - 43); - write32le(buf + 44, helper->getRVA() - rva - 48); + write32le(buf + 54, desc->getRVA() - rva - 58); + write32le(buf + 59, helper->getRVA() - rva - 63); } Chunk *desc = nullptr; diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp index 283aeed..570b8f9 100644 --- a/lld/COFF/Driver.cpp +++ b/lld/COFF/Driver.cpp @@ -274,8 +274,13 @@ void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> mb, make<std::unique_ptr<Archive>>(std::move(file)); // take ownership int memberIndex = 0; - for (MemoryBufferRef m : getArchiveMembers(ctx, archive)) - addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++); + for (MemoryBufferRef m : getArchiveMembers(ctx, archive)) { + if (!archive->isThin()) + addArchiveBuffer(m, "<whole-archive>", filename, memberIndex++); + else + addThinArchiveBuffer(m, "<whole-archive>"); + } + return; } addFile(make<ArchiveFile>(ctx, mbref)); @@ -386,6 +391,14 @@ void LinkerDriver::addArchiveBuffer(MemoryBufferRef mb, StringRef symName, Log(ctx) << "Loaded " << obj << " for " << symName; } +void LinkerDriver::addThinArchiveBuffer(MemoryBufferRef mb, StringRef symName) { + // Pass an empty string as the archive name and an offset of 0 so that + // the original filename is used as the buffer identifier. This is + // useful for DTLTO, where having the member identifier be the actual + // path on disk enables distribution of bitcode files during ThinLTO. + addArchiveBuffer(mb, symName, /*parentName=*/"", /*OffsetInArchive=*/0); +} + void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, const Archive::Symbol &sym, StringRef parentName) { @@ -422,11 +435,8 @@ void LinkerDriver::enqueueArchiveMember(const Archive::Child &c, reportBufferError(errorCodeToError(mbOrErr.second), childName); llvm::TimeTraceScope timeScope("Archive: ", mbOrErr.first->getBufferIdentifier()); - // Pass empty string as archive name so that the original filename is - // used as the buffer identifier. - ctx.driver.addArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), - toCOFFString(ctx, sym), "", - /*OffsetInArchive=*/0); + ctx.driver.addThinArchiveBuffer(takeBuffer(std::move(mbOrErr.first)), + toCOFFString(ctx, sym)); }); } @@ -1643,8 +1653,8 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { config->warnLocallyDefinedImported = false; else if (s == "longsections") config->warnLongSectionNames = false; - else if (s == "exporteddllmain") - config->warnExportedDllMain = false; + else if (s == "importeddllmain") + config->warnImportedDllMain = false; // Other warning numbers are ignored. } } @@ -2088,6 +2098,23 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { Fatal(ctx) << "/manifestinput: requires /manifest:embed"; } + // Handle /thinlto-distributor:<path> + config->dtltoDistributor = args.getLastArgValue(OPT_thinlto_distributor); + + // Handle /thinlto-distributor-arg:<arg> + for (auto *arg : args.filtered(OPT_thinlto_distributor_arg)) + config->dtltoDistributorArgs.push_back(arg->getValue()); + + // Handle /thinlto-remote-compiler:<path> + config->dtltoCompiler = args.getLastArgValue(OPT_thinlto_compiler); + if (!config->dtltoDistributor.empty() && config->dtltoCompiler.empty()) + Err(ctx) << "A value must be specified for /thinlto-remote-compiler if " + "/thinlto-distributor is specified."; + + // Handle /thinlto-remote-compiler-arg:<arg> + for (auto *arg : args.filtered(OPT_thinlto_compiler_arg)) + config->dtltoCompilerArgs.push_back(arg->getValue()); + // Handle /dwodir config->dwoDir = args.getLastArgValue(OPT_dwodir); @@ -2527,28 +2554,7 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) { e.symbolName = symtab.mangleMaybe(e.sym); } - // Add weak aliases. Weak aliases is a mechanism to give remaining - // undefined symbols final chance to be resolved successfully. - for (auto pair : symtab.alternateNames) { - StringRef from = pair.first; - StringRef to = pair.second; - Symbol *sym = symtab.find(from); - if (!sym) - continue; - if (auto *u = dyn_cast<Undefined>(sym)) { - if (u->weakAlias) { - // On ARM64EC, anti-dependency aliases are treated as undefined - // symbols unless a demangled symbol aliases a defined one, which - // is part of the implementation. - if (!symtab.isEC() || !u->isAntiDep) - continue; - if (!isa<Undefined>(u->weakAlias) && - !isArm64ECMangledFunctionName(u->getName())) - continue; - } - u->setWeakAlias(symtab.addUndefined(to)); - } - } + symtab.resolveAlternateNames(); }); ctx.forEachActiveSymtab([&](SymbolTable &symtab) { diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h index 14c97a9..5a9bd5c 100644 --- a/lld/COFF/Driver.h +++ b/lld/COFF/Driver.h @@ -173,6 +173,7 @@ private: bool lazy); void addArchiveBuffer(MemoryBufferRef mbref, StringRef symName, StringRef parentName, uint64_t offsetInArchive); + void addThinArchiveBuffer(MemoryBufferRef mbref, StringRef symName); void enqueueTask(std::function<void()> task); bool run(); diff --git a/lld/COFF/InputFiles.cpp b/lld/COFF/InputFiles.cpp index 0b7dbea..c08099b 100644 --- a/lld/COFF/InputFiles.cpp +++ b/lld/COFF/InputFiles.cpp @@ -117,8 +117,6 @@ static coff_symbol_generic *cloneSymbol(COFFSymbolRef sym) { // Skip importing DllMain thunks from import libraries. static bool fixupDllMain(COFFLinkerContext &ctx, llvm::object::Archive *file, const Archive::Symbol &sym, bool &skipDllMain) { - if (skipDllMain) - return true; const Archive::Child &c = CHECK(sym.getMember(), file->getFileName() + ": could not get the member for symbol " + @@ -128,13 +126,13 @@ static bool fixupDllMain(COFFLinkerContext &ctx, llvm::object::Archive *file, file->getFileName() + ": could not get the buffer for a child buffer of the archive"); if (identify_magic(mb.getBuffer()) == file_magic::coff_import_library) { - if (ctx.config.warnExportedDllMain) { + if (ctx.config.warnImportedDllMain) { // We won't place DllMain symbols in the symbol table if they are // coming from a import library. This message can be ignored with the flag - // '/ignore:exporteddllmain' + // '/ignore:importeddllmain' Warn(ctx) << file->getFileName() - << ": skipping exported DllMain symbol [exporteddllmain]\nNOTE: this " + << ": skipping imported DllMain symbol [importeddllmain]\nNOTE: this " "might be a mistake when the DLL/library was produced."; } skipDllMain = true; @@ -204,14 +202,24 @@ void ArchiveFile::parse() { } } - // Read the symbol table to construct Lazy objects. bool skipDllMain = false; + StringRef mangledDllMain, impMangledDllMain; + + // The calls below will fail if we haven't set the machine type yet. Instead + // of failing, it is preferable to skip this "imported DllMain" check if we + // don't know the machine type at this point. + if (!file->isEmpty() && ctx.config.machine != IMAGE_FILE_MACHINE_UNKNOWN) { + mangledDllMain = archiveSymtab->mangle("DllMain"); + impMangledDllMain = uniqueSaver().save("__imp_" + mangledDllMain); + } + + // Read the symbol table to construct Lazy objects. for (const Archive::Symbol &sym : file->symbols()) { - // If the DllMain symbol was exported by mistake, skip importing it - // otherwise we might end up with a import thunk in the final binary which - // is wrong. - if (sym.getName() == "__imp_DllMain" || sym.getName() == "DllMain") { - if (fixupDllMain(ctx, file.get(), sym, skipDllMain)) + // If an import library provides the DllMain symbol, skip importing it, as + // we should be using our own DllMain, not another DLL's DllMain. + if (!mangledDllMain.empty() && (sym.getName() == mangledDllMain || + sym.getName() == impMangledDllMain)) { + if (skipDllMain || fixupDllMain(ctx, file.get(), sym, skipDllMain)) continue; } archiveSymtab->addLazyArchive(this, sym); @@ -395,6 +403,11 @@ SectionChunk *ObjFile::readSection(uint32_t sectionNumber, return nullptr; } + // Those sections are generated by -fembed-bitcode and do not need to be kept + // in executable files. + if (name == ".llvmbc" || name == ".llvmcmd") + return nullptr; + // Object files may have DWARF debug info or MS CodeView debug info // (or both). // diff --git a/lld/COFF/LTO.cpp b/lld/COFF/LTO.cpp index 2a4d07c..1050874 100644 --- a/lld/COFF/LTO.cpp +++ b/lld/COFF/LTO.cpp @@ -110,7 +110,16 @@ BitcodeCompiler::BitcodeCompiler(COFFLinkerContext &c) : ctx(c) { // Initialize ltoObj. lto::ThinBackend backend; - if (ctx.config.thinLTOIndexOnly) { + if (!ctx.config.dtltoDistributor.empty()) { + backend = lto::createOutOfProcessThinBackend( + llvm::hardware_concurrency(ctx.config.thinLTOJobs), + /*OnWrite=*/nullptr, + /*ShouldEmitIndexFiles=*/false, + /*ShouldEmitImportFiles=*/false, ctx.config.outputFile, + ctx.config.dtltoDistributor, ctx.config.dtltoDistributorArgs, + ctx.config.dtltoCompiler, ctx.config.dtltoCompilerArgs, + !ctx.config.saveTempsArgs.empty()); + } else if (ctx.config.thinLTOIndexOnly) { auto OnIndexWrite = [&](StringRef S) { thinIndices.erase(S); }; backend = lto::createWriteIndexesThinBackend( llvm::hardware_concurrency(ctx.config.thinLTOJobs), diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td index a887d7d..0d66b49 100644 --- a/lld/COFF/Options.td +++ b/lld/COFF/Options.td @@ -270,6 +270,17 @@ def thinlto_object_suffix_replace : P< def thinlto_prefix_replace: P< "thinlto-prefix-replace", "'old;new' replace old prefix with new prefix in ThinLTO outputs">; +def thinlto_distributor : P<"thinlto-distributor", + "Distributor to use for ThinLTO backend compilations. If specified, ThinLTO " + "backend compilations will be distributed">; +def thinlto_distributor_arg : P<"thinlto-distributor-arg", + "Arguments to pass to the ThinLTO distributor">; +def thinlto_compiler : P<"thinlto-remote-compiler", + "Compiler for the ThinLTO distributor to invoke for ThinLTO backend " + "compilations">; +def thinlto_compiler_arg : P<"thinlto-remote-compiler-arg", + "Compiler arguments for the ThinLTO distributor to pass for ThinLTO backend " + "compilations">; def lto_obj_path : P< "lto-obj-path", "output native object for merged LTO unit to this path">; @@ -342,7 +353,13 @@ def fastfail : F<"fastfail">; def kernel : F<"kernel">; def pdbcompress : F<"pdbcompress">; def emitpogophaseinfo : F<"emitpogophaseinfo">; +defm emittoolversioninfo: B< + "emittoolversioninfo", + "Emit a tool version info after DOS header (so-called Rich header, default)", + "Do not emit a tool version info after DOS header (so-called Rich header)">; +def nocoffgrpinfo: F<"nocoffgrpinfo">; def noexp : F<"noexp">; +def novcfeature: F<"novcfeature">; def delay : P_priv<"delay">; def errorreport : P_priv<"errorreport">; diff --git a/lld/COFF/PDB.cpp b/lld/COFF/PDB.cpp index a54ea40..94eeae2 100644 --- a/lld/COFF/PDB.cpp +++ b/lld/COFF/PDB.cpp @@ -1135,9 +1135,12 @@ static pdb::BulkPublic createPublic(COFFLinkerContext &ctx, Defined *def) { pub.setFlags(flags); OutputSection *os = ctx.getOutputSection(def->getChunk()); - assert(os && "all publics should be in final image"); - pub.Offset = def->getRVA() - os->getRVA(); - pub.Segment = os->sectionIndex; + assert((os || !def->getChunk()->getSize()) && + "all publics should be in final image"); + if (os) { + pub.Offset = def->getRVA() - os->getRVA(); + pub.Segment = os->sectionIndex; + } return pub; } diff --git a/lld/COFF/SymbolTable.cpp b/lld/COFF/SymbolTable.cpp index 0062df5..189e75d 100644 --- a/lld/COFF/SymbolTable.cpp +++ b/lld/COFF/SymbolTable.cpp @@ -1344,6 +1344,43 @@ void SymbolTable::parseAlternateName(StringRef s) { alternateNames.insert(it, std::make_pair(from, to)); } +void SymbolTable::resolveAlternateNames() { + // Add weak aliases. Weak aliases is a mechanism to give remaining + // undefined symbols final chance to be resolved successfully. + for (auto pair : alternateNames) { + StringRef from = pair.first; + StringRef to = pair.second; + Symbol *sym = find(from); + if (!sym) + continue; + if (auto *u = dyn_cast<Undefined>(sym)) { + if (u->weakAlias) { + // On ARM64EC, anti-dependency aliases are treated as undefined + // symbols unless a demangled symbol aliases a defined one, which + // is part of the implementation. + if (!isEC() || !u->isAntiDep) + continue; + if (!isa<Undefined>(u->weakAlias) && + !isArm64ECMangledFunctionName(u->getName())) + continue; + } + + // Check if the destination symbol is defined. If not, skip it. + // It may still be resolved later if more input files are added. + // Also skip anti-dependency targets, as they can't be chained anyway. + Symbol *toSym = find(to); + if (!toSym) + continue; + auto toUndef = dyn_cast<Undefined>(toSym); + if (toUndef && (!toUndef->weakAlias || toUndef->isAntiDep)) + continue; + if (toSym->isLazy()) + forceLazy(toSym); + u->setWeakAlias(toSym); + } + } +} + // Parses /aligncomm option argument. void SymbolTable::parseAligncomm(StringRef s) { auto [name, align] = s.split(','); diff --git a/lld/COFF/SymbolTable.h b/lld/COFF/SymbolTable.h index 15e2644..7eb0676 100644 --- a/lld/COFF/SymbolTable.h +++ b/lld/COFF/SymbolTable.h @@ -69,6 +69,9 @@ public: // symbols and warn about imported local symbols. void resolveRemainingUndefines(); + // Try to resolve undefined symbols with alternate names. + void resolveAlternateNames(); + // Load lazy objects that are needed for MinGW automatic import and for // doing stdcall fixups. void loadMinGWSymbols(); diff --git a/lld/ELF/Arch/Hexagon.cpp b/lld/ELF/Arch/Hexagon.cpp index 479131a..9b33e78 100644 --- a/lld/ELF/Arch/Hexagon.cpp +++ b/lld/ELF/Arch/Hexagon.cpp @@ -11,6 +11,7 @@ #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" +#include "Thunks.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/SmallVector.h" #include "llvm/BinaryFormat/ELF.h" @@ -36,6 +37,10 @@ public: const uint8_t *loc) const override; RelType getDynRel(RelType type) const override; int64_t getImplicitAddend(const uint8_t *buf, RelType type) const override; + bool needsThunk(RelExpr expr, RelType type, const InputFile *file, + uint64_t branchAddr, const Symbol &s, + int64_t a) const override; + bool inBranchRange(RelType type, uint64_t src, uint64_t dst) const override; void relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const override; void writePltHeader(uint8_t *buf) const override; @@ -63,6 +68,8 @@ Hexagon::Hexagon(Ctx &ctx) : TargetInfo(ctx) { tlsGotRel = R_HEX_TPREL_32; tlsModuleIndexRel = R_HEX_DTPMOD_32; tlsOffsetRel = R_HEX_DTPREL_32; + + needsThunks = true; } uint32_t Hexagon::calcEFlags() const { @@ -258,6 +265,46 @@ static uint32_t findMaskR16(Ctx &ctx, uint32_t insn) { static void or32le(uint8_t *p, int32_t v) { write32le(p, read32le(p) | v); } +bool Hexagon::inBranchRange(RelType type, uint64_t src, uint64_t dst) const { + int64_t offset = dst - src; + switch (type) { + case llvm::ELF::R_HEX_B22_PCREL: + case llvm::ELF::R_HEX_PLT_B22_PCREL: + case llvm::ELF::R_HEX_GD_PLT_B22_PCREL: + case llvm::ELF::R_HEX_LD_PLT_B22_PCREL: + return llvm::isInt<22>(offset >> 2); + case llvm::ELF::R_HEX_B15_PCREL: + return llvm::isInt<15>(offset >> 2); + break; + case llvm::ELF::R_HEX_B13_PCREL: + return llvm::isInt<13>(offset >> 2); + break; + case llvm::ELF::R_HEX_B9_PCREL: + return llvm::isInt<9>(offset >> 2); + default: + return true; + } + llvm_unreachable("unsupported relocation"); +} + +bool Hexagon::needsThunk(RelExpr expr, RelType type, const InputFile *file, + uint64_t branchAddr, const Symbol &s, + int64_t a) const { + // Only check branch range for supported branch relocation types + switch (type) { + case R_HEX_B22_PCREL: + case R_HEX_PLT_B22_PCREL: + case R_HEX_GD_PLT_B22_PCREL: + case R_HEX_LD_PLT_B22_PCREL: + case R_HEX_B15_PCREL: + case R_HEX_B13_PCREL: + case R_HEX_B9_PCREL: + return !ctx.target->inBranchRange(type, branchAddr, s.getVA(ctx, a)); + default: + return false; + } +} + void Hexagon::relocate(uint8_t *loc, const Relocation &rel, uint64_t val) const { switch (rel.type) { diff --git a/lld/ELF/Arch/LoongArch.cpp b/lld/ELF/Arch/LoongArch.cpp index fe804cb..a145530 100644 --- a/lld/ELF/Arch/LoongArch.cpp +++ b/lld/ELF/Arch/LoongArch.cpp @@ -809,10 +809,13 @@ static void relaxPCHi20Lo12(Ctx &ctx, const InputSection &sec, size_t i, // address. // Meanwhile skip undefined, preemptible and STT_GNU_IFUNC symbols, because // these symbols may be resolve in runtime. + // Moreover, relaxation can only occur if the addends of both relocations are + // zero for GOT references. if (rHi20.type == R_LARCH_GOT_PC_HI20 && - (!rHi20.sym->isDefined() || rHi20.sym->isPreemptible || - rHi20.sym->isGnuIFunc() || - (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section))) + (!rHi20.sym || rHi20.sym != rLo12.sym || !rHi20.sym->isDefined() || + rHi20.sym->isPreemptible || rHi20.sym->isGnuIFunc() || + (ctx.arg.isPic && !cast<Defined>(*rHi20.sym).section) || + rHi20.addend != 0 || rLo12.addend != 0)) return; uint64_t dest = 0; @@ -966,10 +969,16 @@ static bool relax(Ctx &ctx, InputSection &sec) { case R_LARCH_GOT_PC_HI20: case R_LARCH_TLS_GD_PC_HI20: case R_LARCH_TLS_LD_PC_HI20: - case R_LARCH_TLS_DESC_PC_HI20: // The overflow check for i+2 will be carried out in isPairRelaxable. - if (r.expr != RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC && - r.expr != R_RELAX_TLS_GD_TO_LE && isPairRelaxable(relocs, i)) + if (isPairRelaxable(relocs, i)) + relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove); + break; + case R_LARCH_TLS_DESC_PC_HI20: + if (r.expr == RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC || + r.expr == R_RELAX_TLS_GD_TO_LE) { + if (relaxable(relocs, i)) + remove = 4; + } else if (isPairRelaxable(relocs, i)) relaxPCHi20Lo12(ctx, sec, i, loc, r, relocs[i + 2], remove); break; case R_LARCH_CALL36: @@ -987,6 +996,17 @@ static bool relax(Ctx &ctx, InputSection &sec) { isUInt<12>(r.sym->getVA(ctx, r.addend))) remove = 4; break; + case R_LARCH_TLS_DESC_PC_LO12: + if (relaxable(relocs, i) && + (r.expr == RE_LOONGARCH_RELAX_TLS_GD_TO_IE_PAGE_PC || + r.expr == R_RELAX_TLS_GD_TO_LE)) + remove = 4; + break; + case R_LARCH_TLS_DESC_LD: + if (relaxable(relocs, i) && r.expr == R_RELAX_TLS_GD_TO_LE && + isUInt<12>(r.sym->getVA(ctx, r.addend))) + remove = 4; + break; } // For all anchors whose offsets are <= r.offset, they are preceded by @@ -1216,6 +1236,10 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { bits); relocateNoSym(loc, rel.type, val); } else { + isRelax = relaxable(relocs, i); + if (isRelax && (rel.type == R_LARCH_TLS_DESC_PC_HI20 || + rel.type == R_LARCH_TLS_DESC_PC_LO12)) + continue; tlsdescToIe(loc, rel, val); } continue; @@ -1232,6 +1256,11 @@ void LoongArch::relocateAlloc(InputSectionBase &sec, uint8_t *buf) const { bits); relocateNoSym(loc, rel.type, val); } else { + isRelax = relaxable(relocs, i); + if (isRelax && (rel.type == R_LARCH_TLS_DESC_PC_HI20 || + rel.type == R_LARCH_TLS_DESC_PC_LO12 || + (rel.type == R_LARCH_TLS_DESC_LD && isUInt<12>(val)))) + continue; tlsdescToLe(loc, rel, val); } continue; diff --git a/lld/ELF/Arch/Mips.cpp b/lld/ELF/Arch/Mips.cpp index 91c7f15..f88b021c 100644 --- a/lld/ELF/Arch/Mips.cpp +++ b/lld/ELF/Arch/Mips.cpp @@ -40,6 +40,10 @@ public: }; } // namespace +uint64_t elf::getMipsPageAddr(uint64_t addr) { + return (addr + 0x8000) & ~0xffff; +} + template <class ELFT> MIPS<ELFT>::MIPS(Ctx &ctx) : TargetInfo(ctx) { gotPltHeaderEntriesNum = 2; defaultMaxPageSize = 65536; diff --git a/lld/ELF/BPSectionOrderer.cpp b/lld/ELF/BPSectionOrderer.cpp index f464b1d..0615204 100644 --- a/lld/ELF/BPSectionOrderer.cpp +++ b/lld/ELF/BPSectionOrderer.cpp @@ -76,10 +76,10 @@ DenseMap<const InputSectionBase *, int> elf::runBalancedPartitioning( if (!d) return; auto *sec = dyn_cast_or_null<InputSection>(d->section); - // Skip empty, discarded, ICF folded sections. Skipping ICF folded sections - // reduces duplicate detection work in BPSectionOrderer. + // Skip empty, discarded, ICF folded sections, .bss. Skipping ICF folded + // sections reduces duplicate detection work in BPSectionOrderer. if (!sec || sec->size == 0 || !sec->isLive() || sec->repl != sec || - !orderer.secToSym.try_emplace(sec, d).second) + !sec->content().data() || !orderer.secToSym.try_emplace(sec, d).second) return; rootSymbolToSectionIdxs[CachedHashStringRef( lld::utils::getRootSymbol(sym.getName()))] diff --git a/lld/ELF/Config.h b/lld/ELF/Config.h index d9639b0..a83a4c1 100644 --- a/lld/ELF/Config.h +++ b/lld/ELF/Config.h @@ -404,6 +404,7 @@ struct Config { bool zIfuncNoplt; bool zInitfirst; bool zInterpose; + bool zKeepDataSectionPrefix; bool zKeepTextSectionPrefix; bool zLrodataAfterBss; bool zNoBtCfi; @@ -701,6 +702,8 @@ struct Ctx : CommonLinkerContext { std::unique_ptr<llvm::TarWriter> tar; // InputFile for linker created symbols with no source location. InputFile *internalFile = nullptr; + // Dummy Undefined for relocations without a symbol. + Undefined *dummySym = nullptr; // True if symbols can be exported (isExported) or preemptible. bool hasDynsym = false; // True if SHT_LLVM_SYMPART is used. diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp index 21d228e..6c2f318 100644 --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -1625,6 +1625,8 @@ static void readConfigs(Ctx &ctx, opt::InputArgList &args) { ctx.arg.zIfuncNoplt = hasZOption(args, "ifunc-noplt"); ctx.arg.zInitfirst = hasZOption(args, "initfirst"); ctx.arg.zInterpose = hasZOption(args, "interpose"); + ctx.arg.zKeepDataSectionPrefix = getZFlag( + args, "keep-data-section-prefix", "nokeep-data-section-prefix", false); ctx.arg.zKeepTextSectionPrefix = getZFlag( args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); ctx.arg.zLrodataAfterBss = @@ -3138,6 +3140,7 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &args) { ctx.symtab->insert(arg->getValue())->traced = true; ctx.internalFile = createInternalFile(ctx, "<internal>"); + ctx.dummySym = make<Undefined>(ctx.internalFile, "", STB_LOCAL, 0, 0); // Handle -u/--undefined before input files. If both a.a and b.so define foo, // -u foo a.a b.so will extract a.a. diff --git a/lld/ELF/InputFiles.cpp b/lld/ELF/InputFiles.cpp index 71e72e7..37e4c8a 100644 --- a/lld/ELF/InputFiles.cpp +++ b/lld/ELF/InputFiles.cpp @@ -21,6 +21,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/LTO/LTO.h" #include "llvm/Object/IRObjectFile.h" +#include "llvm/Support/AArch64AttributeParser.h" #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Endian.h" @@ -537,6 +538,41 @@ uint32_t ObjFile<ELFT>::getSectionIndex(const Elf_Sym &sym) const { this); } +template <class ELFT> +static void +handleAArch64BAAndGnuProperties(ObjFile<ELFT> *file, Ctx &ctx, + const AArch64BuildAttrSubsections &baInfo) { + if (file->aarch64PauthAbiCoreInfo) { + // Check for data mismatch. + if (file->aarch64PauthAbiCoreInfo) { + if (baInfo.Pauth.TagPlatform != file->aarch64PauthAbiCoreInfo->platform || + baInfo.Pauth.TagSchema != file->aarch64PauthAbiCoreInfo->version) + Err(ctx) << file + << " GNU properties and build attributes have conflicting " + "AArch64 PAuth data"; + } + if (baInfo.AndFeatures != file->andFeatures) + Err(ctx) << file + << " GNU properties and build attributes have conflicting " + "AArch64 PAuth data"; + } else { + // When BuildAttributes are missing, PauthABI value defaults to (TagPlatform + // = 0, TagSchema = 0). GNU properties do not write PAuthAbiCoreInfo if GNU + // property is not present. To match this behaviour, we only write + // PAuthAbiCoreInfo when there is at least one non-zero value. The + // specification reserves TagPlatform = 0, TagSchema = 1 values to match the + // 'Invalid' GNU property section with platform = 0, version = 0. + if (baInfo.Pauth.TagPlatform || baInfo.Pauth.TagSchema) { + if (baInfo.Pauth.TagPlatform == 0 && baInfo.Pauth.TagSchema == 1) + file->aarch64PauthAbiCoreInfo = {0, 0}; + else + file->aarch64PauthAbiCoreInfo = {baInfo.Pauth.TagPlatform, + baInfo.Pauth.TagSchema}; + } + file->andFeatures = baInfo.AndFeatures; + } +} + template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) { object::ELFFile<ELFT> obj = this->getObj(); // Read a section table. justSymbols is usually false. @@ -554,6 +590,7 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) { sections.resize(size); for (size_t i = 0; i != size; ++i) { const Elf_Shdr &sec = objSections[i]; + if (LLVM_LIKELY(sec.sh_type == SHT_PROGBITS)) continue; if (LLVM_LIKELY(sec.sh_type == SHT_GROUP)) { @@ -637,13 +674,6 @@ template <class ELFT> void ObjFile<ELFT>::parse(bool ignoreComdats) { } break; case EM_AARCH64: - // FIXME: BuildAttributes have been implemented in llvm, but not yet in - // lld. Remove the section so that it does not accumulate in the output - // file. When support is implemented we expect not to output a build - // attributes section in files of type ET_EXEC or ET_SHARED, but ld -r - // ouptut will need a single merged attributes section. - if (sec.sh_type == SHT_AARCH64_ATTRIBUTES) - sections[i] = &InputSection::discarded; // Producing a static binary with MTE globals is not currently supported, // remove all SHT_AARCH64_MEMTAG_GLOBALS_STATIC sections as they're unused // medatada, and we don't want them to end up in the output file for @@ -744,6 +774,8 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats, StringRef shstrtab = CHECK2(obj.getSectionStringTable(objSections), this); uint64_t size = objSections.size(); SmallVector<ArrayRef<Elf_Word>, 0> selectedGroups; + AArch64BuildAttrSubsections aarch64BAsubSections; + bool hasAArch64BuildAttributes = false; for (size_t i = 0; i != size; ++i) { if (this->sections[i] == &InputSection::discarded) continue; @@ -775,6 +807,26 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats, continue; } + // Processor-specific types that do not use the following switch statement. + // + // Extract Build Attributes section contents into aarch64BAsubSections. + // Input objects may contain both build Build Attributes and GNU + // properties. We delay processing Build Attributes until we have finished + // reading all sections so that we can check that these are consistent. + if (type == SHT_AARCH64_ATTRIBUTES && ctx.arg.emachine == EM_AARCH64) { + ArrayRef<uint8_t> contents = check(obj.getSectionContents(sec)); + AArch64AttributeParser attributes; + if (Error e = attributes.parse(contents, ELFT::Endianness)) { + StringRef name = check(obj.getSectionName(sec, shstrtab)); + InputSection isec(*this, sec, name); + Warn(ctx) << &isec << ": " << std::move(e); + } else { + aarch64BAsubSections = extractBuildAttributesSubsections(attributes); + hasAArch64BuildAttributes = true; + } + this->sections[i] = &InputSection::discarded; + continue; + } switch (type) { case SHT_GROUP: { if (!ctx.arg.relocatable) @@ -912,6 +964,12 @@ void ObjFile<ELFT>::initializeSections(bool ignoreComdats, << linkSec; } + // Handle AArch64 Build Attributes and GNU properties: + // - Err on mismatched values. + // - Store missing values as GNU properties. + if (hasAArch64BuildAttributes) + handleAArch64BAAndGnuProperties<ELFT>(this, ctx, aarch64BAsubSections); + for (ArrayRef<Elf_Word> entries : selectedGroups) handleSectionGroup<ELFT>(this->sections, entries); } diff --git a/lld/ELF/InputSection.cpp b/lld/ELF/InputSection.cpp index 68e3feb..784ff7c 100644 --- a/lld/ELF/InputSection.cpp +++ b/lld/ELF/InputSection.cpp @@ -861,6 +861,11 @@ uint64_t InputSectionBase::getRelocTargetVA(Ctx &ctx, const Relocation &r, return ctx.in.mipsGot->getVA() + ctx.in.mipsGot->getPageEntryOffset(file, *r.sym, a) - ctx.in.mipsGot->getGp(file); + case RE_MIPS_OSEC_LOCAL_PAGE: + // This is used by the MIPS multi-GOT implementation. It relocates + // addresses of 64kb pages that lie inside the output section that sym is + // a representative for. + return getMipsPageAddr(r.sym->getOutputSection()->addr) + a; case RE_MIPS_GOT_OFF: case RE_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp index 4333b03..32ac28d6 100644 --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -885,10 +885,12 @@ static void addPltEntry(Ctx &ctx, PltSection &plt, GotPltSection &gotPlt, RelocationBaseSection &rel, RelType type, Symbol &sym) { plt.addEntry(sym); gotPlt.addEntry(sym); - rel.addReloc({type, &gotPlt, sym.getGotPltOffset(ctx), - sym.isPreemptible ? DynamicReloc::AgainstSymbol - : DynamicReloc::AddendOnlyWithTargetVA, - sym, 0, R_ABS}); + if (sym.isPreemptible) + rel.addReloc( + {type, &gotPlt, sym.getGotPltOffset(ctx), true, sym, 0, R_ADDEND}); + else + rel.addReloc( + {type, &gotPlt, sym.getGotPltOffset(ctx), false, sym, 0, R_ABS}); } void elf::addGotEntry(Ctx &ctx, Symbol &sym) { @@ -897,9 +899,8 @@ void elf::addGotEntry(Ctx &ctx, Symbol &sym) { // If preemptible, emit a GLOB_DAT relocation. if (sym.isPreemptible) { - ctx.mainPart->relaDyn->addReloc({ctx.target->gotRel, ctx.in.got.get(), off, - DynamicReloc::AgainstSymbol, sym, 0, - R_ABS}); + ctx.mainPart->relaDyn->addReloc( + {ctx.target->gotRel, ctx.in.got.get(), off, true, sym, 0, R_ADDEND}); return; } @@ -920,15 +921,13 @@ static void addGotAuthEntry(Ctx &ctx, Symbol &sym) { // If preemptible, emit a GLOB_DAT relocation. if (sym.isPreemptible) { ctx.mainPart->relaDyn->addReloc({R_AARCH64_AUTH_GLOB_DAT, ctx.in.got.get(), - off, DynamicReloc::AgainstSymbol, sym, 0, - R_ABS}); + off, true, sym, 0, R_ADDEND}); return; } // Signed GOT requires dynamic relocation. ctx.in.got->getPartition(ctx).relaDyn->addReloc( - {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, - DynamicReloc::AddendOnlyWithTargetVA, sym, 0, R_ABS}); + {R_AARCH64_AUTH_RELATIVE, ctx.in.got.get(), off, false, sym, 0, R_ABS}); } static void addTpOffsetGotEntry(Ctx &ctx, Symbol &sym) { @@ -1159,9 +1158,8 @@ void RelocationScanner::processAux(RelExpr expr, RelType type, uint64_t offset, sec->addReloc({expr, type, offset, addend, &sym}); part.relrAuthDyn->relocs.push_back({sec, sec->relocs().size() - 1}); } else { - part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, - DynamicReloc::AddendOnlyWithTargetVA, sym, - addend, R_ABS}); + part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, sec, offset, false, + sym, addend, R_ABS}); } return; } @@ -1948,13 +1946,12 @@ void elf::postScanRelocations(Ctx &ctx) { GotSection *got = ctx.in.got.get(); if (ctx.needsTlsLd.load(std::memory_order_relaxed) && got->addTlsIndex()) { - static Undefined dummy(ctx.internalFile, "", STB_LOCAL, 0, 0); if (ctx.arg.shared) ctx.mainPart->relaDyn->addReloc( {ctx.target->tlsModuleIndexRel, got, got->getTlsIndexOff()}); else got->addConstant({R_ADDEND, ctx.target->symbolicRel, - got->getTlsIndexOff(), 1, &dummy}); + got->getTlsIndexOff(), 1, ctx.dummySym}); } assert(ctx.symAux.size() == 1); @@ -2140,18 +2137,45 @@ void ThunkCreator::mergeThunks(ArrayRef<OutputSection *> outputSections) { }); } -static int64_t getPCBias(Ctx &ctx, RelType type) { - if (ctx.arg.emachine != EM_ARM) - return 0; - switch (type) { - case R_ARM_THM_JUMP19: - case R_ARM_THM_JUMP24: - case R_ARM_THM_CALL: - return 4; - default: - return 8; +constexpr uint32_t HEXAGON_MASK_END_PACKET = 3 << 14; +constexpr uint32_t HEXAGON_END_OF_PACKET = 3 << 14; +constexpr uint32_t HEXAGON_END_OF_DUPLEX = 0 << 14; + +// Return the distance between the packet start and the instruction in the +// relocation. +static int getHexagonPacketOffset(const InputSection &isec, + const Relocation &rel) { + const ArrayRef<uint8_t> data = isec.content(); + + // Search back as many as 3 instructions. + for (unsigned i = 0;; i++) { + if (i == 3 || rel.offset < (i + 1) * 4) + return i * 4; + uint32_t instWord = 0; + const ArrayRef<uint8_t> instWordContents = + data.drop_front(rel.offset - (i + 1) * 4); + memcpy(&instWord, instWordContents.data(), sizeof(instWord)); + if (((instWord & HEXAGON_MASK_END_PACKET) == HEXAGON_END_OF_PACKET) || + ((instWord & HEXAGON_MASK_END_PACKET) == HEXAGON_END_OF_DUPLEX)) + return i * 4; } } +static int64_t getPCBias(Ctx &ctx, const InputSection &isec, + const Relocation &rel) { + if (ctx.arg.emachine == EM_ARM) { + switch (rel.type) { + case R_ARM_THM_JUMP19: + case R_ARM_THM_JUMP24: + case R_ARM_THM_CALL: + return 4; + default: + return 8; + } + } + if (ctx.arg.emachine == EM_HEXAGON) + return -getHexagonPacketOffset(isec, rel); + return 0; +} // Find or create a ThunkSection within the InputSectionDescription (ISD) that // is in range of Src. An ISD maps to a range of InputSections described by a @@ -2162,7 +2186,7 @@ ThunkSection *ThunkCreator::getISDThunkSec(OutputSection *os, const Relocation &rel, uint64_t src) { // See the comment in getThunk for -pcBias below. - const int64_t pcBias = getPCBias(ctx, rel.type); + const int64_t pcBias = getPCBias(ctx, *isec, rel); for (std::pair<ThunkSection *, uint32_t> tp : isd->thunkSections) { ThunkSection *ts = tp.first; uint64_t tsBase = os->addr + ts->outSecOff - pcBias; @@ -2323,7 +2347,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(InputSection *isec, // out in the relocation addend. We compensate for the PC bias so that // an Arm and Thumb relocation to the same destination get the same keyAddend, // which is usually 0. - const int64_t pcBias = getPCBias(ctx, rel.type); + const int64_t pcBias = getPCBias(ctx, *isec, rel); const int64_t keyAddend = rel.addend + pcBias; // We use a ((section, offset), addend) pair to find the thunk position if @@ -2482,7 +2506,7 @@ bool ThunkCreator::createThunks(uint32_t pass, // STT_SECTION + non-zero addend, clear the addend after // redirection. if (ctx.arg.emachine != EM_MIPS) - rel.addend = -getPCBias(ctx, rel.type); + rel.addend = -getPCBias(ctx, *isec, rel); } for (auto &p : isd->thunkSections) @@ -2526,7 +2550,8 @@ void elf::hexagonTLSSymbolUpdate(Ctx &ctx) { for (Relocation &rel : isec->relocs()) if (rel.sym->type == llvm::ELF::STT_TLS && rel.expr == R_PLT_PC) { if (needEntry) { - sym->allocateAux(ctx); + if (sym->auxIdx == 0) + sym->allocateAux(ctx); addPltEntry(ctx, *ctx.in.plt, *ctx.in.gotPlt, *ctx.in.relaPlt, ctx.target->pltRel, *sym); needEntry = false; diff --git a/lld/ELF/Relocations.h b/lld/ELF/Relocations.h index 02ddf70..c1c4860 100644 --- a/lld/ELF/Relocations.h +++ b/lld/ELF/Relocations.h @@ -110,6 +110,7 @@ enum RelExpr { RE_MIPS_GOT_LOCAL_PAGE, RE_MIPS_GOT_OFF, RE_MIPS_GOT_OFF32, + RE_MIPS_OSEC_LOCAL_PAGE, RE_MIPS_TLSGD, RE_MIPS_TLSLD, RE_PPC32_PLTREL, diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index efec41a..0d87f9a 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -769,10 +769,6 @@ void GotSection::writeTo(uint8_t *buf) { } } -static uint64_t getMipsPageAddr(uint64_t addr) { - return (addr + 0x8000) & ~0xffff; -} - static uint64_t getMipsPageCount(uint64_t size) { return (size + 0xfffe) / 0xffff + 1; } @@ -786,7 +782,7 @@ void MipsGotSection::addEntry(InputFile &file, Symbol &sym, int64_t addend, FileGot &g = getGot(file); if (expr == RE_MIPS_GOT_LOCAL_PAGE) { if (const OutputSection *os = sym.getOutputSection()) - g.pagesMap.insert({os, {}}); + g.pagesMap.insert({os, {&sym}}); else g.local16.insert({{nullptr, getMipsPageAddr(sym.getVA(ctx, addend))}, 0}); } else if (sym.isTls()) @@ -1066,8 +1062,7 @@ void MipsGotSection::build() { // be allocated before us in the static TLS block. if (s->isPreemptible || ctx.arg.shared) ctx.mainPart->relaDyn->addReloc( - {ctx.target->tlsGotRel, this, offset, - DynamicReloc::AgainstSymbolWithTargetVA, *s, 0, R_ABS}); + {ctx.target->tlsGotRel, this, offset, true, *s, 0, R_ABS}); } for (std::pair<Symbol *, size_t> &p : got.dynTlsSymbols) { Symbol *s = p.first; @@ -1115,15 +1110,16 @@ void MipsGotSection::build() { size_t pageCount = l.second.count; for (size_t pi = 0; pi < pageCount; ++pi) { uint64_t offset = (l.second.firstIndex + pi) * ctx.arg.wordsize; - ctx.mainPart->relaDyn->addReloc({ctx.target->relativeRel, this, offset, - l.first, int64_t(pi * 0x10000)}); + ctx.mainPart->relaDyn->addReloc( + {ctx.target->relativeRel, this, offset, false, *l.second.repSym, + int64_t(pi * 0x10000), RE_MIPS_OSEC_LOCAL_PAGE}); } } for (const std::pair<GotEntry, size_t> &p : got.local16) { uint64_t offset = p.second * ctx.arg.wordsize; ctx.mainPart->relaDyn->addReloc({ctx.target->relativeRel, this, offset, - DynamicReloc::AddendOnlyWithTargetVA, - *p.first.first, p.first.second, R_ABS}); + false, *p.first.first, p.first.second, + R_ABS}); } } } @@ -1646,24 +1642,10 @@ uint64_t DynamicReloc::getOffset() const { } int64_t DynamicReloc::computeAddend(Ctx &ctx) const { - switch (kind) { - case AddendOnly: - assert(sym == nullptr); - return addend; - case AgainstSymbol: - assert(sym != nullptr); - return addend; - case AddendOnlyWithTargetVA: - case AgainstSymbolWithTargetVA: { - uint64_t ca = inputSec->getRelocTargetVA( - ctx, Relocation{expr, type, 0, addend, sym}, getOffset()); - return ctx.arg.is64 ? ca : SignExtend64<32>(ca); - } - case MipsMultiGotPage: - assert(sym == nullptr); - return getMipsPageAddr(outputSec->addr) + addend; - } - llvm_unreachable("Unknown DynamicReloc::Kind enum"); + assert(!isFinal && "addend already computed"); + uint64_t ca = inputSec->getRelocTargetVA( + ctx, Relocation{expr, type, 0, addend, sym}, getOffset()); + return ctx.arg.is64 ? ca : SignExtend64<32>(ca); } uint32_t DynamicReloc::getSymIndex(SymbolTableBaseSection *symTab) const { @@ -1691,8 +1673,8 @@ RelocationBaseSection::RelocationBaseSection(Ctx &ctx, StringRef name, void RelocationBaseSection::addSymbolReloc( RelType dynType, InputSectionBase &isec, uint64_t offsetInSec, Symbol &sym, int64_t addend, std::optional<RelType> addendRelType) { - addReloc(DynamicReloc::AgainstSymbol, dynType, isec, offsetInSec, sym, addend, - R_ADDEND, addendRelType ? *addendRelType : ctx.target->noneRel); + addReloc(true, dynType, isec, offsetInSec, sym, addend, R_ADDEND, + addendRelType ? *addendRelType : ctx.target->noneRel); } void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible( @@ -1700,11 +1682,9 @@ void RelocationBaseSection::addAddendOnlyRelocIfNonPreemptible( RelType addendRelType) { // No need to write an addend to the section for preemptible symbols. if (sym.isPreemptible) - addReloc({dynType, &isec, offsetInSec, DynamicReloc::AgainstSymbol, sym, 0, - R_ABS}); + addReloc({dynType, &isec, offsetInSec, true, sym, 0, R_ADDEND}); else - addReloc(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, offsetInSec, - sym, 0, R_ABS, addendRelType); + addReloc(false, dynType, isec, offsetInSec, sym, 0, R_ABS, addendRelType); } void RelocationBaseSection::mergeRels() { @@ -1744,17 +1724,17 @@ void RelocationBaseSection::finalizeContents() { } } -void DynamicReloc::computeRaw(Ctx &ctx, SymbolTableBaseSection *symt) { +void DynamicReloc::finalize(Ctx &ctx, SymbolTableBaseSection *symt) { r_offset = getOffset(); r_sym = getSymIndex(symt); addend = computeAddend(ctx); - kind = AddendOnly; // Catch errors + isFinal = true; // Catch errors } void RelocationBaseSection::computeRels() { SymbolTableBaseSection *symTab = getPartition(ctx).dynSymTab.get(); parallelForEach(relocs, [&ctx = ctx, symTab](DynamicReloc &rel) { - rel.computeRaw(ctx, symTab); + rel.finalize(ctx, symTab); }); auto irelative = std::stable_partition( diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h index 5f01513..223dfe3 100644 --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -327,9 +327,11 @@ private: size_t startIndex = 0; struct PageBlock { + Symbol *repSym; // Representative symbol for the OutputSection size_t firstIndex; size_t count; - PageBlock() : firstIndex(0), count(0) {} + PageBlock(Symbol *repSym = nullptr) + : repSym(repSym), firstIndex(0), count(0) {} }; // Map output sections referenced by MIPS GOT relocations @@ -418,61 +420,31 @@ private: class DynamicReloc { public: - enum Kind { - /// The resulting dynamic relocation does not reference a symbol (#sym must - /// be nullptr) and uses #addend as the result of computeAddend(ctx). - AddendOnly, - /// The resulting dynamic relocation will not reference a symbol: #sym is - /// only used to compute the addend with InputSection::getRelocTargetVA(). - /// Useful for various relative and TLS relocations (e.g. R_X86_64_TPOFF64). - AddendOnlyWithTargetVA, - /// The resulting dynamic relocation references symbol #sym from the dynamic - /// symbol table and uses #addend as the value of computeAddend(ctx). - AgainstSymbol, - /// The resulting dynamic relocation references symbol #sym from the dynamic - /// symbol table and uses InputSection::getRelocTargetVA() + #addend for the - /// final addend. It can be used for relocations that write the symbol VA as - // the addend (e.g. R_MIPS_TLS_TPREL64) but still reference the symbol. - AgainstSymbolWithTargetVA, - /// This is used by the MIPS multi-GOT implementation. It relocates - /// addresses of 64kb pages that lie inside the output section. - MipsMultiGotPage, - }; - /// This constructor records a relocation against a symbol. + /// This constructor records a normal relocation. DynamicReloc(RelType type, const InputSectionBase *inputSec, - uint64_t offsetInSec, Kind kind, Symbol &sym, int64_t addend, - RelExpr expr) + uint64_t offsetInSec, bool isAgainstSymbol, Symbol &sym, + int64_t addend, RelExpr expr) : sym(&sym), inputSec(inputSec), offsetInSec(offsetInSec), type(type), - addend(addend), kind(kind), expr(expr) {} + addend(addend), isAgainstSymbol(isAgainstSymbol), isFinal(false), + expr(expr) {} /// This constructor records a relative relocation with no symbol. DynamicReloc(RelType type, const InputSectionBase *inputSec, uint64_t offsetInSec, int64_t addend = 0) - : sym(nullptr), inputSec(inputSec), offsetInSec(offsetInSec), type(type), - addend(addend), kind(AddendOnly), expr(R_ADDEND) {} - /// This constructor records dynamic relocation settings used by the MIPS - /// multi-GOT implementation. - DynamicReloc(RelType type, const InputSectionBase *inputSec, - uint64_t offsetInSec, const OutputSection *outputSec, - int64_t addend) - : sym(nullptr), outputSec(outputSec), inputSec(inputSec), - offsetInSec(offsetInSec), type(type), addend(addend), - kind(MipsMultiGotPage), expr(R_ADDEND) {} + : DynamicReloc(type, inputSec, offsetInSec, false, + *inputSec->getCtx().dummySym, addend, R_ADDEND) {} uint64_t getOffset() const; uint32_t getSymIndex(SymbolTableBaseSection *symTab) const; - bool needsDynSymIndex() const { - return kind == AgainstSymbol || kind == AgainstSymbolWithTargetVA; - } + bool needsDynSymIndex() const { return isAgainstSymbol; } /// Computes the addend of the dynamic relocation. Note that this is not the /// same as the #addend member variable as it may also include the symbol /// address/the address of the corresponding GOT entry/etc. int64_t computeAddend(Ctx &) const; - void computeRaw(Ctx &, SymbolTableBaseSection *symt); + void finalize(Ctx &, SymbolTableBaseSection *symt); Symbol *sym; - const OutputSection *outputSec = nullptr; const InputSectionBase *inputSec; uint64_t offsetInSec; uint64_t r_offset; @@ -483,7 +455,15 @@ public: int64_t addend; private: - Kind kind; + /// Whether this was constructed with a Kind of AgainstSymbol. + LLVM_PREFERRED_TYPE(bool) + uint8_t isAgainstSymbol : 1; + + /// The resulting dynamic relocation has already had its addend computed. + /// Calling computeAddend() is an error. + LLVM_PREFERRED_TYPE(bool) + uint8_t isFinal : 1; + // The kind of expression used to calculate the added (required e.g. for // relative GOT relocations). RelExpr expr; @@ -528,8 +508,8 @@ public: uint64_t offsetInSec, Symbol &sym, int64_t addend, RelType addendRelType, RelExpr expr) { assert(expr != R_ADDEND && "expected non-addend relocation expression"); - addReloc<shard>(DynamicReloc::AddendOnlyWithTargetVA, dynType, isec, - offsetInSec, sym, addend, expr, addendRelType); + addReloc<shard>(false, dynType, isec, offsetInSec, sym, addend, expr, + addendRelType); } /// Add a dynamic relocation using the target address of \p sym as the addend /// if \p sym is non-preemptible. Otherwise add a relocation against \p sym. @@ -538,14 +518,15 @@ public: uint64_t offsetInSec, Symbol &sym, RelType addendRelType); template <bool shard = false> - void addReloc(DynamicReloc::Kind kind, RelType dynType, InputSectionBase &sec, + void addReloc(bool isAgainstSymbol, RelType dynType, InputSectionBase &sec, uint64_t offsetInSec, Symbol &sym, int64_t addend, RelExpr expr, RelType addendRelType) { // Write the addends to the relocated address if required. We skip // it if the written value would be zero. if (ctx.arg.writeAddends && (expr != R_ADDEND || addend != 0)) sec.addReloc({expr, addendRelType, offsetInSec, addend, &sym}); - addReloc<shard>({dynType, &sec, offsetInSec, kind, sym, addend, expr}); + addReloc<shard>( + {dynType, &sec, offsetInSec, isAgainstSymbol, sym, addend, expr}); } bool isNeeded() const override { return !relocs.empty() || diff --git a/lld/ELF/Target.cpp b/lld/ELF/Target.cpp index ad7d57d..4946484 100644 --- a/lld/ELF/Target.cpp +++ b/lld/ELF/Target.cpp @@ -105,10 +105,9 @@ ErrorPlace elf::getErrorPlace(Ctx &ctx, const uint8_t *loc) { if (isecLoc <= loc && loc < isecLoc + isec->getSize()) { std::string objLoc = isec->getLocation(loc - isecLoc); // Return object file location and source file location. - Undefined dummy(ctx.internalFile, "", STB_LOCAL, 0, 0); ELFSyncStream msg(ctx, DiagLevel::None); if (isec->file) - msg << isec->getSrcMsg(dummy, loc - isecLoc); + msg << isec->getSrcMsg(*ctx.dummySym, loc - isecLoc); return {isec, objLoc + ": ", std::string(msg.str())}; } } diff --git a/lld/ELF/Target.h b/lld/ELF/Target.h index 93f1592..fdc0c20 100644 --- a/lld/ELF/Target.h +++ b/lld/ELF/Target.h @@ -214,6 +214,7 @@ void processArmCmseSymbols(Ctx &); template <class ELFT> uint32_t calcMipsEFlags(Ctx &); uint8_t getMipsFpAbiFlag(Ctx &, InputFile *file, uint8_t oldFlag, uint8_t newFlag); +uint64_t getMipsPageAddr(uint64_t addr); bool isMipsN32Abi(Ctx &, const InputFile &f); bool isMicroMips(Ctx &); bool isMipsR6(Ctx &); @@ -338,21 +339,23 @@ inline uint64_t overwriteULEB128(uint8_t *bufLoc, uint64_t val) { #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" #endif #define invokeELFT(f, ...) \ - switch (ctx.arg.ekind) { \ - case lld::elf::ELF32LEKind: \ - f<llvm::object::ELF32LE>(__VA_ARGS__); \ - break; \ - case lld::elf::ELF32BEKind: \ - f<llvm::object::ELF32BE>(__VA_ARGS__); \ - break; \ - case lld::elf::ELF64LEKind: \ - f<llvm::object::ELF64LE>(__VA_ARGS__); \ - break; \ - case lld::elf::ELF64BEKind: \ - f<llvm::object::ELF64BE>(__VA_ARGS__); \ - break; \ - default: \ - llvm_unreachable("unknown ctx.arg.ekind"); \ - } + do { \ + switch (ctx.arg.ekind) { \ + case lld::elf::ELF32LEKind: \ + f<llvm::object::ELF32LE>(__VA_ARGS__); \ + break; \ + case lld::elf::ELF32BEKind: \ + f<llvm::object::ELF32BE>(__VA_ARGS__); \ + break; \ + case lld::elf::ELF64LEKind: \ + f<llvm::object::ELF64LE>(__VA_ARGS__); \ + break; \ + case lld::elf::ELF64BEKind: \ + f<llvm::object::ELF64BE>(__VA_ARGS__); \ + break; \ + default: \ + llvm_unreachable("unknown ctx.arg.ekind"); \ + } \ + } while (0) #endif diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp index c26ba76..65d0f09 100644 --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -415,6 +415,22 @@ public: void addSymbols(ThunkSection &isec) override; }; +// Hexagon CPUs need thunks for R_HEX_B{9,1{3,5},22}_PCREL, +// R_HEX_{,GD_}PLT_B22_PCREL when their destination is out of +// range. +class HexagonThunk : public Thunk { +public: + HexagonThunk(Ctx &ctx, const InputSection &isec, Relocation &rel, + Symbol &dest) + : Thunk(ctx, dest, 0), relOffset(rel.offset) { + alignment = 4; + } + uint32_t relOffset; + uint32_t size() override { return ctx.arg.isPic ? 12 : 8; } + void writeTo(uint8_t *buf) override; + void addSymbols(ThunkSection &isec) override; +}; + // MIPS LA25 thunk class MipsThunk final : public Thunk { public: @@ -1519,6 +1535,39 @@ bool PPC64LongBranchThunk::isCompatibleWith(const InputSection &isec, return rel.type == R_PPC64_REL24 || rel.type == R_PPC64_REL14; } +// Hexagon Target Thunks +static uint64_t getHexagonThunkDestVA(Ctx &ctx, const Symbol &s, int64_t a) { + uint64_t v = s.isInPlt(ctx) ? s.getPltVA(ctx) : s.getVA(ctx, a); + return SignExtend64<32>(v); +} + +void HexagonThunk::writeTo(uint8_t *buf) { + uint64_t s = getHexagonThunkDestVA(ctx, destination, addend); + uint64_t p = getThunkTargetSym()->getVA(ctx); + + if (ctx.arg.isPic) { + write32(ctx, buf + 0, 0x00004000); // { immext(#0) + ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p); + write32(ctx, buf + 4, 0x6a49c00e); // r14 = add(pc,##0) } + ctx.target->relocateNoSym(buf + 4, R_HEX_6_PCREL_X, s - p); + + write32(ctx, buf + 8, 0x528ec000); // { jumpr r14 } + } else { + write32(ctx, buf + 0, 0x00004000); // { immext + ctx.target->relocateNoSym(buf, R_HEX_B32_PCREL_X, s - p); + write32(ctx, buf + 4, 0x5800c000); // jump <> } + ctx.target->relocateNoSym(buf + 4, R_HEX_B22_PCREL_X, s - p); + } +} +void HexagonThunk::addSymbols(ThunkSection &isec) { + Symbol *enclosing = isec.getEnclosingSymbol(relOffset); + StringRef src = enclosing ? enclosing->getName() : isec.name; + + addSymbol( + saver().save("__hexagon_thunk_" + destination.getName() + "_from_" + src), + STT_FUNC, 0, isec); +} + Thunk::Thunk(Ctx &ctx, Symbol &d, int64_t a) : ctx(ctx), destination(d), addend(a), offset(0) { destination.thunkAccessed = true; @@ -1692,6 +1741,24 @@ static std::unique_ptr<Thunk> addThunkAVR(Ctx &ctx, RelType type, Symbol &s, } } +static std::unique_ptr<Thunk> addThunkHexagon(Ctx &ctx, + const InputSection &isec, + Relocation &rel, Symbol &s) { + switch (rel.type) { + case R_HEX_B9_PCREL: + case R_HEX_B13_PCREL: + case R_HEX_B15_PCREL: + case R_HEX_B22_PCREL: + case R_HEX_PLT_B22_PCREL: + case R_HEX_GD_PLT_B22_PCREL: + return std::make_unique<HexagonThunk>(ctx, isec, rel, s); + default: + Fatal(ctx) << "unrecognized relocation " << rel.type << " to " << &s + << " for hexagon target"; + llvm_unreachable(""); + } +} + static std::unique_ptr<Thunk> addThunkMips(Ctx &ctx, RelType type, Symbol &s) { if ((s.stOther & STO_MIPS_MICROMIPS) && isMipsR6(ctx)) return std::make_unique<MicroMipsR6Thunk>(ctx, s); @@ -1761,8 +1828,11 @@ std::unique_ptr<Thunk> elf::addThunk(Ctx &ctx, const InputSection &isec, return addThunkPPC32(ctx, isec, rel, s); case EM_PPC64: return addThunkPPC64(ctx, rel.type, s, a); + case EM_HEXAGON: + return addThunkHexagon(ctx, isec, rel, s); default: - llvm_unreachable("add Thunk only supported for ARM, AVR, Mips and PowerPC"); + llvm_unreachable( + "add Thunk only supported for ARM, AVR, Hexagon, Mips and PowerPC"); } } diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp index 15909da..2b0e097 100644 --- a/lld/ELF/Writer.cpp +++ b/lld/ELF/Writer.cpp @@ -553,6 +553,19 @@ template <class ELFT> void Writer<ELFT>::addSectionSymbols() { } } +// Returns true if this is a variant of .data.rel.ro. +static bool isRelRoDataSection(Ctx &ctx, StringRef secName) { + if (!secName.consume_front(".data.rel.ro")) + return false; + if (secName.empty()) + return true; + // If -z keep-data-section-prefix is specified, additionally allow + // '.data.rel.ro.hot' and '.data.rel.ro.unlikely'. + if (ctx.arg.zKeepDataSectionPrefix) + return secName == ".hot" || secName == ".unlikely"; + return false; +} + // Today's loaders have a feature to make segments read-only after // processing dynamic relocations to enhance security. PT_GNU_RELRO // is defined for that. @@ -629,7 +642,7 @@ static bool isRelroSection(Ctx &ctx, const OutputSection *sec) { // magic section names. StringRef s = sec->name; - bool abiAgnostic = s == ".data.rel.ro" || s == ".bss.rel.ro" || + bool abiAgnostic = isRelRoDataSection(ctx, s) || s == ".bss.rel.ro" || s == ".ctors" || s == ".dtors" || s == ".jcr" || s == ".eh_frame" || s == ".fini_array" || s == ".init_array" || s == ".preinit_array"; @@ -1573,9 +1586,8 @@ template <class ELFT> void Writer<ELFT>::finalizeAddressDependentContent() { if (isInt<32>(reloc.sym->getVA(ctx, reloc.addend))) return false; part.relaDyn->addReloc({R_AARCH64_AUTH_RELATIVE, elem.inputSec, - reloc.offset, - DynamicReloc::AddendOnlyWithTargetVA, - *reloc.sym, reloc.addend, R_ABS}); + reloc.offset, false, *reloc.sym, + reloc.addend, R_ABS}); return true; }); changed |= (it != part.relrAuthDyn->relocs.end()); diff --git a/lld/docs/DTLTO.rst b/lld/docs/DTLTO.rst index 985decf..54fcc03 100644 --- a/lld/docs/DTLTO.rst +++ b/lld/docs/DTLTO.rst @@ -7,8 +7,7 @@ during the traditional link step. The implementation is documented here: https://llvm.org/docs/DTLTO.html. -Currently, DTLTO is only supported in ELF LLD. Support will be added to other -LLD flavours in the future. +Currently, DTLTO is only supported in ELF and COFF LLD. ELF LLD ------- @@ -40,3 +39,37 @@ The command-line interface is as follows: Some LLD LTO options (e.g., ``--lto-sample-profile=<file>``) are supported. Currently, other options are silently accepted but do not have the intended effect. Support for such options will be expanded in the future. + +COFF LLD +-------- + +The command-line interface is as follows: + +- ``/thinlto-distributor:<path>`` + Specifies the file to execute as the distributor process. If specified, + ThinLTO backend compilations will be distributed. + +- ``/thinlto-remote-compiler:<path>`` + Specifies the path to the compiler that the distributor process will use for + backend compilations. The compiler invoked must match the version of LLD. + +- ``/thinlto-distributor-arg:<arg>`` + Specifies ``<arg>`` on the command line when invoking the distributor. + Can be specified multiple times. + +- ``/thinlto-remote-compiler-arg:<arg>`` + Appends ``<arg>`` to the remote compiler's command line. + Can be specified multiple times. + + Options that introduce extra input/output files may cause miscompilation if + the distribution system does not automatically handle pushing/fetching them to + remote nodes. In such cases, configure the distributor - possibly using + ``/thinlto-distributor-arg:`` - to manage these dependencies. See the + distributor documentation for details. + +Some LLD LTO options (e.g., ``/lto-sample-profile:<file>``) are supported. +Currently, other options are silently accepted but do not have the intended +effect. Support for such options could be expanded in the future. + +Currently, there is no DTLTO command line interface supplied for ``clang-cl``, +as users are expected to invoke LLD directly.
\ No newline at end of file diff --git a/lld/docs/ReleaseNotes.rst b/lld/docs/ReleaseNotes.rst index 863b201..6f60efd 100644 --- a/lld/docs/ReleaseNotes.rst +++ b/lld/docs/ReleaseNotes.rst @@ -25,70 +25,9 @@ Non-comprehensive list of changes in this release ELF Improvements ---------------- -* Added ``-z dynamic-undefined-weak`` to make undefined weak symbols dynamic - when the dynamic symbol table is present. - (`#143831 <https://github.com/llvm/llvm-project/pull/143831>`_) -* For ``-z undefs`` (default for ``-shared``), relocations referencing undefined - strong symbols now behave like relocations referencing undefined weak symbols. -* ``--why-live=<glob>`` prints for each symbol matching ``<glob>`` a chain of - items that kept it live during garbage collection. This is inspired by the - Mach-O LLD feature of the same name. -* ``--thinlto-distributor=`` and ``--thinlto-remote-compiler=`` options are - added to support Integrated Distributed ThinLTO. - (`#142757 <https://github.com/llvm/llvm-project/pull/142757>`_) -* Linker script ``OVERLAY`` descriptions now support virtual memory regions - (e.g. ``>region``) and ``NOCROSSREFS``. -* When the last ``PT_LOAD`` segment is executable and includes BSS sections, - its ``p_memsz`` member is now correct. - (`#139207 <https://github.com/llvm/llvm-project/pull/139207>`_) -* Spurious ``ASSERT`` errors before the layout converges are now fixed. - -* For ARM and AArch64, ``--xosegment`` and ``--no-xosegment`` control whether - to place executable-only and readable-executable sections in the same - segment. The default option is ``--no-xosegment``. - (`#132412 <https://github.com/llvm/llvm-project/pull/132412>`_) -* For AArch64, added support for the ``SHF_AARCH64_PURECODE`` section flag, - which indicates that the section only contains program code and no data. - An output section will only have this flag set if all input sections also - have it set. (`#125689 <https://github.com/llvm/llvm-project/pull/125689>`_, - `#134798 <https://github.com/llvm/llvm-project/pull/134798>`_) -* For AArch64 and ARM, added ``-zexecute-only-report``, which checks for - missing ``SHF_AARCH64_PURECODE`` and ``SHF_ARM_PURECODE`` section flags - on executable sections. - (`#128883 <https://github.com/llvm/llvm-project/pull/128883>`_) -* For AArch64, ``-z nopac-plt`` has been added. -* For AArch64 and X86_64, added ``--branch-to-branch``, which rewrites branches - that point to another branch instruction to instead branch directly to the - target of the second instruction. Enabled by default at ``-O2``. -* For AArch64, added support for ``-zgcs-report-dynamic``, enabling checks for - GNU GCS Attribute Flags in Dynamic Objects when GCS is enabled. Inherits value - from ``-zgcs-report`` (capped at ``warning`` level) unless user-defined, - ensuring compatibility with GNU ld linker. -* The default Hexagon architecture version in ELF object files produced by - lld is changed to v68. This change is only effective when the version is - not provided in the command line by the user and cannot be inferred from - inputs. -* For LoongArch, the initial-exec to local-exec TLS optimization has been implemented. -* For LoongArch, several relaxation optimizations are supported, including relaxation for - ``R_LARCH_PCALA_HI20/LO12`` and ``R_LARCH_GOT_PC_HI20/LO12`` relocations, instruction - relaxation for ``R_LARCH_CALL36``, TLS local-exec (``LE``)/global dynamic (``GD``)/ - local dynamic (``LD``) model relaxation, and TLSDESC code sequence relaxation. -* For RISCV, an oscillation bug due to call relaxation is now fixed. - (`#142899 <https://github.com/llvm/llvm-project/pull/142899>`_) -* For x86-64, the ``.ltext`` section is now placed before ``.rodata``. - Breaking changes ---------------- -* Executable-only and readable-executable sections are now allowed to be placed - in the same segment by default. Pass ``--xosegment`` to lld in order to get - the old behavior back. - -* When using ``--no-pie`` without a ``SECTIONS`` command, the linker uses the - target's default image base. If ``-Ttext=`` or ``--section-start`` specifies - an output section address below this base, there will now be an error. - ``--image-base`` can be set at a lower address to fix the error. - (`#140187 <https://github.com/llvm/llvm-project/pull/140187>`_) COFF Improvements ----------------- diff --git a/lld/docs/ld.lld.1 b/lld/docs/ld.lld.1 index 7edc522..1835879 100644 --- a/lld/docs/ld.lld.1 +++ b/lld/docs/ld.lld.1 @@ -798,6 +798,13 @@ Specify how to report the missing GNU_PROPERTY_X86_FEATURE_1_IBT or GNU_PROPERTY .Cm none is the default, linker will not report the missing property otherwise will be reported as a warning or an error. .Pp +.It Cm gcs-report Ns = Ns Ar [none|warning|error] +Specify how to report missing +.Cm GNU_PROPERTY_AARCH64_FEATURE_1_GCS +property. GNU_PROPERTY_AARCH64_FEATURE_1_GCS indicates object file support for the Guarded Control Stack security feature. +.Cm none +is the default, linker will not report the missing property otherwise will be reported as a warning or an error. +.Pp .It Cm dynamic-undefined-weak Make undefined weak symbols dynamic when the dynamic symbol table is present, if they are referenced from relocatable object files and not forced local by symbol visibility or versioning. Do not make them dynamic when @@ -953,6 +960,17 @@ disallows overlap. .It Cm shstk x86 only, use shadow stack. .Pp +.It Cm gcs Ns = Ns Ar [implicit|never|always] +Specifies how the +.Cm GNU_PROPERTY_AARCH64_FEATURE_1_GCS +bit is set in the output ELF file. When set, it indicates support for the Guarded Control Stack (GCS) security feature. +.Cm implicit +(default) The GCS feature bit is set if all input relocatable files have a .note.gnu.property section containing the GNU_PROPERTY_AARCH64_FEATURE_1_GCS bit. +.Cm never +clears the GCS feature bit regardless of input relocatable files' markings. +.Cm always +sets the GCS feature bit regardless of input object markings. +.Pp .It Cm stack-size Ns = Ns Ar size Set the main thread's stack size to .Ar size . diff --git a/lld/test/COFF/alternatename-alias.s b/lld/test/COFF/alternatename-alias.s new file mode 100644 index 0000000..bd0a861 --- /dev/null +++ b/lld/test/COFF/alternatename-alias.s @@ -0,0 +1,15 @@ +// REQUIRES: x86 + +// Check that a weak alias can be used as an alternate name target. +// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj +// RUN: lld-link -dll -noentry %t.obj -alternatename:sym=altsym + + .data + .rva sym + + .weak altsym + .set altsym,a + + .globl a +a: + .word 1 diff --git a/lld/test/COFF/alternatename-antidep.s b/lld/test/COFF/alternatename-antidep.s new file mode 100644 index 0000000..1188a9b --- /dev/null +++ b/lld/test/COFF/alternatename-antidep.s @@ -0,0 +1,16 @@ +// REQUIRES: x86 + +// Check that an anti-dependency alias can't be used as an alternate name target. +// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj +// RUN: not lld-link -dll -noentry %t.obj -alternatename:sym=altsym 2>&1 | FileCheck %s +// CHECK: error: undefined symbol: sym + + .data + .rva sym + + .weak_anti_dep altsym + .set altsym,a + + .globl a +a: + .word 1 diff --git a/lld/test/COFF/alternatename-lib.s b/lld/test/COFF/alternatename-lib.s new file mode 100644 index 0000000..206fe6b --- /dev/null +++ b/lld/test/COFF/alternatename-lib.s @@ -0,0 +1,43 @@ +// REQUIRES: x86 +// RUN: split-file %s %t.dir && cd %t.dir + +// RUN: llvm-mc -filetype=obj -triple=x86_64-windows refab.s -o refab.obj +// RUN: llvm-mc -filetype=obj -triple=x86_64-windows aa.s -o aa.obj +// RUN: llvm-mc -filetype=obj -triple=x86_64-windows b.s -o b.obj +// RUN: llvm-mc -filetype=obj -triple=x86_64-windows antidep.s -o antidep.obj +// RUN: llvm-lib -out:aa.lib aa.obj +// RUN: llvm-lib -out:b.lib b.obj + +// Check that -alternatename with an undefined target does not prevent the symbol from being resolved to a library, +// once another alternate name is resolved and pulls in the source symbol. +// RUN: lld-link -out:out.dll -dll -noentry -machine:amd64 refab.obj aa.lib -alternatename:a=aa -alternatename:b=undef + +// Check that -alternatename with an anti-dependency target does not prevent the symbol from being resolved to a library, +// after another alternate name is resolved and pulls in the source symbol. +// RUN: lld-link -out:out2.dll -dll -noentry -machine:amd64 antidep.obj refab.obj aa.lib -alternatename:a=aa -alternatename:b=u + +#--- refab.s + .data + .rva a + .rva b + +#--- aa.s + .globl aa +aa: + .word 1 + + .section .drectve, "yn" + .ascii "/defaultlib:b.lib" + +#--- b.s + .globl b +b: + .word 2 + +#--- antidep.s + .weak_anti_dep u + .set u,d + + .globl d +d: + .word 3 diff --git a/lld/test/COFF/arm64ec-altnames.s b/lld/test/COFF/arm64ec-altnames.s index b2abb24..cca778a 100644 --- a/lld/test/COFF/arm64ec-altnames.s +++ b/lld/test/COFF/arm64ec-altnames.s @@ -2,6 +2,7 @@ REQUIRES: aarch64 RUN: split-file %s %t.dir && cd %t.dir RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ext.s -o ext.obj +RUN: llvm-mc -filetype=obj -triple=arm64ec-windows ext-mangled.s -o ext-mangled.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impl.s -o impl.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows impl-cpp.s -o impl-cpp.obj RUN: llvm-mc -filetype=obj -triple=arm64ec-windows %S/Inputs/loadconfig-arm64ec.s -o loadconfig.obj @@ -49,6 +50,20 @@ RUN: lld-link -machine:arm64ec -dll -noentry -out:out4.dll impl-cpp.obj loadconf RUN: llvm-objdump -d out4.dll | FileCheck --check-prefix=DISASM %s RUN: llvm-readobj --hex-dump=.test out4.dll | FileCheck --check-prefix=TESTSEC %s +# Check that when both mangled and demangled alternate names are used, +# only the one whose target is defined is used (the mangled one in this case). + +RUN: lld-link -machine:arm64ec -dll -noentry -out:out5.dll ext-mangled.obj loadconfig.obj "-alternatename:#func=#altsym" -alternatename:func=altsym +RUN: llvm-objdump -d out5.dll | FileCheck --check-prefix=DISASM %s +RUN: llvm-readobj --hex-dump=.test out5.dll | FileCheck --check-prefix=TESTSEC %s + +# Check that when both mangled and demangled alternate names are used, +# only the one whose target is defined is used (the demangled one in this case). + +RUN: lld-link -machine:arm64ec -dll -noentry -out:out6.dll ext.obj loadconfig.obj "-alternatename:#func=#altsym" -alternatename:func=altsym +RUN: llvm-objdump -d out6.dll | FileCheck --check-prefix=DISASM2 %s +RUN: llvm-readobj --hex-dump=.test out6.dll | FileCheck --check-prefix=TESTSEC2 %s + #--- ext.s .weak_anti_dep func .set func, "#func" @@ -70,6 +85,30 @@ altsym: mov w0, #1 ret +#--- ext-mangled.s + .weak_anti_dep func +.set func, "#func" + .weak_anti_dep "#func" +.set "#func", thunksym + + .section .test, "r" + .rva func + .rva "#func" + + .section .thnk,"xr",discard,thunksym +thunksym: + mov w0, #2 + ret + + .section .text,"xr",discard,"#altsym" + .globl "#altsym" +"#altsym": + mov w0, #1 + ret + + .weak_anti_dep altsym + .set altsym,"#altsym" + #--- impl.s .weak_anti_dep func .set func, "#func" diff --git a/lld/test/COFF/arm64ec-delayimport.test b/lld/test/COFF/arm64ec-delayimport.test index 1e0bd89..01d4ab8 100644 --- a/lld/test/COFF/arm64ec-delayimport.test +++ b/lld/test/COFF/arm64ec-delayimport.test @@ -51,28 +51,28 @@ DISASM-NEXT: 180002016: 48 8d 05 6b 50 00 00 leaq 0x506b(%rip), %rax DISASM-NEXT: 18000201d: e9 0c 00 00 00 jmp 0x18000202e <.text+0x102e> DISASM-NEXT: 180002022: 48 8d 05 67 50 00 00 leaq 0x5067(%rip), %rax # 0x180007090 DISASM-NEXT: 180002029: e9 00 00 00 00 jmp 0x18000202e <.text+0x102e> -DISASM-NEXT: 18000202e: 51 pushq %rcx -DISASM-NEXT: 18000202f: 52 pushq %rdx -DISASM-NEXT: 180002030: 41 50 pushq %r8 -DISASM-NEXT: 180002032: 41 51 pushq %r9 -DISASM-NEXT: 180002034: 48 83 ec 48 subq $0x48, %rsp -DISASM-NEXT: 180002038: 66 0f 7f 04 24 movdqa %xmm0, (%rsp) -DISASM-NEXT: 18000203d: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp) -DISASM-NEXT: 180002043: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp) -DISASM-NEXT: 180002049: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp) -DISASM-NEXT: 18000204f: 48 8b d0 movq %rax, %rdx -DISASM-NEXT: 180002052: 48 8d 0d a7 21 00 00 leaq 0x21a7(%rip), %rcx # 0x180004200 -DISASM-NEXT: 180002059: e8 aa ef ff ff callq 0x180001008 <.text+0x8> -DISASM-NEXT: 18000205e: 66 0f 6f 04 24 movdqa (%rsp), %xmm0 -DISASM-NEXT: 180002063: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1 -DISASM-NEXT: 180002069: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2 -DISASM-NEXT: 18000206f: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3 -DISASM-NEXT: 180002075: 48 83 c4 48 addq $0x48, %rsp -DISASM-NEXT: 180002079: 41 59 popq %r9 -DISASM-NEXT: 18000207b: 41 58 popq %r8 -DISASM-NEXT: 18000207d: 5a popq %rdx -DISASM-NEXT: 18000207e: 59 popq %rcx -DISASM-NEXT: 18000207f: ff e0 jmpq *%rax +DISASM-NEXT: 18000202e: 48 89 4c 24 08 movq %rcx, 0x8(%rsp) +DISASM-NEXT: 180002033: 48 89 54 24 10 movq %rdx, 0x10(%rsp) +DISASM-NEXT: 180002038: 4c 89 44 24 18 movq %r8, 0x18(%rsp) +DISASM-NEXT: 18000203d: 4c 89 4c 24 20 movq %r9, 0x20(%rsp) +DISASM-NEXT: 180002042: 48 83 ec 68 subq $0x68, %rsp +DISASM-NEXT: 180002046: 66 0f 7f 44 24 20 movdqa %xmm0, 0x20(%rsp) +DISASM-NEXT: 18000204c: 66 0f 7f 4c 24 30 movdqa %xmm1, 0x30(%rsp) +DISASM-NEXT: 180002052: 66 0f 7f 54 24 40 movdqa %xmm2, 0x40(%rsp) +DISASM-NEXT: 180002058: 66 0f 7f 5c 24 50 movdqa %xmm3, 0x50(%rsp) +DISASM-NEXT: 18000205e: 48 8b d0 movq %rax, %rdx +DISASM-NEXT: 180002061: 48 8d 0d 90 21 00 00 leaq 0x2190(%rip), %rcx # 0x1800041f8 +DISASM-NEXT: 180002068: e8 9b ef ff ff callq 0x180001008 <.text+0x8> +DISASM-NEXT: 18000206d: 66 0f 6f 44 24 20 movdqa 0x20(%rsp), %xmm0 +DISASM-NEXT: 180002073: 66 0f 6f 4c 24 30 movdqa 0x30(%rsp), %xmm1 +DISASM-NEXT: 180002079: 66 0f 6f 54 24 40 movdqa 0x40(%rsp), %xmm2 +DISASM-NEXT: 18000207f: 66 0f 6f 5c 24 50 movdqa 0x50(%rsp), %xmm3 +DISASM-NEXT: 180002085: 48 8b 4c 24 70 movq 0x70(%rsp), %rcx +DISASM-NEXT: 18000208a: 48 8b 54 24 78 movq 0x78(%rsp), %rdx +DISASM-NEXT: 18000208f: 4c 8b 84 24 80 00 00 00 movq 0x80(%rsp), %r8 +DISASM-NEXT: 180002097: 4c 8b 8c 24 88 00 00 00 movq 0x88(%rsp), %r9 +DISASM-NEXT: 18000209f: 48 83 c4 68 addq $0x68, %rsp +DISASM-NEXT: 1800020a3: ff e0 jmpq *%rax RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=LOADCFG %s LOADCFG: CHPEMetadata [ @@ -85,7 +85,7 @@ IMPORTS-NEXT: Name: test.dll IMPORTS-NEXT: Attributes: 0x1 IMPORTS-NEXT: ModuleHandle: 0x7080 IMPORTS-NEXT: ImportAddressTable: 0x7088 -IMPORTS-NEXT: ImportNameTable: 0x4240 +IMPORTS-NEXT: ImportNameTable: 0x4238 IMPORTS-NEXT: BoundDelayImportTable: 0x0 IMPORTS-NEXT: UnloadDelayImportTable: 0x0 IMPORTS-NEXT: Import { @@ -141,7 +141,7 @@ RELOC-NEXT: Address: 0x6008 RELOC-NEXT: } RUN: llvm-readobj --hex-dump=.pdata out.dll | FileCheck --check-prefix=PDATA %s -PDATA: 0x180008000 2e200000 81200000 18400000 +PDATA: 0x180008000 2e200000 a5200000 18400000 Verify that a demangled version of __delayLoadHelper2 can be used. diff --git a/lld/test/COFF/arm64x-delayimport.test b/lld/test/COFF/arm64x-delayimport.test index 56923ef..2a68bce 100644 --- a/lld/test/COFF/arm64x-delayimport.test +++ b/lld/test/COFF/arm64x-delayimport.test @@ -21,7 +21,7 @@ IMPORTS-NEXT: Name: test.dll IMPORTS-NEXT: Attributes: 0x1 IMPORTS-NEXT: ModuleHandle: 0x6080 IMPORTS-NEXT: ImportAddressTable: 0x6088 -IMPORTS-NEXT: ImportNameTable: 0x4390 +IMPORTS-NEXT: ImportNameTable: 0x4388 IMPORTS-NEXT: BoundDelayImportTable: 0x0 IMPORTS-NEXT: UnloadDelayImportTable: 0x0 IMPORTS-NEXT: Import { @@ -35,7 +35,7 @@ IMPORTS-NEXT: Name: test.dll IMPORTS-NEXT: Attributes: 0x1 IMPORTS-NEXT: ModuleHandle: 0x6080 IMPORTS-NEXT: ImportAddressTable: 0x6098 -IMPORTS-NEXT: ImportNameTable: 0x43A0 +IMPORTS-NEXT: ImportNameTable: 0x4398 IMPORTS-NEXT: BoundDelayImportTable: 0x0 IMPORTS-NEXT: UnloadDelayImportTable: 0x0 IMPORTS-NEXT: Import { @@ -73,7 +73,7 @@ DISASM-NEXT: 180001040: ad0497e4 stp q4, q5, [sp, #0x90] DISASM-NEXT: 180001044: ad059fe6 stp q6, q7, [sp, #0xb0] DISASM-NEXT: 180001048: aa1103e1 mov x1, x17 DISASM-NEXT: 18000104c: f0000000 adrp x0, 0x180004000 -DISASM-NEXT: 180001050: 910d4000 add x0, x0, #0x350 +DISASM-NEXT: 180001050: 910d2000 add x0, x0, #0x348 DISASM-NEXT: 180001054: 97ffffeb bl 0x180001000 <.text> DISASM-NEXT: 180001058: aa0003f0 mov x16, x0 DISASM-NEXT: 18000105c: ad459fe6 ldp q6, q7, [sp, #0xb0] @@ -105,28 +105,28 @@ DISASM-NEXT: ... DISASM-NEXT: 180003000: ff 25 92 30 00 00 jmpq *0x3092(%rip) # 0x180006098 DISASM-NEXT: 180003006: 48 8d 05 8b 30 00 00 leaq 0x308b(%rip), %rax # 0x180006098 DISASM-NEXT: 18000300d: e9 00 00 00 00 jmp 0x180003012 <.text+0x2012> -DISASM-NEXT: 180003012: 51 pushq %rcx -DISASM-NEXT: 180003013: 52 pushq %rdx -DISASM-NEXT: 180003014: 41 50 pushq %r8 -DISASM-NEXT: 180003016: 41 51 pushq %r9 -DISASM-NEXT: 180003018: 48 83 ec 48 subq $0x48, %rsp -DISASM-NEXT: 18000301c: 66 0f 7f 04 24 movdqa %xmm0, (%rsp) -DISASM-NEXT: 180003021: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp) -DISASM-NEXT: 180003027: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp) -DISASM-NEXT: 18000302d: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp) -DISASM-NEXT: 180003033: 48 8b d0 movq %rax, %rdx -DISASM-NEXT: 180003036: 48 8d 0d 13 13 00 00 leaq 0x1313(%rip), %rcx # 0x180004350 -DISASM-NEXT: 18000303d: e8 c6 ef ff ff callq 0x180002008 <.text+0x1008> -DISASM-NEXT: 180003042: 66 0f 6f 04 24 movdqa (%rsp), %xmm0 -DISASM-NEXT: 180003047: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1 -DISASM-NEXT: 18000304d: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2 -DISASM-NEXT: 180003053: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3 -DISASM-NEXT: 180003059: 48 83 c4 48 addq $0x48, %rsp -DISASM-NEXT: 18000305d: 41 59 popq %r9 -DISASM-NEXT: 18000305f: 41 58 popq %r8 -DISASM-NEXT: 180003061: 5a popq %rdx -DISASM-NEXT: 180003062: 59 popq %rcx -DISASM-NEXT: 180003063: ff e0 jmpq *%rax +DISASM-NEXT: 180003012: 48 89 4c 24 08 movq %rcx, 0x8(%rsp) +DISASM-NEXT: 180003017: 48 89 54 24 10 movq %rdx, 0x10(%rsp) +DISASM-NEXT: 18000301c: 4c 89 44 24 18 movq %r8, 0x18(%rsp) +DISASM-NEXT: 180003021: 4c 89 4c 24 20 movq %r9, 0x20(%rsp) +DISASM-NEXT: 180003026: 48 83 ec 68 subq $0x68, %rsp +DISASM-NEXT: 18000302a: 66 0f 7f 44 24 20 movdqa %xmm0, 0x20(%rsp) +DISASM-NEXT: 180003030: 66 0f 7f 4c 24 30 movdqa %xmm1, 0x30(%rsp) +DISASM-NEXT: 180003036: 66 0f 7f 54 24 40 movdqa %xmm2, 0x40(%rsp) +DISASM-NEXT: 18000303c: 66 0f 7f 5c 24 50 movdqa %xmm3, 0x50(%rsp) +DISASM-NEXT: 180003042: 48 8b d0 movq %rax, %rdx +DISASM-NEXT: 180003045: 48 8d 0d fc 12 00 00 leaq 0x12fc(%rip), %rcx # 0x180004348 +DISASM-NEXT: 18000304c: e8 b7 ef ff ff callq 0x180002008 <.text+0x1008> +DISASM-NEXT: 180003051: 66 0f 6f 44 24 20 movdqa 0x20(%rsp), %xmm0 +DISASM-NEXT: 180003057: 66 0f 6f 4c 24 30 movdqa 0x30(%rsp), %xmm1 +DISASM-NEXT: 18000305d: 66 0f 6f 54 24 40 movdqa 0x40(%rsp), %xmm2 +DISASM-NEXT: 180003063: 66 0f 6f 5c 24 50 movdqa 0x50(%rsp), %xmm3 +DISASM-NEXT: 180003069: 48 8b 4c 24 70 movq 0x70(%rsp), %rcx +DISASM-NEXT: 18000306e: 48 8b 54 24 78 movq 0x78(%rsp), %rdx +DISASM-NEXT: 180003073: 4c 8b 84 24 80 00 00 00 movq 0x80(%rsp), %r8 +DISASM-NEXT: 18000307b: 4c 8b 8c 24 88 00 00 00 movq 0x88(%rsp), %r9 +DISASM-NEXT: 180003083: 48 83 c4 68 addq $0x68, %rsp +DISASM-NEXT: 180003087: ff e0 jmpq *%rax RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=LOADCFG %s LOADCFG: AuxiliaryDelayloadIAT: 0x5000 @@ -230,7 +230,7 @@ EC-IMPORTS-NEXT: Name: test.dll EC-IMPORTS-NEXT: Attributes: 0x1 EC-IMPORTS-NEXT: ModuleHandle: 0x6080 EC-IMPORTS-NEXT: ImportAddressTable: 0x6088 -EC-IMPORTS-NEXT: ImportNameTable: 0x4388 +EC-IMPORTS-NEXT: ImportNameTable: 0x4380 EC-IMPORTS-NEXT: BoundDelayImportTable: 0x0 EC-IMPORTS-NEXT: UnloadDelayImportTable: 0x0 EC-IMPORTS-NEXT: } @@ -243,7 +243,7 @@ EC-IMPORTS-NEXT: Name: test.dll EC-IMPORTS-NEXT: Attributes: 0x1 EC-IMPORTS-NEXT: ModuleHandle: 0x6080 EC-IMPORTS-NEXT: ImportAddressTable: 0x6090 -EC-IMPORTS-NEXT: ImportNameTable: 0x4390 +EC-IMPORTS-NEXT: ImportNameTable: 0x4388 EC-IMPORTS-NEXT: BoundDelayImportTable: 0x0 EC-IMPORTS-NEXT: UnloadDelayImportTable: 0x0 EC-IMPORTS-NEXT: Import { @@ -279,28 +279,28 @@ EC-DISASM-NEXT: ... EC-DISASM-NEXT: 180003000: ff 25 8a 30 00 00 jmpq *0x308a(%rip) # 0x180006090 EC-DISASM-NEXT: 180003006: 48 8d 05 83 30 00 00 leaq 0x3083(%rip), %rax # 0x180006090 EC-DISASM-NEXT: 18000300d: e9 00 00 00 00 jmp 0x180003012 <.text+0x2012> -EC-DISASM-NEXT: 180003012: 51 pushq %rcx -EC-DISASM-NEXT: 180003013: 52 pushq %rdx -EC-DISASM-NEXT: 180003014: 41 50 pushq %r8 -EC-DISASM-NEXT: 180003016: 41 51 pushq %r9 -EC-DISASM-NEXT: 180003018: 48 83 ec 48 subq $0x48, %rsp -EC-DISASM-NEXT: 18000301c: 66 0f 7f 04 24 movdqa %xmm0, (%rsp) -EC-DISASM-NEXT: 180003021: 66 0f 7f 4c 24 10 movdqa %xmm1, 0x10(%rsp) -EC-DISASM-NEXT: 180003027: 66 0f 7f 54 24 20 movdqa %xmm2, 0x20(%rsp) -EC-DISASM-NEXT: 18000302d: 66 0f 7f 5c 24 30 movdqa %xmm3, 0x30(%rsp) -EC-DISASM-NEXT: 180003033: 48 8b d0 movq %rax, %rdx -EC-DISASM-NEXT: 180003036: 48 8d 0d 0b 13 00 00 leaq 0x130b(%rip), %rcx # 0x180004348 -EC-DISASM-NEXT: 18000303d: e8 c6 ef ff ff callq 0x180002008 <.text+0x1008> -EC-DISASM-NEXT: 180003042: 66 0f 6f 04 24 movdqa (%rsp), %xmm0 -EC-DISASM-NEXT: 180003047: 66 0f 6f 4c 24 10 movdqa 0x10(%rsp), %xmm1 -EC-DISASM-NEXT: 18000304d: 66 0f 6f 54 24 20 movdqa 0x20(%rsp), %xmm2 -EC-DISASM-NEXT: 180003053: 66 0f 6f 5c 24 30 movdqa 0x30(%rsp), %xmm3 -EC-DISASM-NEXT: 180003059: 48 83 c4 48 addq $0x48, %rsp -EC-DISASM-NEXT: 18000305d: 41 59 popq %r9 -EC-DISASM-NEXT: 18000305f: 41 58 popq %r8 -EC-DISASM-NEXT: 180003061: 5a popq %rdx -EC-DISASM-NEXT: 180003062: 59 popq %rcx -EC-DISASM-NEXT: 180003063: ff e0 jmpq *%rax +EC-DISASM-NEXT: 180003012: 48 89 4c 24 08 movq %rcx, 0x8(%rsp) +EC-DISASM-NEXT: 180003017: 48 89 54 24 10 movq %rdx, 0x10(%rsp) +EC-DISASM-NEXT: 18000301c: 4c 89 44 24 18 movq %r8, 0x18(%rsp) +EC-DISASM-NEXT: 180003021: 4c 89 4c 24 20 movq %r9, 0x20(%rsp) +EC-DISASM-NEXT: 180003026: 48 83 ec 68 subq $0x68, %rsp +EC-DISASM-NEXT: 18000302a: 66 0f 7f 44 24 20 movdqa %xmm0, 0x20(%rsp) +EC-DISASM-NEXT: 180003030: 66 0f 7f 4c 24 30 movdqa %xmm1, 0x30(%rsp) +EC-DISASM-NEXT: 180003036: 66 0f 7f 54 24 40 movdqa %xmm2, 0x40(%rsp) +EC-DISASM-NEXT: 18000303c: 66 0f 7f 5c 24 50 movdqa %xmm3, 0x50(%rsp) +EC-DISASM-NEXT: 180003042: 48 8b d0 movq %rax, %rdx +EC-DISASM-NEXT: 180003045: 48 8d 0d f4 12 00 00 leaq 0x12f4(%rip), %rcx # 0x180004340 +EC-DISASM-NEXT: 18000304c: e8 b7 ef ff ff callq 0x180002008 <.text+0x1008> +EC-DISASM-NEXT: 180003051: 66 0f 6f 44 24 20 movdqa 0x20(%rsp), %xmm0 +EC-DISASM-NEXT: 180003057: 66 0f 6f 4c 24 30 movdqa 0x30(%rsp), %xmm1 +EC-DISASM-NEXT: 18000305d: 66 0f 6f 54 24 40 movdqa 0x40(%rsp), %xmm2 +EC-DISASM-NEXT: 180003063: 66 0f 6f 5c 24 50 movdqa 0x50(%rsp), %xmm3 +EC-DISASM-NEXT: 180003069: 48 8b 4c 24 70 movq 0x70(%rsp), %rcx +EC-DISASM-NEXT: 18000306e: 48 8b 54 24 78 movq 0x78(%rsp), %rdx +EC-DISASM-NEXT: 180003073: 4c 8b 84 24 80 00 00 00 movq 0x80(%rsp), %r8 +EC-DISASM-NEXT: 18000307b: 4c 8b 8c 24 88 00 00 00 movq 0x88(%rsp), %r9 +EC-DISASM-NEXT: 180003083: 48 83 c4 68 addq $0x68, %rsp +EC-DISASM-NEXT: 180003087: ff e0 jmpq *%rax RUN: llvm-readobj --coff-load-config out-ec.dll | FileCheck --check-prefix=EC-LOADCFG %s EC-LOADCFG: AuxiliaryDelayloadIAT: 0x5000 diff --git a/lld/test/COFF/delayimports.test b/lld/test/COFF/delayimports.test index f410eef..ed074f4 100644 --- a/lld/test/COFF/delayimports.test +++ b/lld/test/COFF/delayimports.test @@ -10,7 +10,7 @@ IMPORT-NEXT: Name: std64.dll IMPORT-NEXT: Attributes: 0x1 IMPORT-NEXT: ModuleHandle: 0x3018 IMPORT-NEXT: ImportAddressTable: 0x3020 -IMPORT-NEXT: ImportNameTable: 0x2050 +IMPORT-NEXT: ImportNameTable: 0x2048 IMPORT-NEXT: BoundDelayImportTable: 0x0 IMPORT-NEXT: UnloadDelayImportTable: 0x0 IMPORT-NEXT: Import { @@ -44,22 +44,18 @@ BASEREL-NEXT: } UNWIND: UnwindInformation [ UNWIND-NEXT: RuntimeFunction { UNWIND-NEXT: StartAddress: (0x14000108A) -UNWIND-NEXT: EndAddress: (0x1400010DD) +UNWIND-NEXT: EndAddress: (0x140001101) UNWIND-NEXT: UnwindInfoAddress: (0x140002000) UNWIND-NEXT: UnwindInfo { UNWIND-NEXT: Version: 1 UNWIND-NEXT: Flags [ (0x0) UNWIND-NEXT: ] -UNWIND-NEXT: PrologSize: 10 +UNWIND-NEXT: PrologSize: 24 UNWIND-NEXT: FrameRegister: - UNWIND-NEXT: FrameOffset: - -UNWIND-NEXT: UnwindCodeCount: 5 +UNWIND-NEXT: UnwindCodeCount: 1 UNWIND-NEXT: UnwindCodes [ -UNWIND-NEXT: 0x0A: ALLOC_SMALL size=72 -UNWIND-NEXT: 0x06: ALLOC_SMALL size=8 -UNWIND-NEXT: 0x04: ALLOC_SMALL size=8 -UNWIND-NEXT: 0x02: ALLOC_SMALL size=8 -UNWIND-NEXT: 0x01: ALLOC_SMALL size=8 +UNWIND-NEXT: 0x18: ALLOC_SMALL size=104 UNWIND-NEXT: ] UNWIND-NEXT: } UNWIND-NEXT: } diff --git a/lld/test/COFF/delayimporttables.yaml b/lld/test/COFF/delayimporttables.yaml index cf54c0a..ff66812 100644 --- a/lld/test/COFF/delayimporttables.yaml +++ b/lld/test/COFF/delayimporttables.yaml @@ -15,7 +15,7 @@ # CHECK-NEXT: Attributes: 0x1 # CHECK-NEXT: ModuleHandle: 0x3000 # CHECK-NEXT: ImportAddressTable: 0x3010 -# CHECK-NEXT: ImportNameTable: 0x2070 +# CHECK-NEXT: ImportNameTable: 0x2068 # CHECK-NEXT: BoundDelayImportTable: 0x0 # CHECK-NEXT: UnloadDelayImportTable: 0x0 # CHECK-NEXT: Import { @@ -32,16 +32,16 @@ # CHECK-NEXT: Attributes: 0x1 # CHECK-NEXT: ModuleHandle: 0x3008 # CHECK-NEXT: ImportAddressTable: 0x3028 -# CHECK-NEXT: ImportNameTable: 0x2088 +# CHECK-NEXT: ImportNameTable: 0x2080 # CHECK-NEXT: BoundDelayImportTable: 0x0 # CHECK-NEXT: UnloadDelayImportTable: 0x0 # CHECK-NEXT: Import { # CHECK-NEXT: Symbol: left (0) -# CHECK-NEXT: Address: 0x1400010B8 +# CHECK-NEXT: Address: 0x1400010DC # CHECK-NEXT: } # CHECK-NEXT: Import { # CHECK-NEXT: Symbol: right (0) -# CHECK-NEXT: Address: 0x1400010C4 +# CHECK-NEXT: Address: 0x1400010E8 # CHECK-NEXT: } # CHECK-NEXT: } diff --git a/lld/test/COFF/dtlto/files.test b/lld/test/COFF/dtlto/files.test new file mode 100644 index 0000000..4297ada --- /dev/null +++ b/lld/test/COFF/dtlto/files.test @@ -0,0 +1,71 @@ +REQUIRES: x86 + +## Test that the LLD options /lldsavetemps and -thinlto-emit-imports-files +## function correctly with DTLTO we also check that index files +## (-thinlto-emit-index-files) are not emitted with DTLTO. + +RUN: rm -rf %t && split-file %s %t && cd %t + +RUN: sed 's/@t1/@t2/g' t1.ll > t2.ll + +## Generate ThinLTO bitcode files. Note that t3.bc will not be used by the +## linker. +RUN: opt -thinlto-bc t1.ll -o t1.bc +RUN: opt -thinlto-bc t2.ll -o t2.bc +RUN: cp t1.bc t3.bc + +## Generate object files for mock.py to return. +RUN: llc t1.ll --filetype=obj -o t1.obj +RUN: llc t2.ll --filetype=obj -o t2.obj + +## Create response file containing shared ThinLTO linker arguments. +## -start-lib/-end-lib is used to test the special case where unused lazy +## bitcode inputs result in empty index/imports files. +## Note that mock.py does not do any compilation; instead, it simply writes +## the contents of the object files supplied on the command line into the +## output object files in job order. +RUN: echo "/entry:t1 /subsystem:console \ +RUN: t1.bc t2.bc -start-lib t3.bc -end-lib /out:my.exe \ +RUN: -thinlto-distributor:\"%python\" \ +RUN: -thinlto-distributor-arg:\"%llvm_src_root/utils/dtlto/mock.py\" \ +RUN: -thinlto-distributor-arg:t1.obj \ +RUN: -thinlto-distributor-arg:t2.obj \ +RUN: -thinlto-remote-compiler:fake.exe" > l.rsp + +## Check that without extra flags, no index/imports files are produced and +## backend temp files are removed. +RUN: lld-link @l.rsp +RUN: ls | FileCheck %s \ +RUN: --check-prefixes=NOBACKEND,NOOTHERS + +## Check that with /lldsavetemps and -thinlto-emit-imports-files backend +## tempoary files are retained and no index/imports files are produced. +RUN: rm -f *.imports *.thinlto.bc +RUN: lld-link @l.rsp /lldsavetemps -thinlto-emit-imports-files +RUN: ls | sort | FileCheck %s \ +RUN: --check-prefixes=BACKEND,NOOTHERS + +## JSON jobs description, retained with --save-temps. +## Note that DTLTO temporary files include a PID component. +NOBACKEND-NOT: {{^}}my.[[#]].dist-file.json{{$}} +BACKEND: {{^}}my.[[#]].dist-file.json{{$}} + +## Index/imports files for t1.bc. +NOOTHERS-NOT: {{^}}t1.bc.imports{{$}} +NOOTHERS-NOT: {{^}}t1.bc.thinlto.bc{{$}} + +## Index/imports files for t2.bc. +NOOTHERS-NOT: {{^}}t2.bc.imports{{$}} +NOOTHERS-NOT: {{^}}t2.bc.thinlto.bc{{$}} + +## Empty index/imports files for unused t3.bc. +NOOTHERS-NOT: {{^}}t3.bc.imports{{$}} +NOOTHERS-NOT: {{^}}t3.bc.thinlto.bc{{$}} + +#--- t1.ll +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define void @t1() { + ret void +} diff --git a/lld/test/COFF/dtlto/options.test b/lld/test/COFF/dtlto/options.test new file mode 100644 index 0000000..023ecd2 --- /dev/null +++ b/lld/test/COFF/dtlto/options.test @@ -0,0 +1,56 @@ +REQUIRES: x86 + +## Test that DTLTO-specific options are handled correctly. + +RUN: rm -rf %t && split-file %s %t && cd %t + +RUN: opt -thinlto-bc foo.ll -o foo.obj + +## Not specifying a value for -thinlto-remote-compiler should result in an +## error if -thinlto-distributor is specified. +RUN: not lld-link /entry:foo /subsystem:console foo.obj /out:my.exe \ +RUN: -thinlto-distributor:fake.exe 2>&1 | FileCheck %s --check-prefix=COMPILER +RUN: lld-link /entry:foo /subsystem:console foo.obj /out:my.exe + +## Specifying an empty value for -thinlto-remote-compiler should result in an +## error if -thinlto-distributor is specified. +RUN: not lld-link /entry:foo /subsystem:console foo.obj /out:my.exe \ +RUN: -thinlto-distributor:fake.exe \ +RUN: -thinlto-remote-compiler:"" 2>&1 | FileCheck %s --check-prefix=COMPILER +RUN: lld-link /entry:foo /subsystem:console foo.obj /out:my.exe \ +RUN: -thinlto-remote-compiler:"" + +COMPILER: error: A value must be specified for /thinlto-remote-compiler if /thinlto-distributor is specified. + +## Test that DTLTO options are passed correctly to the distributor and +## remote compiler. +## Note: validate.py does not perform any compilation. Instead, it validates the +## received JSON, pretty-prints the JSON and the supplied arguments, and then +## exits with an error. This allows FileCheck directives to verify the +## distributor inputs. +RUN: not lld-link /entry:foo /subsystem:console foo.obj /out:my.exe \ +RUN: -thinlto-distributor:%python \ +RUN: -thinlto-distributor-arg:%llvm_src_root/utils/dtlto/validate.py \ +RUN: -thinlto-distributor-arg:darg1=10 \ +RUN: -thinlto-distributor-arg:darg2=20 \ +RUN: -thinlto-remote-compiler:my_clang.exe \ +RUN: -thinlto-remote-compiler-arg:carg1=20 \ +RUN: -thinlto-remote-compiler-arg:carg2=30 2>&1 | FileCheck %s + +CHECK: distributor_args=['darg1=10', 'darg2=20'] + +CHECK: "linker_output": "my.exe" + +CHECK: "my_clang.exe" +CHECK: "carg1=20" +CHECK: "carg2=30" + +CHECK: error: DTLTO backend compilation: cannot open native object file: + +#--- foo.ll +target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc" + +define void @foo() { + ret void +} diff --git a/lld/test/COFF/embed-bitcode.test b/lld/test/COFF/embed-bitcode.test new file mode 100644 index 0000000..10f88c5 --- /dev/null +++ b/lld/test/COFF/embed-bitcode.test @@ -0,0 +1,30 @@ +# RUN: yaml2obj %s -o %t.obj +# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj +# RUN: llvm-readobj -S %t.exe | FileCheck %s + +# CHECK-NOT: Name: .llvmbc +# CHECK-NOT: Name: .llvmcmd + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + SectionData: "C3" + - Name: .llvmbc + Characteristics: [ IMAGE_SCN_MEM_DISCARDABLE ] + SectionData: "4243C0DE" + - Name: .llvmcmd + Characteristics: [ IMAGE_SCN_MEM_DISCARDABLE ] + SectionData: "2D63633100" + +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/giats.s b/lld/test/COFF/giats.s index f870429..c044210 100644 --- a/lld/test/COFF/giats.s +++ b/lld/test/COFF/giats.s @@ -37,14 +37,14 @@ # DELAY-CHECK: ImageBase: 0x140000000 # DELAY-CHECK: LoadConfig [ -# DELAY-CHECK: GuardCFFunctionTable: 0x140002124 +# DELAY-CHECK: GuardCFFunctionTable: 0x14000211C # DELAY-CHECK: GuardCFFunctionCount: 2 # DELAY-CHECK: GuardFlags [ (0x10500) # DELAY-CHECK: CF_FUNCTION_TABLE_PRESENT (0x400) # DELAY-CHECK: CF_INSTRUMENTED (0x100) # DELAY-CHECK: CF_LONGJUMP_TABLE_PRESENT (0x10000) # DELAY-CHECK: ] -# DELAY-CHECK: GuardAddressTakenIatEntryTable: 0x14000212C +# DELAY-CHECK: GuardAddressTakenIatEntryTable: 0x140002124 # DELAY-CHECK: GuardAddressTakenIatEntryCount: 1 # DELAY-CHECK: ] # DELAY-CHECK: GuardFidTable [ diff --git a/lld/test/COFF/imported-dllmain-i386.test b/lld/test/COFF/imported-dllmain-i386.test new file mode 100644 index 0000000..f8aa090 --- /dev/null +++ b/lld/test/COFF/imported-dllmain-i386.test @@ -0,0 +1,58 @@ +REQUIRES: x86 +RUN: split-file %s %t.dir && cd %t.dir + +RUN: llvm-mc -filetype=obj -triple=i386-windows a.s -o a.obj + +RUN: llvm-mc -filetype=obj -triple=i386-windows b1.s -o b1.obj +RUN: llvm-mc -filetype=obj -triple=i386-windows b2.s -o b2.obj + +### This is the line where our problem occurs. Here, we export the DllMain symbol which shouldn't happen normally. +RUN: lld-link b1.obj b2.obj -out:b.dll -dll -implib:b.lib -entry:DllMain -export:bar -export:DllMain -safeseh:no + +RUN: llvm-mc -filetype=obj -triple=i386-windows c.s -o c.obj +RUN: lld-link -lib c.obj -out:c.lib + +### Later, if b.lib is provided before other libs/objs that export DllMain statically, we previously were using the dllimported DllMain from b.lib, which is wrong. +RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain -safeseh:no 2>&1 | FileCheck -check-prefix=WARN %s +RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain -ignore:importeddllmain -safeseh:no 2>&1 | FileCheck -check-prefix=IGNORED --allow-empty %s +RUN: llvm-objdump --private-headers -d out.dll | FileCheck -check-prefix=DISASM %s + +WARN: lld-link: warning: b.lib: skipping imported DllMain symbol [importeddllmain] +IGNORED-NOT: lld-link: warning: b.lib: skipping imported DllMain symbol [importeddllmain] + +DISASM: The Import Tables: +DISASM: DLL Name: b.dll +DISASM-NOT: DllMain +DISASM: bar +DISASM: Disassembly of section .text: +DISASM: b0 01 movb $0x1, %al +DISASM-NEXT: c3 retl + +#--- a.s + .text + .globl _foo +_foo: + call *__imp__bar + ret + +#--- b1.s + .text + .globl _bar +_bar: + ret + +#--- b2.s + .intel_syntax noprefix + .text + .globl _DllMain +_DllMain: + xor al, al + ret + +#--- c.s + .intel_syntax noprefix + .text + .globl _DllMain +_DllMain: + mov al, 1 + ret diff --git a/lld/test/COFF/exported-dllmain.test b/lld/test/COFF/imported-dllmain.test index fcf6ed1..fa8579b 100644 --- a/lld/test/COFF/exported-dllmain.test +++ b/lld/test/COFF/imported-dllmain.test @@ -14,11 +14,11 @@ RUN: lld-link -lib c.obj -out:c.lib ### Later, if b.lib is provided before other libs/objs that export DllMain statically, we previously were using the dllimported DllMain from b.lib, which is wrong. RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain 2>&1 | FileCheck -check-prefix=WARN %s -RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain -ignore:exporteddllmain 2>&1 | FileCheck -check-prefix=IGNORED --allow-empty %s +RUN: lld-link a.obj b.lib c.lib -dll -out:out.dll -entry:DllMain -ignore:importeddllmain 2>&1 | FileCheck -check-prefix=IGNORED --allow-empty %s RUN: llvm-objdump --private-headers -d out.dll | FileCheck -check-prefix=DISASM %s -WARN: lld-link: warning: b.lib: skipping exported DllMain symbol [exporteddllmain] -IGNORED-NOT: lld-link: warning: b.lib: skipping exported DllMain symbol [exporteddllmain] +WARN: lld-link: warning: b.lib: skipping imported DllMain symbol [importeddllmain] +IGNORED-NOT: lld-link: warning: b.lib: skipping imported DllMain symbol [importeddllmain] DISASM: The Import Tables: DISASM: DLL Name: b.dll diff --git a/lld/test/COFF/nodefaultlib.test b/lld/test/COFF/nodefaultlib.test index ceeb1f3..fbf6b43 100644 --- a/lld/test/COFF/nodefaultlib.test +++ b/lld/test/COFF/nodefaultlib.test @@ -1,5 +1,6 @@ -# RUN: cp %p/Inputs/hello64.obj %T -# RUN: cp %p/Inputs/std64.lib %T +# RUN: mkdir -p %t.dir +# RUN: cp %p/Inputs/hello64.obj %t.dir +# RUN: cp %p/Inputs/std64.lib %t.dir # RUN: not lld-link /out:%t.exe /entry:main /subsystem:console \ # RUN: hello64.obj /defaultlib:std64.lib >& %t.log @@ -9,12 +10,12 @@ # RUN: hello64 /defaultlib:std64.lib >& %t.log # RUN: FileCheck -DMSG=%errc_ENOENT -check-prefix=CHECK2 %s < %t.log -# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \ +# RUN: lld-link /libpath:%t.dir /out:%t.exe /entry:main \ # RUN: /subsystem:console hello64.obj /defaultlib:std64.lib \ # RUN: /nodefaultlib:std64.lib >& %t.log || true # RUN: FileCheck -check-prefix=CHECK3 %s < %t.log -# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \ +# RUN: lld-link /libpath:%t.dir /out:%t.exe /entry:main \ # RUN: /subsystem:console hello64.obj /defaultlib:std64 \ # RUN: /nodefaultlib:std64.lib >& %t.log || true # RUN: FileCheck -check-prefix=CHECK3 %s < %t.log @@ -24,10 +25,10 @@ CHECK2: error: could not open 'hello64': [[MSG]] CHECK3: error: undefined symbol: MessageBoxA CHECK3-NEXT: >>> referenced by {{.*}}hello64.obj:(main) -# RUN: lld-link /libpath:%T /out:%t.exe /entry:main \ +# RUN: lld-link /libpath:%t.dir /out:%t.exe /entry:main \ # RUN: /subsystem:console hello64.obj /defaultlib:std64.lib -# RUN: env LIB=%T lld-link /out:%t.exe /entry:main \ +# RUN: env LIB=%t.dir lld-link /out:%t.exe /entry:main \ # RUN: /subsystem:console hello64.obj /defaultlib:std64.lib MSVC stamps uppercase references in OBJ directives, thus ensure that passing lowercase 'libcmt' and 'oldnames' to /nodefaultlib works. @@ -37,11 +38,11 @@ MSVC stamps uppercase references in OBJ directives, thus ensure that passing low UPPERCASE-NOT: OLDNAMES UPPERCASE-NOT: LIBCMT -# RUN: yaml2obj -o %T/defaultlib.obj %p/Inputs/defaultlib.yaml +# RUN: yaml2obj -o %t.dir/defaultlib.obj %p/Inputs/defaultlib.yaml # RUN: mkdir -p %t.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x64 # RUN: cp %p/Inputs/ret42.lib %t.dir/sysroot/VC/Tools/MSVC/1.1.1.1/lib/x64/default.lib -# RUN: lld-link /winsysroot:%t.dir/sysroot /out:%t.exe /entry:main /subsystem:console %T/defaultlib.obj -# RUN: not lld-link /winsysroot:%t.dir/sysroot /out:%t.exe /entry:main /subsystem:console /nodefaultlib:default.lib %T/defaultlib.obj 2>&1 | FileCheck -check-prefix=CHECK4 %s +# RUN: lld-link /winsysroot:%t.dir/sysroot /out:%t.exe /entry:main /subsystem:console %t.dir/defaultlib.obj +# RUN: not lld-link /winsysroot:%t.dir/sysroot /out:%t.exe /entry:main /subsystem:console /nodefaultlib:default.lib %t.dir/defaultlib.obj 2>&1 | FileCheck -check-prefix=CHECK4 %s CHECK4: error: <root>: undefined symbol: main diff --git a/lld/test/COFF/pdb-empty-sec.s b/lld/test/COFF/pdb-empty-sec.s new file mode 100644 index 0000000..0d61447 --- /dev/null +++ b/lld/test/COFF/pdb-empty-sec.s @@ -0,0 +1,19 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-windows %s -o %t.obj +// RUN: lld-link -dll -noentry -debug %t.obj -out:%t.dll +// RUN: llvm-pdbutil dump -publics %t.pdb | FileCheck %s + +// CHECK: Records +// CHECK-NEXT: 0 | S_PUB32 [size = 20] `func` +// CHECK-NEXT: flags = none, addr = 0001:0000 +// CHECK-NEXT: 20 | S_PUB32 [size = 20] `sym` +// CHECK-NEXT: flags = none, addr = 0000:0000 + + .globl sym + .data +sym: + .text + .globl func +func: + ret diff --git a/lld/test/COFF/pdb-options.test b/lld/test/COFF/pdb-options.test index 70f6cbf..840040e 100644 --- a/lld/test/COFF/pdb-options.test +++ b/lld/test/COFF/pdb-options.test @@ -19,8 +19,10 @@ ; If /DEBUG is specified but not /pdb, it uses a default name in the current ; directory. This is a bit hacky since but we need to be IN our test specific ; temporary directory when we run this command or we can't test this -# RUN: cd %T -# RUN: lld-link /DEBUG /entry:main /nodefaultlib %t1.obj %t2.obj -# RUN: ls %t1.pdb -# RUN: rm %t* -# RUN: cd %T/.. +# RUN: mkdir -p %t.dir +# RUN: cp %t1.obj %t.dir/1.obj +# RUN: cp %t2.obj %t.dir/2.obj +# RUN: cd %t.dir +# RUN: lld-link /DEBUG /entry:main /nodefaultlib %t.dir/1.obj %t.dir/2.obj +# RUN: ls %t.dir/1.pdb +# RUN: rm -r %t* diff --git a/lld/test/COFF/pdb-type-server-invalid-signature.yaml b/lld/test/COFF/pdb-type-server-invalid-signature.yaml index 8f1528f..aedcefa 100644 --- a/lld/test/COFF/pdb-type-server-invalid-signature.yaml +++ b/lld/test/COFF/pdb-type-server-invalid-signature.yaml @@ -19,9 +19,10 @@ # VALID-SIGNATURE-NOT: The signature does not match; the file(s) might be out of date # Test an invalid path reference to a PDB type server; as a fallback LLD should try to load the PDB in the same path as the OBJ -# RUN: yaml2obj %S/Inputs/pdb-type-server-invalid-path.yaml -o %t3.obj -# RUN: cp %S/Inputs/pdb-diff-cl.pdb %T -# RUN: lld-link %t3.obj -out:%t3.exe -debug -pdb:%t3.pdb -nodefaultlib -entry:main 2>&1 | FileCheck -DMSG=%errc_ENOENT %s -check-prefix=INVALID-PATH -allow-empty +# RUN: mkdir -p %t.dir +# RUN: yaml2obj %S/Inputs/pdb-type-server-invalid-path.yaml -o %t.dir/3.obj +# RUN: cp %S/Inputs/pdb-diff-cl.pdb %t.dir/pdb-diff-cl.pdb +# RUN: lld-link %t.dir/3.obj -out:%t3.exe -debug -pdb:%t3.pdb -nodefaultlib -entry:main 2>&1 | FileCheck -DMSG=%errc_ENOENT %s -check-prefix=INVALID-PATH -allow-empty # INVALID-PATH-NOT: warning: Cannot use debug info for '{{.*}}3.obj' [LNK4099] # INVALID-PATH-NOT: failed to load reference 'c:\some_invalid_path_AABB98765\pdb-diff-cl.pdb': [[MSG]] diff --git a/lld/test/COFF/thin-archive.s b/lld/test/COFF/thin-archive.s index 55d71ea..7fab10c 100644 --- a/lld/test/COFF/thin-archive.s +++ b/lld/test/COFF/thin-archive.s @@ -22,23 +22,34 @@ # SYMTAB: ?f@@YAHXZ in # NO-SYMTAB-NOT: ?f@@YAHXZ in -# RUN: lld-link /entry:main %t.main.obj %t.lib /out:%t.exe 2>&1 | \ -# RUN: FileCheck --allow-empty %s -# RUN: lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe 2>&1 | \ -# RUN: FileCheck --allow-empty %s -# RUN: lld-link /entry:main %t.main.obj /wholearchive:%t_thin.lib /out:%t.exe 2>&1 | \ -# RUN: FileCheck --allow-empty %s +# RUN: echo "/entry:main \"%t.main.obj\" /out:\"%t.exe\"" > %t.rsp + +# RUN: lld-link @%t.rsp %t.lib /verbose 2>&1 | \ +# RUN: FileCheck %s --check-prefix=LOAD_NON_THIN +# RUN: lld-link @%t.rsp %t_thin.lib /verbose 2>&1 | \ +# RUN: FileCheck %s --check-prefix=LOAD_THIN_SYM +# RUN: lld-link @%t.rsp /wholearchive:%t_thin.lib /verbose 2>&1 | \ +# RUN: FileCheck %s --check-prefix=LOAD_THIN_WHOLE +# RUN: lld-link @%t.rsp /wholearchive %t_thin.lib /verbose 2>&1 | \ +# RUN: FileCheck %s --check-prefix=LOAD_THIN_WHOLE + +# LOAD_NON_THIN: Loaded {{.*}}.lib({{.*}}.obj) for int __cdecl f(void) +# LOAD_THIN_SYM: Loaded {{.*}}.obj for int __cdecl f(void) +# LOAD_THIN_WHOLE: Loaded {{.*}}.obj for <whole-archive> # RUN: rm %t.lib.obj -# RUN: lld-link /entry:main %t.main.obj %t.lib /out:%t.exe 2>&1 | \ -# RUN: FileCheck --allow-empty %s -# RUN: env LLD_IN_TEST=1 not lld-link /entry:main %t.main.obj %t_thin.lib \ -# RUN: /out:%t.exe 2>&1 | FileCheck --check-prefix=NOOBJ %s -# RUN: env LLD_IN_TEST=1 not lld-link /entry:main %t.main.obj %t_thin.lib /out:%t.exe \ -# RUN: /demangle:no 2>&1 | FileCheck --check-prefix=NOOBJNODEMANGLE %s - -# CHECK-NOT: error: could not get the buffer for the member defining +# RUN: lld-link @%t.rsp %t.lib 2>&1 | \ +# RUN: FileCheck %s --check-prefix=ERR --allow-empty +# RUN: env LLD_IN_TEST=1 not lld-link @%t.rsp %t_thin.lib 2>&1 | \ +# RUN: FileCheck %s --check-prefix=NOOBJ +# RUN: env LLD_IN_TEST=1 not lld-link @%t.rsp /wholearchive:%t_thin.lib 2>&1 | \ +# RUN: FileCheck %s --check-prefix=NOOBJWHOLE +# RUN: env LLD_IN_TEST=1 not lld-link @%t.rsp %t_thin.lib /demangle:no 2>&1 | \ +# RUN: FileCheck %s --check-prefix=NOOBJNODEMANGLE + +# ERR-NOT: error: could not get the buffer for the member defining # NOOBJ: error: could not get the buffer for the member defining symbol int __cdecl f(void): {{.*}}.lib({{.*}}.lib.obj): +# NOOBJWHOLE: error: {{.*}}.lib: could not get the buffer for a child of the archive: '{{.*}}.obj' # NOOBJNODEMANGLE: error: could not get the buffer for the member defining symbol ?f@@YAHXZ: {{.*}}.lib({{.*}}.lib.obj): .text diff --git a/lld/test/COFF/wrap-lto-2.ll b/lld/test/COFF/wrap-lto-2.ll index c50feab..4c74ff2 100644 --- a/lld/test/COFF/wrap-lto-2.ll +++ b/lld/test/COFF/wrap-lto-2.ll @@ -23,28 +23,30 @@ ;; the wrapped symbol, when LTO or ThinLTO is involved. It checks for various ;; combinations of bitcode and regular objects. +; RUN: mkdir -p %t.dir + ;; LTO + LTO -; RUN: lld-link -out:%t.bc-bc.exe %t.main.bc -libpath:%T %t.bc.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps +; RUN: lld-link -out:%t.bc-bc.exe %t.main.bc -libpath:%t.dir %t.bc.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps ; RUN: llvm-objdump -d %t.bc-bc.exe | FileCheck %s --check-prefixes=CHECK,JMP ;; LTO + Object -; RUN: lld-link -out:%t.bc-obj.exe %t.main.bc -libpath:%T %t.obj.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps +; RUN: lld-link -out:%t.bc-obj.exe %t.main.bc -libpath:%t.dir %t.obj.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps ; RUN: llvm-objdump -d %t.bc-obj.exe | FileCheck %s --check-prefixes=CHECK,JMP ;; Object + LTO -; RUN: lld-link -out:%t.obj-bc.exe %t.main.obj -libpath:%T %t.bc.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps +; RUN: lld-link -out:%t.obj-bc.exe %t.main.obj -libpath:%t.dir %t.bc.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps ; RUN: llvm-objdump -d %t.obj-bc.exe | FileCheck %s --check-prefixes=CHECK,CALL ;; ThinLTO + ThinLTO -; RUN: lld-link -out:%t.thin-thin.exe %t.main.thin -libpath:%T %t.thin.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps +; RUN: lld-link -out:%t.thin-thin.exe %t.main.thin -libpath:%t.dir %t.thin.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps ; RUN: llvm-objdump -d %t.thin-thin.exe | FileCheck %s --check-prefixes=CHECK,JMP ;; ThinLTO + Object -; RUN: lld-link -out:%t.thin-obj.exe %t.main.thin -libpath:%T %t.obj.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps +; RUN: lld-link -out:%t.thin-obj.exe %t.main.thin -libpath:%t.dir %t.obj.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps ; RUN: llvm-objdump -d %t.thin-obj.exe | FileCheck %s --check-prefixes=CHECK,JMP ;; Object + ThinLTO -; RUN: lld-link -out:%t.obj-thin.exe %t.main.obj -libpath:%T %t.thin.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps +; RUN: lld-link -out:%t.obj-thin.exe %t.main.obj -libpath:%t.dir %t.thin.lib -entry:entry -subsystem:console -wrap:bar -debug:symtab -lldsavetemps ; RUN: llvm-objdump -d %t.obj-thin.exe | FileCheck %s --check-prefixes=CHECK,CALL ;; Make sure that calls in entry() are not eliminated and that bar is diff --git a/lld/test/COFF/wrap-with-archive.s b/lld/test/COFF/wrap-with-archive.s index 96b244a..d8a4fdb 100644 --- a/lld/test/COFF/wrap-with-archive.s +++ b/lld/test/COFF/wrap-with-archive.s @@ -6,7 +6,8 @@ // RUN: rm -f %t.lib // RUN: llvm-ar rcs %t.lib %t.wrap.obj %t.other.obj -// RUN: lld-link -out:%t.exe %t.main.obj -libpath:%T %t.lib -entry:entry -subsystem:console -wrap:foo +// RUN: mkdir -p %t.dir +// RUN: lld-link -out:%t.exe %t.main.obj -libpath:%t.dir %t.lib -entry:entry -subsystem:console -wrap:foo // Note: No real definition of foo exists here, but that works fine as long // as there's no actual references to __real_foo. diff --git a/lld/test/ELF/aarch64-build-attributes-be.s b/lld/test/ELF/aarch64-build-attributes-be.s new file mode 100644 index 0000000..8ae9ce5 --- /dev/null +++ b/lld/test/ELF/aarch64-build-attributes-be.s @@ -0,0 +1,29 @@ +// REQUIRES: aarch64 +// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o +// RUN: ld.lld %t.o --shared -o %t.so +// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE + +// RUN: llvm-mc -triple=aarch64_be %s -filetype=obj -o %t.o +// RUN: ld.lld %t.o --shared -o %t.so +// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE +// RUN: ld.lld %t.o -o %t +// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE +// RUN: ld.lld -r %t.o -o %t2.o +// RUN: llvm-readelf -n %t.so | FileCheck %s --check-prefix=NOTE + +/// Test that lld can read big-endian build-attributes. + +// NOTE: Displaying notes found in: .note.gnu.property +// NOTE-NEXT: Owner Data size Description +// NOTE-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note) +// NOTE-NEXT: Properties: aarch64 feature: BTI, PAC, GCS +// NOTE-NEXT: AArch64 PAuth ABI core info: platform 0x89abcdef (unknown), version 0x89abcdef + + +.aeabi_subsection aeabi_pauthabi, required, uleb128 +.aeabi_attribute Tag_PAuth_Platform, 0x123456789ABCDEF +.aeabi_attribute Tag_PAuth_Schema, 0x123456789ABCDEF +.aeabi_subsection aeabi_feature_and_bits, optional, uleb128 +.aeabi_attribute Tag_Feature_BTI, 1 +.aeabi_attribute Tag_Feature_PAC, 1 +.aeabi_attribute Tag_Feature_GCS, 1 diff --git a/lld/test/ELF/aarch64-build-attributes-err.s b/lld/test/ELF/aarch64-build-attributes-err.s new file mode 100644 index 0000000..ca04f4c --- /dev/null +++ b/lld/test/ELF/aarch64-build-attributes-err.s @@ -0,0 +1,35 @@ +// REQUIRES: aarch64 + +// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o +// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ERR + +// ERR: GNU properties and build attributes have conflicting AArch64 PAuth data +// ERR-NEXT: GNU properties and build attributes have conflicting AArch64 PAuth data + +.aeabi_subsection aeabi_pauthabi, required, uleb128 +.aeabi_attribute Tag_PAuth_Platform, 5 +.aeabi_attribute Tag_PAuth_Schema, 5 +.aeabi_subsection aeabi_feature_and_bits, optional, uleb128 +.aeabi_attribute Tag_Feature_BTI, 1 +.aeabi_attribute Tag_Feature_PAC, 1 +.aeabi_attribute Tag_Feature_GCS, 1 + +.section ".note.gnu.property", "a" +.long 0x4 +.long 0x10 +.long 0x5 +.asciz "GNU" +.long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND +.long 0x4 +.long 0x2 // GNU_PROPERTY_AARCH64_FEATURE_1_PAC +.long 0x0 + +.section ".note.gnu.property", "a" +.long 0x4 +.long 0x18 +.long 0x5 +.asciz "GNU" +.long 0xc0000001 +.long 0x10 +.quad 0x12345678 // platform +.quad 0x87654321 // version diff --git a/lld/test/ELF/aarch64-build-attributes-invalid.s b/lld/test/ELF/aarch64-build-attributes-invalid.s new file mode 100644 index 0000000..7cd4723 --- /dev/null +++ b/lld/test/ELF/aarch64-build-attributes-invalid.s @@ -0,0 +1,18 @@ +// REQUIRES: aarch64 + +// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t.o +// RUN: ld.lld -r %t.o -o %t.invalid.o +// RUN: llvm-readelf -n %t.invalid.o | FileCheck %s + +/// According to the BuildAttributes specification Build Attributes +/// A (TagPlatform, TagSchema)of (0, 1) maps to an explicit PAuth property +/// of platform = 0, version = 0 ('Invalid'). + +// CHECK: Displaying notes found in: .note.gnu.property +// CHECK-NEXT: Owner Data size Description +// CHECK-NEXT: GNU 0x00000018 NT_GNU_PROPERTY_TYPE_0 (property note) +// CHECK-NEXT: Properties: AArch64 PAuth ABI core info: platform 0x0 (invalid), version 0x0 + +.aeabi_subsection aeabi_pauthabi, required, uleb128 +.aeabi_attribute Tag_PAuth_Platform, 0 +.aeabi_attribute Tag_PAuth_Schema, 1 diff --git a/lld/test/ELF/aarch64-build-attributes-malformed.s b/lld/test/ELF/aarch64-build-attributes-malformed.s new file mode 100644 index 0000000..c8a0fd6 --- /dev/null +++ b/lld/test/ELF/aarch64-build-attributes-malformed.s @@ -0,0 +1,18 @@ +# REQUIRES: aarch64 + +# RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t.o +# RUN: ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: (.ARM.attributes): unexpected end of data at offset 0x3f while reading [0x3d, 0x41) + +.section .ARM.attributes,"",%0x70000003 +.byte 0x41 // Tag 'A' (format version) +.long 0x00000019 // Subsection length +.asciz "aeabi_pauthabi" // Subsection name +.byte 0x00, 0x00 // Optionality and Type +.byte 0x01, 0x01, 0x02, 0x01 // PAuth_Platform and PAuth_Schema +.long 0x00000023 // Subsection length +.asciz "aeabi_feature_and_bits" // Subsection name +.byte 0x01, 0x00 // Optionality and Type +.byte 0x00, 0x01, 0x01, 0x01, 0x02, 0x01 // BTI, PAC, GCS +.byte 0x00, 0x00 // This is the malformation, data is too long. diff --git a/lld/test/ELF/aarch64-build-attributes-mixed.s b/lld/test/ELF/aarch64-build-attributes-mixed.s new file mode 100644 index 0000000..68e9a1f --- /dev/null +++ b/lld/test/ELF/aarch64-build-attributes-mixed.s @@ -0,0 +1,67 @@ +// REQUIRES: aarch64 + +// RUN: rm -rf %t && split-file %s %t && cd %t + +// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t11.o +// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-property.s -o %t12.o +// RUN: llvm-mc -triple=aarch64 -filetype=obj merged-property2.s -o %t13.o +// RUN: ld.lld -r %t11.o %t12.o %t13.o -o %t.merged1.o +// RUN: llvm-readelf -n %t.merged1.o | FileCheck %s --check-prefix=NOTE-MIXED + +/// This test verifies merging of AArch64 build attributes and GNU property notes. +/// Three object files are combined: one with build attributes (PAuth information, BTI, PAC, GCS), +/// and two with GNU property notes encoding the same feature bits. +/// PAuth ABI info is provided in one of the files and it is expected to be preserved in the merged output. + +// NOTE-MIXED: Displaying notes found in: .note.gnu.property +// NOTE-MIXED-NEXT: Owner Data size Description +// NOTE-MIXED-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note) +// NOTE-MIXED-NEXT: Properties: aarch64 feature: BTI, PAC +// NOTE-MIXED-NEXT: AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13 + +// CHECK: .note.gnu.property +// CHECK-NOT: .ARM.attributes + +.aeabi_subsection aeabi_pauthabi, required, uleb128 +.aeabi_attribute Tag_PAuth_Platform, 49 +.aeabi_attribute Tag_PAuth_Schema, 19 +.aeabi_subsection aeabi_feature_and_bits, optional, uleb128 +.aeabi_attribute Tag_Feature_BTI, 1 +.aeabi_attribute Tag_Feature_PAC, 1 +.aeabi_attribute Tag_Feature_GCS, 1 + + +//--- merged-property.s +.section ".note.gnu.property", "a" + .long 0x4 // Name length is always 4 ("GNU") + .long end - begin // Data length + .long 0x5 // Type: NT_GNU_PROPERTY_TYPE_0 + .asciz "GNU" // Name + .p2align 0x3 +begin: + .long 0xc0000000 // GNU_PROPERTY_AARCH64_FEATURE_1_AND + .long 0x4 + .long 0x7 // pr_data: BTI (1), PAC (2), GCS (4) = 0b111 = 7 + .long 0x0 + // PAuth ABI property note + .long 0xc0000001 // GNU_PROPERTY_AARCH64_FEATURE_PAUTH + .long 0x10 // Data length + .quad 0x31 // PAuth ABI platform + .quad 0x13 // PAuth ABI version + .p2align 0x3 // Align to 8 byte for 64 bit +end: + +//--- merged-property2.s +.section .note.gnu.property, "a" + .align 0x4 + .long 0x4 // Name length is always 4 ("GNU") + .long end2 - begin2 // Data length + .long 0x5 // Type: NT_GNU_PROPERTY_TYPE_0 + .asciz "GNU" // Name +begin2: + .align 0x4 + .long 0xc0000000 // Type: GNU_PROPERTY_AARCH64_FEATURE_1_AND + .long 0x4 // Data length + .long 0x7 // pr_data: BTI (1), PAC (2), GCS (4) = 0b111 = 7 + .long 0x0 +end2: diff --git a/lld/test/ELF/aarch64-build-attributes.s b/lld/test/ELF/aarch64-build-attributes.s index 24e15f9..f2d5421 100644 --- a/lld/test/ELF/aarch64-build-attributes.s +++ b/lld/test/ELF/aarch64-build-attributes.s @@ -1,26 +1,50 @@ // REQUIRES: aarch64 -// RUN: llvm-mc -triple=aarch64 %s -filetype=obj -o %t.o -// RUN: ld.lld %t.o --shared -o %t.so -// RUN: llvm-readelf --sections %t.so | FileCheck %s -// RUN: ld.lld %t.o -o %t -// RUN: llvm-readelf --sections %t | FileCheck %s -// RUN: ld.lld -r %t.o -o %t2.o -// RUN: llvm-readelf --sections %t2.o | FileCheck %s - -/// File has a Build attributes section. This should not appear in -/// ET_EXEC or ET_SHARED files as there is no requirement for it to -/// do so. FIXME, the ld -r (relocatable link) should output a single -/// merged build attributes section. When full support is added in -/// ld.lld this test should be updated. +// RUN: rm -rf %t && split-file %s %t && cd %t +// RUN: llvm-mc -triple=aarch64 -filetype=obj %s -o %t1.o +// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-gcs.s -o %t2.o +// RUN: llvm-mc -triple=aarch64 -filetype=obj pauth-bti-pac.s -o %t3.o +// RUN: ld.lld -r %t1.o %t2.o %t3.o -o %t.merged.o +// RUN: llvm-readelf -n %t.merged.o | FileCheck %s --check-prefix=NOTE + +/// This test merges three object files with AArch64 build attributes. +/// All contain identical PAuth ABI info (platform/version), which must be preserved. +/// Only BTI is common across all three in the AND feature set, so the merged output +/// must show BTI only. PAC and GCS are present in subsets and should not appear. + +// NOTE: Displaying notes found in: .note.gnu.property +// NOTE-NEXT: Owner Data size Description +// NOTE-NEXT: GNU 0x00000028 NT_GNU_PROPERTY_TYPE_0 (property note) +// NOTE-NEXT: Properties: aarch64 feature: BTI +// NOTE-NEXT: AArch64 PAuth ABI core info: platform 0x31 (unknown), version 0x13 + +// CHECK: .note.gnu.property // CHECK-NOT: .ARM.attributes +.aeabi_subsection aeabi_pauthabi, required, uleb128 +.aeabi_attribute Tag_PAuth_Platform, 49 +.aeabi_attribute Tag_PAuth_Schema, 19 .aeabi_subsection aeabi_feature_and_bits, optional, uleb128 .aeabi_attribute Tag_Feature_BTI, 1 .aeabi_attribute Tag_Feature_PAC, 1 .aeabi_attribute Tag_Feature_GCS, 1 -.global _start -.type _start, %function -_start: -ret + +//--- pauth-bti-gcs.s +.aeabi_subsection aeabi_pauthabi, required, uleb128 +.aeabi_attribute Tag_PAuth_Platform, 49 +.aeabi_attribute Tag_PAuth_Schema, 19 +.aeabi_subsection aeabi_feature_and_bits, optional, uleb128 +.aeabi_attribute Tag_Feature_BTI, 1 +.aeabi_attribute Tag_Feature_PAC, 0 +.aeabi_attribute Tag_Feature_GCS, 1 + + +//--- pauth-bti-pac.s +.aeabi_subsection aeabi_pauthabi, required, uleb128 +.aeabi_attribute Tag_PAuth_Platform, 49 +.aeabi_attribute Tag_PAuth_Schema, 19 +.aeabi_subsection aeabi_feature_and_bits, optional, uleb128 +.aeabi_attribute Tag_Feature_BTI, 1 +.aeabi_attribute Tag_Feature_PAC, 1 +.aeabi_attribute Tag_Feature_GCS, 0 diff --git a/lld/test/ELF/bp-section-orderer.s b/lld/test/ELF/bp-section-orderer.s index 4df2e8d..438d7c2 100644 --- a/lld/test/ELF/bp-section-orderer.s +++ b/lld/test/ELF/bp-section-orderer.s @@ -26,28 +26,28 @@ # RUN: ld.lld -o out.s a.o --irpgo-profile=a.profdata --bp-startup-sort=function # RUN: llvm-nm -jn out.s | tr '\n' , | FileCheck %s --check-prefix=STARTUP -# STARTUP: s5,s4,s3,s2,s1,A,B,C,F,E,D,merged1,merged2,_start,d4,d3,d2,d1,{{$}} +# STARTUP: s5,s4,s3,s2,s1,A,B,C,F,E,D,merged1,merged2,_start,d4,d3,d2,d1,g1,{{$}} # RUN: ld.lld -o out.os a.o --irpgo-profile=a.profdata --bp-startup-sort=function --symbol-ordering-file a.txt # RUN: llvm-nm -jn out.os | tr '\n' , | FileCheck %s --check-prefix=ORDER-STARTUP -# ORDER-STARTUP: s2,s1,s5,s4,s3,A,F,E,D,B,C,merged1,merged2,_start,d3,d2,d4,d1,{{$}} +# ORDER-STARTUP: s2,s1,s5,s4,s3,A,F,E,D,B,C,merged1,merged2,_start,d3,d2,d4,d1,g1,{{$}} # RUN: ld.lld -o out.cf a.o --verbose-bp-section-orderer --bp-compression-sort=function 2>&1 | FileCheck %s --check-prefix=BP-COMPRESSION-FUNC # RUN: ld.lld -o out.cf.icf a.o --verbose-bp-section-orderer --bp-compression-sort=function --icf=all --gc-sections 2>&1 | FileCheck %s --check-prefix=BP-COMPRESSION-ICF-FUNC # RUN: llvm-nm -jn out.cf | tr '\n' , | FileCheck %s --check-prefix=CFUNC -# CFUNC: s5,s4,s3,s2,s1,A,F,merged1,merged2,C,E,D,B,_start,d4,d3,d2,d1,{{$}} +# CFUNC: s5,s4,s3,s2,s1,A,F,merged1,merged2,C,E,D,B,_start,d4,d3,d2,d1,g1,{{$}} # RUN: ld.lld -o out.cd a.o --verbose-bp-section-orderer --bp-compression-sort=data 2>&1 | FileCheck %s --check-prefix=BP-COMPRESSION-DATA # RUN: llvm-nm -jn out.cd | tr '\n' , | FileCheck %s --check-prefix=CDATA -# CDATA: s5,s3,s4,s2,s1,F,C,E,D,B,A,merged1,merged2,_start,d4,d1,d3,d2,{{$}} +# CDATA: s5,s3,s4,s2,s1,F,C,E,D,B,A,merged1,merged2,_start,d4,d1,d3,d2,g1,{{$}} # RUN: ld.lld -o out.cb a.o --verbose-bp-section-orderer --bp-compression-sort=both 2>&1 | FileCheck %s --check-prefix=BP-COMPRESSION-BOTH # RUN: llvm-nm -jn out.cb | tr '\n' , | FileCheck %s --check-prefix=CBOTH -# CBOTH: s5,s3,s4,s2,s1,A,F,merged1,merged2,C,E,D,B,_start,d4,d1,d3,d2,{{$}} +# CBOTH: s5,s3,s4,s2,s1,A,F,merged1,merged2,C,E,D,B,_start,d4,d1,d3,d2,g1,{{$}} # RUN: ld.lld -o out.cbs a.o --verbose-bp-section-orderer --bp-compression-sort=both --irpgo-profile=a.profdata --bp-startup-sort=function 2>&1 | FileCheck %s --check-prefix=BP-COMPRESSION-BOTH # RUN: llvm-nm -jn out.cbs | tr '\n' , | FileCheck %s --check-prefix=CBOTH-STARTUP -# CBOTH-STARTUP: s5,s3,s4,s2,s1,A,B,C,F,E,D,merged1,merged2,_start,d4,d1,d3,d2,{{$}} +# CBOTH-STARTUP: s5,s3,s4,s2,s1,A,B,C,F,E,D,merged1,merged2,_start,d4,d1,d3,d2,g1,{{$}} # BP-COMPRESSION-FUNC: Ordered 9 sections ([[#]] bytes) using balanced partitioning # BP-COMPRESSION-ICF-FUNC: Ordered 8 sections ([[#]] bytes) using balanced partitioning @@ -108,6 +108,7 @@ d3 d2 #--- a.c +int g1; const char s5[] = "engineering"; const char s4[] = "computer program"; const char s3[] = "hardware engineer"; @@ -377,6 +378,14 @@ d1: .word 6 // 0x6 .size d1, 16 + .type g1,@object // @g1 + .section .bss.g1,"aw",@nobits + .globl g1 + .p2align 2, 0x0 +g1: + .word 0 // 0x0 + .size g1, 4 + .section ".note.GNU-stack","",@progbits .addrsig .addrsig_sym F diff --git a/lld/test/ELF/hexagon-jump-error.s b/lld/test/ELF/hexagon-jump-error.s deleted file mode 100644 index 53860b5..0000000 --- a/lld/test/ELF/hexagon-jump-error.s +++ /dev/null @@ -1,32 +0,0 @@ -# REQUIRES: hexagon -# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %s -o %t.o -## Use --threads=1 to keep emitted warnings across sections sequential. -# RUN: not ld.lld %t.o -o /dev/null --threads=1 2>&1 | FileCheck --implicit-check-not "out of range" %s - - .globl _start - .type _start, @function -_start: - -# CHECK: relocation R_HEX_B9_PCREL out of range: 1028 is not in [-1024, 1023] -{r0 = #0; jump #1f} -.space (1<<10) -.section b9, "ax" -1: - -# CHECK: relocation R_HEX_B13_PCREL out of range: 16388 is not in [-16384, 16383] -if (r0==#0) jump:t #1f -.space (1<<14) -.section b13, "ax" -1: - -# CHECK: relocation R_HEX_B15_PCREL out of range: 65540 is not in [-65536, 65535] -if (p0) jump #1f -.space (1<<16) -.section b15, "ax" -1: - -# CHECK: relocation R_HEX_B22_PCREL out of range: 8388612 is not in [-8388608, 8388607] -jump #1f -.space (1<<23) -.section b22, "ax" -1: diff --git a/lld/test/ELF/hexagon-plt.s b/lld/test/ELF/hexagon-plt.s index 679de82..780dc43 100644 --- a/lld/test/ELF/hexagon-plt.s +++ b/lld/test/ELF/hexagon-plt.s @@ -30,31 +30,31 @@ # DIS: <_start>: ## Direct call ## Call foo directly -# DIS-NEXT: { call 0x2003c } +# DIS-NEXT: { call 0x2003c <foo> } ## Call bar via plt -# DIS-NEXT: { call 0x20060 } +# DIS-NEXT: { call 0x20060 <bar@plt> } ## Call weak via plt -# DIS-NEXT: { call 0x20070 } +# DIS-NEXT: { call 0x20070 <weak@plt> } # DIS-NEXT: { immext(#0) ## Call foo directly -# DIS-NEXT: if (p0) jump:nt 0x2003c } +# DIS-NEXT: if (p0) jump:nt 0x2003c <foo> } # DIS-NEXT: { immext(#64) ## Call bar via plt -# DIS-NEXT: if (p0) jump:nt 0x20060 } +# DIS-NEXT: if (p0) jump:nt 0x20060 <bar@plt> } # DIS-NEXT: { immext(#64) ## Call weak via plt -# DIS-NEXT: if (p0) jump:nt 0x20070 } +# DIS-NEXT: if (p0) jump:nt 0x20070 <weak@plt> } # DIS-NEXT: { immext(#0) ## Call foo directly -# DIS-NEXT: r0 = #0 ; jump 0x2003c } +# DIS-NEXT: r0 = #0 ; jump 0x2003c <foo> } # DIS-NEXT: { immext(#0) ## Call bar via plt -# DIS-NEXT: r0 = #0 ; jump 0x20060 } +# DIS-NEXT: r0 = #0 ; jump 0x20060 <bar@plt> } # DIS-NEXT: { immext(#0) ## Call weak via plt -# DIS-NEXT: r0 = #0 ; jump 0x20070 } +# DIS-NEXT: r0 = #0 ; jump 0x20070 <weak@plt> } # DIS: <foo>: # DIS-NEXT: 2003c: diff --git a/lld/test/ELF/hexagon-shared.s b/lld/test/ELF/hexagon-shared.s index cc62662..7f7390f 100644 --- a/lld/test/ELF/hexagon-shared.s +++ b/lld/test/ELF/hexagon-shared.s @@ -88,7 +88,7 @@ pvar: # PLT-NEXT: jumpr r28 } # TEXT: bc 00 01 00 000100bc -# TEXT: { call 0x10300 } +# TEXT: { call 0x10300 <bar@plt> } # TEXT: if (p0) jump:nt 0x10300 # TEXT: r0 = #0 ; jump 0x10300 # TEXT: r0 = add(r1,##-65548) diff --git a/lld/test/ELF/hexagon-thunk-range-b22rel.s b/lld/test/ELF/hexagon-thunk-range-b22rel.s new file mode 100644 index 0000000..08e37bf --- /dev/null +++ b/lld/test/ELF/hexagon-thunk-range-b22rel.s @@ -0,0 +1,115 @@ +# REQUIRES: hexagon +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf main.s -o main.o +# RUN: ld.lld main.o -o test +# RUN: llvm-objdump -d --no-show-raw-insn test | FileCheck %s + +## Test thunk range scenarios for Hexagon R_HEX_B22_PCREL relocations. +## R_HEX_B22_PCREL has a range of +/- 8MB (0x800000 bytes). + +#--- main.s +.globl _start +.type _start, %function +_start: + call target_within_range_max + call target_beyond_range + call target_within_range_min + call target_beyond_range_min + call target_multiple_calls + call target_multiple_calls + call target_close + jumpr r31 + +target_close: + jumpr r31 + +## Target at maximum positive range (8MB - 4 bytes from _start) +## We need to account for the instructions above: 7 calls + 1 jumpr = 8 * 4 = 32 bytes +.skip 0X7fffbc +.globl target_within_range_max +.type target_within_range_max, %function +target_within_range_max: + jumpr r31 + +## Target just beyond maximum positive range (needs thunk) +.skip 8 +.globl target_beyond_range +.type target_beyond_range, %function +target_beyond_range: + call target_within_range_max + jumpr r31 + +## Target for multiple calls test +.skip 0x100000 +.globl target_multiple_calls +.type target_multiple_calls, %function +target_multiple_calls: + jumpr r31 + +## Now place targets at maximum negative range +## We'll put these before _start in memory layout +.section .text_negative, "ax", %progbits + +## Target at maximum negative range (-8MB + 4 bytes from _start) +.globl target_within_range_min +.type target_within_range_min, %function +target_within_range_min: + call target_close + jumpr r31 + +.skip 0X7ffff4 + +## Target beyond maximum negative range (needs thunk) +.globl target_beyond_range_min +.type target_beyond_range_min, %function +target_beyond_range_min: + jumpr r31 + +## Verify thunk generation for targets beyond B22_PCREL range +# CHECK: <__hexagon_thunk_target_within_range_min_from_.text.thunk>: +# CHECK-NEXT: 200b4: { immext(#0x900000) +# CHECK-NEXT: jump 0x9200cc <target_within_range_min> } + +# CHECK: <__hexagon_thunk_target_beyond_range_min_from_.text.thunk>: +# CHECK-NEXT: 200bc: { immext(#0x1100000) +# CHECK-NEXT: jump 0x11200c8 <target_beyond_range_min> } + +# CHECK: <__hexagon_thunk_target_multiple_calls_from_.text.thunk>: +# CHECK-NEXT: 200c4: { immext(#0x8fffc0) +# CHECK-NEXT: jump 0x9200c0 <target_multiple_calls> } + +## Verify _start calls - some direct, some via thunks +# CHECK: <_start>: +# CHECK-NEXT: 200cc: { call 0x8200ac <target_within_range_max> } +# CHECK-NEXT: { call 0x8200b8 <target_beyond_range> } +# CHECK-NEXT: { call 0x200b4 <__hexagon_thunk_target_within_range_min_from_.text.thunk> } +# CHECK-NEXT: { call 0x200bc <__hexagon_thunk_target_beyond_range_min_from_.text.thunk> } +# CHECK-NEXT: { call 0x200c4 <__hexagon_thunk_target_multiple_calls_from_.text.thunk> } +# CHECK-NEXT: { call 0x200c4 <__hexagon_thunk_target_multiple_calls_from_.text.thunk> } +# CHECK-NEXT: { call 0x200ec <target_close> } + +# CHECK: <target_close>: +# CHECK-NEXT: 200ec: { jumpr r31 } + +## Verify targets at maximum positive range (direct calls, no thunks needed) +# CHECK: <target_within_range_max>: +# CHECK-NEXT: 8200ac: { jumpr r31 } + +# CHECK: <target_beyond_range>: +# CHECK-NEXT: 8200b8: { call 0x8200ac <target_within_range_max> } +# CHECK-NEXT: { jumpr r31 } + +# CHECK: <target_multiple_calls>: +# CHECK-NEXT: 9200c0: { jumpr r31 } + +## Verify targets in negative section and thunk for calling back to main section +# CHECK: <__hexagon_thunk__from_.text.thunk>: +# CHECK-NEXT: 9200c4: { immext(#0xff700000) +# CHECK-NEXT: jump 0x200cc <_start> } + +# CHECK: <target_within_range_min>: +# CHECK-NEXT: 9200cc: { call 0x9200c4 <__hexagon_thunk__from_.text.thunk> } +# CHECK-NEXT: { jumpr r31 } + +# CHECK: <target_beyond_range_min>: +# CHECK-NEXT: 11200c8: { jumpr r31 } diff --git a/lld/test/ELF/hexagon-thunk-range-gdplt.s b/lld/test/ELF/hexagon-thunk-range-gdplt.s new file mode 100644 index 0000000..77fd0e5 --- /dev/null +++ b/lld/test/ELF/hexagon-thunk-range-gdplt.s @@ -0,0 +1,95 @@ +# REQUIRES: hexagon +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf main.s -o main.o +# RUN: ld.lld -shared main.o -o test.so +# RUN: llvm-objdump -d --no-show-raw-insn test.so | FileCheck %s + +## Test thunk range scenarios for Hexagon R_HEX_GD_PLT_B22_PCREL relocations. +## Same ±8MB range as regular calls. + +#--- main.s +.globl _start +.type _start, @function +_start: + ## Setup for TLS Global Dynamic calls + r2 = add(pc,##_GLOBAL_OFFSET_TABLE_@PCREL) + + ## Test TLS GD PLT calls + r0 = add(r2,##tls_var_close@GDGOT) + call tls_var_close@GDPLT + + r0 = add(r2,##tls_var_far@GDGOT) + call tls_var_far@GDPLT + + jumpr r31 + +.skip 0x400000 + +more_code: + r0 = add(r2,##tls_var_distant@GDGOT) + call tls_var_distant@GDPLT + jumpr r31 + +## TLS variables in .tdata section +.section .tdata,"awT",@progbits +.globl tls_var_close, tls_var_far, tls_var_distant +.type tls_var_close, @object +.type tls_var_far, @object +.type tls_var_distant, @object + +tls_var_close: + .word 0x1234 + +tls_var_far: + .word 0x5678 + +tls_var_distant: + .word 0x9abc + +# CHECK: Disassembly of section .text: +# CHECK: <_start>: +# CHECK-NEXT: 102d4: { immext(#0x420100) +# CHECK-NEXT: r2 = add(pc,##0x420130) } +# CHECK-NEXT: { immext(#0xfffeffc0) +# CHECK-NEXT: r0 = add(r2,##-0x10018) } +# CHECK-NEXT: { call 0x410360 <__tls_get_addr@plt> } +# CHECK-NEXT: { immext(#0xfffeffc0) +# CHECK-NEXT: r0 = add(r2,##-0x10010) } +# CHECK-NEXT: { call 0x410360 <__tls_get_addr@plt> } +# CHECK-NEXT: { jumpr r31 } + +# CHECK: <more_code>: +# CHECK-NEXT: 4102f8: { immext(#0xfffeffc0) +# CHECK-NEXT: r0 = add(r2,##-0x10008) } +# CHECK-NEXT: { call 0x410360 <__tls_get_addr@plt> } +# CHECK-NEXT: { jumpr r31 } + +## Verify PLT entries are created for TLS +# CHECK: Disassembly of section .plt: +# CHECK: <.plt>: +# CHECK-NEXT: 410310: { immext(#0x200c0) +# CHECK-NEXT: r28 = add(pc,##0x200f4) } +# CHECK-NEXT: { r14 -= add(r28,#0x10) +# CHECK-NEXT: r15 = memw(r28+#0x8) +# CHECK-NEXT: r28 = memw(r28+#0x4) } +# CHECK-NEXT: { r14 = asr(r14,#0x2) +# CHECK-NEXT: jumpr r28 } +# CHECK-NEXT: { trap0(#0xdb) } + +# CHECK: <tls_var_far@plt>: +# CHECK-NEXT: 410340: { immext(#0x200c0) +# CHECK-NEXT: r14 = add(pc,##0x200d8) } +# CHECK-NEXT: { r28 = memw(r14+#0x0) } +# CHECK-NEXT: { jumpr r28 } + +# CHECK: <tls_var_distant@plt>: +# CHECK-NEXT: 410350: { immext(#0x200c0) +# CHECK-NEXT: r14 = add(pc,##0x200cc) } +# CHECK-NEXT: { r28 = memw(r14+#0x0) } +# CHECK-NEXT: { jumpr r28 } + +# CHECK: <__tls_get_addr@plt>: +# CHECK-NEXT: 410360: { immext(#0x200c0) +# CHECK-NEXT: r14 = add(pc,##0x200c0) } +# CHECK-NEXT: { r28 = memw(r14+#0x0) } +# CHECK-NEXT: { jumpr r28 } diff --git a/lld/test/ELF/hexagon-thunk-range-plt.s b/lld/test/ELF/hexagon-thunk-range-plt.s new file mode 100644 index 0000000..3a8f50b --- /dev/null +++ b/lld/test/ELF/hexagon-thunk-range-plt.s @@ -0,0 +1,75 @@ +# REQUIRES: hexagon +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf external.s -o external.o +# RUN: ld.lld -shared external.o -soname external.so -o external.so +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf main.s -o main.o +# RUN: ld.lld main.o external.so -o test +# RUN: llvm-objdump -d --no-show-raw-insn test | FileCheck %s + +## Test thunk range scenarios for Hexagon R_HEX_PLT_B22_PCREL relocations. +## PLT calls use the same ±8MB range as regular calls but go through PLT entries. +## This test verifies thunk generation for PLT calls at range boundaries. + +#--- external.s +.globl extern_within_range, extern_beyond_range, extern_close +.type extern_within_range, @function +.type extern_beyond_range, @function +.type extern_close, @function + +extern_within_range: + jumpr r31 + +extern_beyond_range: + jumpr r31 + +extern_close: + jumpr r31 + +#--- main.s +.globl _start +.type _start, @function +_start: + ## Test PLT calls to external functions at various ranges + call extern_within_range@PLT + call extern_beyond_range@PLT + call extern_close@PLT + jumpr r31 + +.skip 0x200000 + +# CHECK: Disassembly of section .text: +# CHECK: <_start>: +# CHECK-NEXT: 2021c: { call 0x220250 <extern_within_range@plt> } +# CHECK-NEXT: { call 0x220260 <extern_beyond_range@plt> } +# CHECK-NEXT: { call 0x220270 <extern_close@plt> } +# CHECK-NEXT: { jumpr r31 } + +## Verify PLT header and entries are created with exact addresses +# CHECK: Disassembly of section .plt: +# CHECK: <.plt>: +# CHECK-NEXT: 220230: { immext(#0x20080) +# CHECK-NEXT: r28 = add(pc,##0x200b8) } +# CHECK-NEXT: { r14 -= add(r28,#0x10) +# CHECK-NEXT: r15 = memw(r28+#0x8) +# CHECK-NEXT: r28 = memw(r28+#0x4) } +# CHECK-NEXT: { r14 = asr(r14,#0x2) +# CHECK-NEXT: jumpr r28 } +# CHECK-NEXT: { trap0(#0xdb) } + +# CHECK: <extern_within_range@plt>: +# CHECK-NEXT: 220250: { immext(#0x20080) +# CHECK-NEXT: r14 = add(pc,##0x200a8) } +# CHECK-NEXT: { r28 = memw(r14+#0x0) } +# CHECK-NEXT: { jumpr r28 } + +# CHECK: <extern_beyond_range@plt>: +# CHECK-NEXT: 220260: { immext(#0x20080) +# CHECK-NEXT: r14 = add(pc,##0x2009c) } +# CHECK-NEXT: { r28 = memw(r14+#0x0) } +# CHECK-NEXT: { jumpr r28 } + +# CHECK: <extern_close@plt>: +# CHECK-NEXT: 220270: { immext(#0x20080) +# CHECK-NEXT: r14 = add(pc,##0x20090) } +# CHECK-NEXT: { r28 = memw(r14+#0x0) } +# CHECK-NEXT: { jumpr r28 } diff --git a/lld/test/ELF/hexagon-thunks-packets.s b/lld/test/ELF/hexagon-thunks-packets.s new file mode 100644 index 0000000..c8aaad4 --- /dev/null +++ b/lld/test/ELF/hexagon-thunks-packets.s @@ -0,0 +1,122 @@ +# REQUIRES: hexagon +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-linux-musl %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-objdump -d %t 2>&1 | \ +# RUN: FileCheck --check-prefixes=CHECK-NONPIC,CHECK %s +# RUN: llvm-mc -filetype=obj \ +# RUN: -triple=hexagon-unknown-linux-musl %s -o %t.o +# RUN: ld.lld --pie %t.o -o %t +# RUN: llvm-objdump -d %t 2>&1 | \ +# RUN: FileCheck --check-prefixes=CHECK-PIC,CHECK %s + +## Packets with pc-relative relocations are more interesting because +## the offset must be relative to the start of the source, destination +## packets and not necessarily the instruction word containing the jump/call. + +# CHECK: Disassembly of section .text: + +# CHECK-NONPIC: 000200b4 <__hexagon_thunk_myfn_a_from_.text.thunk>: +# CHECK-NONPIC: { immext(#0x1000040) +# CHECK-NONPIC: jump 0x1020110 <myfn_a> } + +# CHECK-PIC: 00010150 <__hexagon_thunk_myfn_a_from_.text.thunk>: +# CHECK-PIC-NEXT: { immext(#0x1000040) +# CHECK-PIC-NEXT: r14 = add(pc,##0x1000060) } +# CHECK-PIC-NEXT: { jumpr r14 } + +# CHECK-NONPIC: 000200bc <myfn_b>: +# CHECK-NONPIC: { jumpr r31 } +# CHECK-PIC: 0001015c <myfn_b>: +# CHECK-PIC: { jumpr r31 } + .globl myfn_b + .type myfn_b, @function +myfn_b: + jumpr r31 + .size myfn_b, .-myfn_b + +# CHECK-PIC: 00010160 <main>: + .globl main + .type main, @function +main: + { r0 = #0 + call myfn_a } +# CHECK-PIC: { call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC: { call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NEXT: r0 = #0x0 } + call myfn_a +# CHECK-PIC: call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC: call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> + call myfn_b +# CHECK-PIC-NEXT: call 0x1015c <myfn_b> +# CHECK-NONPIC-NEXT: call 0x200bc <myfn_b> + + { r2 = add(r0, r1) + if (p0) call #myfn_b + if (!p0) call #myfn_a } +# CHECK-PIC-NEXT: { if (p0) call 0x1015c <myfn_b> +# CHECK-PIC-NEXT: if (!p0) call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC-NEXT: { if (p0) call 0x200bc <myfn_b> +# CHECK-NONPIC-NEXT: if (!p0) call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> + +# CHECK-NEXT: r2 = add(r0,r1) } + + { r2 = add(r0, r1) + if (p0) call #myfn_a + if (!p0) call #myfn_a } +# CHECK-PIC-NEXT: { if (p0) call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC-NEXT: if (!p0) call 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC-NEXT: { if (p0) call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NONPIC-NEXT: if (!p0) call 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NEXT: r2 = add(r0,r1) } + + { r2 = add(r0, r1) + r1 = r4 + r4 = r5 + if (r0 == #0) jump:t #myfn_a } +# CHECK-PIC-NEXT: { if (r0==#0) jump:t 0x10150 +# CHECK-NONPIC-NEXT: { if (r0==#0) jump:t 0x200b4 +# CHECK-NEXT: r2 = add(r0,r1) +# CHECK-NEXT: r1 = r4; r4 = r5 } + + { r2 = add(r0, r1) + r4 = r5 + if (r0 <= #0) jump:t #myfn_a + p1 = cmp.eq(r0, #0); if (p1.new) jump:nt #myfn_a } +# CHECK-NONPIC-NEXT: { if (r0<=#0) jump:t 0x200b4 +# CHECK-NONPIC-NEXT: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-PIC-NEXT: { if (r0<=#0) jump:t 0x10150 +# CHECK-PIC-NEXT: p1 = cmp.eq(r0,#0x0); if (p1.new) jump:nt 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> +# CHECK-NEXT: r2 = add(r0,r1) +# CHECK-NEXT: r4 = r5 } + + {r0 = #0; jump #myfn_a} +# CHECK-PIC-NEXT: { r0 = #0x0 ; jump 0x10150 <__hexagon_thunk_myfn_a_from_.text.thunk> } +# CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x200b4 <__hexagon_thunk_myfn_a_from_.text.thunk> } + {r0 = #0; jump #myfn_b} +# CHECK-PIC-NEXT: { r0 = #0x0 ; jump 0x1015c <myfn_b> } +# CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x200bc <myfn_b> } + jumpr r31 + .size main, .-main + + .section .text.foo + .skip 0x1000000 + + .globl myfn_a + .type myfn_a, @function +myfn_a: + {r0 = #0; jump #myfn_b} + jumpr r31 + .size myfn_a, .-myfn_a + +# CHECK-NONPIC: 01020110 <myfn_a>: +# CHECK-NONPIC-NEXT: { r0 = #0x0 ; jump 0x1020118 <__hexagon_thunk_myfn_b_from_.text.thunk> } +# CHECK-NONPIC-NEXT: { jumpr r31 } + +# CHECK-NONPIC: 01020118 <__hexagon_thunk_myfn_b_from_.text.thunk>: +# CHECK-NONPIC-NEXT: { immext(#0xfeffff80) +# CHECK-NONPIC-NEXT: jump 0x200bc <myfn_b> } + +# CHECK-PIC: 010101b8 <__hexagon_thunk_myfn_b_from_.text.thunk>: +# CHECK-PIC-NEXT: { immext(#0xfeffff80) +# CHECK-PIC-NEXT: r14 = add(pc,##0xfeffffa4) } +# CHECK-PIC-NEXT: { jumpr r14 } diff --git a/lld/test/ELF/hexagon-thunks.s b/lld/test/ELF/hexagon-thunks.s new file mode 100644 index 0000000..211074e --- /dev/null +++ b/lld/test/ELF/hexagon-thunks.s @@ -0,0 +1,53 @@ +# REQUIRES: hexagon +# RUN: rm -rf %t && split-file %s %t +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %t/a.s -o %t/a.o +# RUN: ld.lld -T %t/lds %t/a.o -o %t/a +# RUN: llvm-objdump -d --no-show-raw-insn %t/a 2>&1 | \ +# RUN: FileCheck --check-prefixes=CHECK-NONPIC,CHECK %s +# RUN: llvm-mc -filetype=obj \ +# RUN: -triple=hexagon-unknown-elf %t/a.s -o %t/a.o + +# RUN: ld.lld -T %t/lds --pie %t/a.o -o %t/a +# RUN: llvm-objdump -d --no-show-raw-insn %t/a 2>&1 | \ +# RUN: FileCheck --check-prefixes=CHECK-PIC,CHECK %s + +#--- a.s +.section .text_low, "ax", %progbits + .globl main + .type main, @function +main: + call myfn + jumpr r31 + .size main, .-main + +.section .text_high, "ax", %progbits + .globl myfn + .type myfn, @function +myfn: + jumpr r31 + .size myfn, .-myfn + +# CHECK: Disassembly of section .text_low: + +# CHECK: <__hexagon_thunk_myfn_from_.text.thunk>: +# CHECK-NONPIC-NEXT: 200b4: { immext(#0x1000000) +# CHECK-NONPIC-NEXT: jump 0x10200bc <myfn> } +# CHECK-PIC-NEXT: 200b4: { immext(#0x1000000) +# CHECK-PIC-NEXT: r14 = add(pc,##0x1000008) } +# CHECK-PIC-NEXT: { jumpr r14 } + +# CHECK-NONPIC: <main>: +# CHECK-NONPIC-NEXT: 200bc: { call 0x200b4 <__hexagon_thunk_myfn_from_.text.thunk> } +# CHECK-PIC: <main>: +# CHECK-PIC-NEXT: 200c0: { call 0x200b4 <__hexagon_thunk_myfn_from_.text.thunk> } +# CHECK-NEXT: { jumpr r31 } + +# CHECK: Disassembly of section .text_high: +# CHECK: <myfn>: +# CHECK-NEXT: 10200bc: { jumpr r31 } + +#--- lds +SECTIONS { + .text_low 0x200b4: { *(.text_low) } + .text_high 0x10200bc : { *(.text_high) } +} diff --git a/lld/test/ELF/hexagon-tls-allocateaux-multiple.s b/lld/test/ELF/hexagon-tls-allocateaux-multiple.s new file mode 100644 index 0000000..a77cc82 --- /dev/null +++ b/lld/test/ELF/hexagon-tls-allocateaux-multiple.s @@ -0,0 +1,36 @@ +# REQUIRES: hexagon +# RUN: rm -rf %t && split-file %s %t && cd %t +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf a.s -o a.o +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf b.s -o b.o +# RUN: ld.lld -shared a.o b.o -o out.so +# RUN: llvm-readobj -r out.so | FileCheck --check-prefix=RELOC %s + +#--- a.s +.globl _start +.type _start, @function + +_start: + r2 = add(pc,##_GLOBAL_OFFSET_TABLE_@PCREL) + r0 = add(r2,##tls_var@GDGOT) + call tls_var@GDPLT + jumpr r31 + +.section .tdata,"awT",@progbits +.globl tls_var +.type tls_var, @object +tls_var: + .word 0x1234 + +#--- b.s +.globl other_func +.type other_func, @function + +other_func: + ## Direct call to __tls_get_addr - this creates another path that may + ## try to allocate auxiliary data for the same symbol + call __tls_get_addr + jumpr r31 + +# RELOC: Section ({{.*}}) .rela.plt { +# RELOC: R_HEX_JMP_SLOT __tls_get_addr 0x0 +# RELOC: } diff --git a/lld/test/ELF/hexagon-tls-gd-xform.s b/lld/test/ELF/hexagon-tls-gd-xform.s index 65aeb11..ade54e8 100644 --- a/lld/test/ELF/hexagon-tls-gd-xform.s +++ b/lld/test/ELF/hexagon-tls-gd-xform.s @@ -18,10 +18,10 @@ _start: .ifdef GDPLT call x@gdplt -# CHECK_GDPLT: 101ec: { call 0x10220 } +# CHECK_GDPLT: 101ec: { call 0x10220 <__tls_get_addr@plt> } .else call x -# CHECK: 101b8: { call 0x101e0 } +# CHECK: 101b8: { call 0x101e0 <x@plt> } .endif # CHECK_GDPLT: 10220: { immext(#0x20040) diff --git a/lld/test/ELF/keep-data-section-prefix.s b/lld/test/ELF/keep-data-section-prefix.s new file mode 100644 index 0000000..4b08f53 --- /dev/null +++ b/lld/test/ELF/keep-data-section-prefix.s @@ -0,0 +1,89 @@ +# REQUIRES: x86 + +# RUN: rm -rf %t && split-file %s %t && cd %t + +# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o + +# RUN: ld.lld -z keep-data-section-prefix -T x.lds a.o -o out1 +# RUN: llvm-readelf -l out1 | FileCheck --check-prefixes=SEG,LS %s +# RUN: llvm-readelf -S out1 | FileCheck %s --check-prefix=CHECK-LS + +# RUN: ld.lld -z keep-data-section-prefix a.o -o out2 +# RUN: llvm-readelf -l out2 | FileCheck --check-prefixes=SEG,PRE %s +# RUN: llvm-readelf -S out2 | FileCheck %s --check-prefix=CHECK-PRE + +# RUN: ld.lld a.o -o out3 +# RUN: llvm-readelf -l out3 | FileCheck --check-prefixes=SEG,PRE %s +# RUN: llvm-readelf -S out3 | FileCheck %s --check-prefix=CHECK-PRE + +# RUN: not ld.lld -T x.lds a.o 2>&1 | FileCheck %s +# CHECK: error: section: .relro_padding is not contiguous with other relro sections + +## The first RW PT_LOAD segment has FileSiz 0x126f (0x1000 + 0x200 + 0x60 + 0xf), +## and its p_offset p_vaddr p_paddr p_filesz should match PT_GNU_RELRO. +# Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# SEG: LOAD 0x0001c8 0x00000000002011c8 0x00000000002011c8 0x000001 0x000001 R E 0x1000 +# SEG-NEXT: LOAD 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x00126f 0x001e37 RW 0x1000 +# SEG-NEXT: LOAD 0x001438 0x0000000000204438 0x0000000000204438 0x000001 0x000002 RW 0x1000 +# SEG-NEXT: GNU_RELRO 0x0001c9 0x00000000002021c9 0x00000000002021c9 0x00126f 0x001e37 R 0x1 +# SEG-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0x0 + +## Input to output mapping per linker script +## .data.rel.ro.split -> .data.rel.ro +## .data.rel.ro -> .data.rel.ro +## .data.rel.ro.hot -> .data.rel.ro.hot +## .data.rel.ro.unlikely -> .data.rel.ro.unlikely +# LS: .text +# LS-NEXT: .data.rel.ro.hot .data.rel.ro .data.rel.ro.unlikely .relro_padding +# LS-NEXT: .data .bss + +# [Nr] Name Type Address Off Size +# CHECK-LS: .data.rel.ro.hot PROGBITS 00000000002021c9 0001c9 00000f +# CHECK-LS-NEXT: .data.rel.ro PROGBITS 00000000002021d8 0001d8 000260 +# CHECK-LS-NEXT: .data.rel.ro.unlikely PROGBITS 0000000000202438 000438 001000 +# CHECK-LS-NEXT: .relro_padding NOBITS 0000000000203438 001438 000bc8 +# CHECK-LS-NEXT: .data PROGBITS 0000000000204438 001438 000001 +# CHECK-LS-NEXT: .bss NOBITS 0000000000204439 001439 000001 + +## Linker script is not provided to map data sections. +## So all input sections with prefix .data.rel.ro will map to .data.rel.ro in the output. +# PRE: .text +# PRE-NEXT: .data.rel.ro .relro_padding +# PRE-NEXT: .data .bss + +# [Nr] Name Type Address Off Size +# CHECK-PRE: .data.rel.ro PROGBITS 00000000002021c9 0001c9 00126f +# CHECK-PRE-NEXT: .relro_padding NOBITS 0000000000203438 001438 000bc8 +# CHECK-PRE-NEXT: .data PROGBITS 0000000000204438 001438 000001 +# CHECK-PRE-NEXT: .bss NOBITS 0000000000204439 001439 000001 + +#--- x.lds +SECTIONS { + .data.rel.ro.hot : { *(.data.rel.ro.hot) } + .data.rel.ro : { .data.rel.ro } + .data.rel.ro.unlikely : { *(.data.rel.ro.unlikely) } +} INSERT AFTER .text + + +#--- a.s +.globl _start +_start: + ret + +.section .data.rel.ro.hot, "aw" +.space 15 + +.section .data.rel.ro, "aw" +.space 96 + +.section .data.rel.ro.split,"aw" +.space 512 + +.section .data.rel.ro.unlikely, "aw" +.space 4096 + +.section .data, "aw" +.space 1 + +.section .bss, "aw" +.space 1 diff --git a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s index a417d89..a33f866 100644 --- a/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s +++ b/lld/test/ELF/loongarch-relax-pc-hi20-lo12.s @@ -1,22 +1,23 @@ # REQUIRES: loongarch +# RUN: rm -rf %t && split-file %s %t && cd %t -# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax %s -o %t.32.o -# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax %s -o %t.64.o +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax a.s -o a.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax a.s -o a.64.o -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -o %t.32 -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -o %t.64 -# RUN: llvm-objdump -td --no-show-raw-insn %t.32 | FileCheck --check-prefixes=RELAX %s -# RUN: llvm-objdump -td --no-show-raw-insn %t.64 | FileCheck --check-prefixes=RELAX %s +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.32.o -o a.32 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.64.o -o a.64 +# RUN: llvm-objdump -td --no-show-raw-insn a.32 | FileCheck --check-prefixes=RELAX %s +# RUN: llvm-objdump -td --no-show-raw-insn a.64 | FileCheck --check-prefixes=RELAX %s -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.32.o -shared -o %t.32s -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 %t.64.o -shared -o %t.64s -# RUN: llvm-objdump -td --no-show-raw-insn %t.32s | FileCheck --check-prefixes=RELAX %s -# RUN: llvm-objdump -td --no-show-raw-insn %t.64s | FileCheck --check-prefixes=RELAX %s +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.32.o -shared -o a.32s +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 a.64.o -shared -o a.64s +# RUN: llvm-objdump -td --no-show-raw-insn a.32s | FileCheck --check-prefixes=RELAX %s +# RUN: llvm-objdump -td --no-show-raw-insn a.64s | FileCheck --check-prefixes=RELAX %s -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.32.o -o %t.32o -# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 %t.64.o -o %t.64o -# RUN: llvm-objdump -td --no-show-raw-insn %t.32o | FileCheck --check-prefixes=NORELAX32 %s -# RUN: llvm-objdump -td --no-show-raw-insn %t.64o | FileCheck --check-prefixes=NORELAX64 %s +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 a.32.o -o a.32o +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x410000 a.64.o -o a.64o +# RUN: llvm-objdump -td --no-show-raw-insn a.32o | FileCheck --check-prefixes=NORELAX32 %s +# RUN: llvm-objdump -td --no-show-raw-insn a.64o | FileCheck --check-prefixes=NORELAX64 %s # RELAX-LABEL: <_start>: ## offset = 0x14000 - 0x10000 = 4096<<2 @@ -49,6 +50,25 @@ # NORELAX64-NEXT: pcalau12i $a0, 1024 # NORELAX64-NEXT: ld.d $a0, $a0, 8 + +## GOT references with non-zero addends. No relaxation. +# RUN: llvm-mc --filetype=obj --triple=loongarch32 -mattr=+relax nonzero.s -o nonzero.32.o +# RUN: llvm-mc --filetype=obj --triple=loongarch64 -mattr=+relax nonzero.s -o nonzero.64.o +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.32.o -o nonzero.32 +# RUN: ld.lld --section-start=.text=0x10000 --section-start=.data=0x14000 nonzero.64.o -o nonzero.64 +# RUN: llvm-objdump -td --no-show-raw-insn nonzero.32 | FileCheck --check-prefixes=NONZERO32 %s +# RUN: llvm-objdump -td --no-show-raw-insn nonzero.64 | FileCheck --check-prefixes=NONZERO64 %s + +# NONZERO32-LABEL: <_start>: +# NONZERO32-NEXT: 10000: pcalau12i $a0, 4 +# NONZERO32-NEXT: ld.w $a0, $a0, 8 + +# NONZERO64-LABEL: <_start>: +# NONZERO64-NEXT: 10000: pcalau12i $a0, 4 +# NONZERO64-NEXT: ld.d $a0, $a0, 12 + + +#--- a.s .section .text .global _start _start: @@ -60,3 +80,14 @@ _start: .section .data sym: .zero 4 + + +#--- nonzero.s +.section .text +.global _start +_start: + la.got $a0, sym+4 + +.section .data +sym: + .zero 4 diff --git a/lld/test/ELF/loongarch-relax-tlsdesc.s b/lld/test/ELF/loongarch-relax-tlsdesc.s index 5f43683..025cbc0 100644 --- a/lld/test/ELF/loongarch-relax-tlsdesc.s +++ b/lld/test/ELF/loongarch-relax-tlsdesc.s @@ -9,7 +9,6 @@ # RUN: llvm-readobj -r -x .got a.64.so | FileCheck --check-prefix=GD64-RELA %s # RUN: llvm-objdump --no-show-raw-insn -dr -h a.64.so | FileCheck %s --check-prefix=GD64 -## FIXME: IE/LE relaxation have not yet been implemented, --relax/--no-relax obtain the same results. ## Transition from TLSDESC to IE/LE. Also check --emit-relocs. # RUN: ld.lld -e 0 -z now --emit-relocs a.64.o c.64.o -o a.64.le # RUN: llvm-readobj -r -x .got a.64.le 2>&1 | FileCheck --check-prefix=LE64-RELA %s @@ -73,25 +72,21 @@ # LE64-RELA: could not find section '.got' ## a@tprel = 0x8 -# LE64: 20158: nop +# LE64: 20158: ori $a0, $zero, 8 # LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 a # LE64-NEXT: R_LARCH_RELAX *ABS* -# LE64-NEXT: nop # LE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 a # LE64-NEXT: R_LARCH_RELAX *ABS* -# LE64-NEXT: nop # LE64-NEXT: R_LARCH_TLS_DESC_LD a # LE64-NEXT: R_LARCH_RELAX *ABS* -# LE64-NEXT: ori $a0, $zero, 8 # LE64-NEXT: R_LARCH_TLS_DESC_CALL a # LE64-NEXT: R_LARCH_RELAX *ABS* # LE64-NEXT: add.d $a1, $a0, $tp ## b@tprel = 0x7ff -# LE64: 2016c: nop +# LE64: 20160: nop # LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 b # LE64-NEXT: R_LARCH_RELAX *ABS* -# LE64-NEXT: nop # LE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 b # LE64-NEXT: nop # LE64-NEXT: R_LARCH_TLS_DESC_LD b @@ -101,7 +96,7 @@ ## c@tprel = 0x800 ## Without R_LARCH_RELAX relocation. No relaxation. -# LE64: 20180: nop +# LE64: 20170: nop # LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 c # LE64-NEXT: addi.d $t0, $zero, 0 # LE64-NEXT: nop @@ -115,13 +110,11 @@ # LE64-NEXT: add.d $a3, $a0, $tp ## d@tprel = 0x1000 -# LE64: 201a0: nop +# LE64: 20190: lu12i.w $a0, 1 # LE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 d # LE64-NEXT: R_LARCH_RELAX *ABS* -# LE64-NEXT: nop # LE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 d # LE64-NEXT: R_LARCH_RELAX *ABS* -# LE64-NEXT: lu12i.w $a0, 1 # LE64-NEXT: R_LARCH_TLS_DESC_LD d # LE64-NEXT: ori $a0, $a0, 0 # LE64-NEXT: R_LARCH_TLS_DESC_CALL d @@ -160,35 +153,31 @@ # LE64-NORELAX-NEXT: add.d $a4, $a0, $tp # IE64-RELA: .rela.dyn { -# IE64-RELA-NEXT: 0x30408 R_LARCH_TLS_TPREL64 c 0x0 -# IE64-RELA-NEXT: 0x30410 R_LARCH_TLS_TPREL64 d 0x0 +# IE64-RELA-NEXT: 0x303F0 R_LARCH_TLS_TPREL64 c 0x0 +# IE64-RELA-NEXT: 0x303F8 R_LARCH_TLS_TPREL64 d 0x0 # IE64-RELA-NEXT: } # IE64-RELA: Hex dump of section '.got': -# IE64-RELA-NEXT: 0x00030408 00000000 00000000 00000000 00000000 . +# IE64-RELA-NEXT: 0x000303f0 00000000 00000000 00000000 00000000 . -# IE64: .got 00000010 0000000000030408 +# IE64: .got 00000010 00000000000303f0 ## a and b are optimized to use LE. c and d are optimized to IE. ## a@tprel = 0x8 -# IE64: 202c8: nop +# IE64: 202c8: ori $a0, $zero, 8 # IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 a # IE64-NEXT: R_LARCH_RELAX *ABS* -# IE64-NEXT: nop # IE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 a # IE64-NEXT: R_LARCH_RELAX *ABS* -# IE64-NEXT: nop # IE64-NEXT: R_LARCH_TLS_DESC_LD a # IE64-NEXT: R_LARCH_RELAX *ABS* -# IE64-NEXT: ori $a0, $zero, 8 # IE64-NEXT: R_LARCH_TLS_DESC_CALL a # IE64-NEXT: R_LARCH_RELAX *ABS* # IE64-NEXT: add.d $a1, $a0, $tp ## b@tprel = 0x7ff -# IE64: 202dc: nop +# IE64: 202d0: nop # IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 b # IE64-NEXT: R_LARCH_RELAX *ABS* -# IE64-NEXT: nop # IE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 b # IE64-NEXT: nop # IE64-NEXT: R_LARCH_TLS_DESC_LD b @@ -196,9 +185,9 @@ # IE64-NEXT: R_LARCH_TLS_DESC_CALL b # IE64-NEXT: add.d $a2, $a0, $tp -## &.got[c]-. = 0x30408 - 0x20300: 0x10 pages, page offset 0x408 +## &.got[c]-. = 0x303f0 - 0x202f0: 0x10 pages, page offset 0x3f0 ## Without R_LARCH_RELAX relocation. No relaxation. -# IE64: 202f0: nop +# IE64: 202e0: nop # IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 c # IE64-NEXT: addi.d $t0, $zero, 0 # IE64-NEXT: nop @@ -207,20 +196,18 @@ # IE64-NEXT: pcalau12i $a0, 16 # IE64-NEXT: R_LARCH_TLS_DESC_LD c # IE64-NEXT: addi.d $t0, $t0, 1 -# IE64-NEXT: ld.d $a0, $a0, 1032 +# IE64-NEXT: ld.d $a0, $a0, 1008 # IE64-NEXT: R_LARCH_TLS_DESC_CALL c # IE64-NEXT: add.d $a3, $a0, $tp -## &.got[d]-. = 0x30408+8 - 0x20318: 0x10 pages, page offset 0x410 -# IE64: 20310: nop +## &.got[d]-. = 0x303f0+8 - 0x20300: 0x10 pages, page offset 0x3f8 +# IE64: 20300: pcalau12i $a0, 16 # IE64-NEXT: R_LARCH_TLS_DESC_PC_HI20 d # IE64-NEXT: R_LARCH_RELAX *ABS* -# IE64-NEXT: nop # IE64-NEXT: R_LARCH_TLS_DESC_PC_LO12 d # IE64-NEXT: R_LARCH_RELAX *ABS* -# IE64-NEXT: pcalau12i $a0, 16 # IE64-NEXT: R_LARCH_TLS_DESC_LD d -# IE64-NEXT: ld.d $a0, $a0, 1040 +# IE64-NEXT: ld.d $a0, $a0, 1016 # IE64-NEXT: R_LARCH_TLS_DESC_CALL d # IE64-NEXT: add.d $a4, $a0, $tp diff --git a/lld/test/MachO/objc.s b/lld/test/MachO/objc.s index dbb9f1d..c327b20 100644 --- a/lld/test/MachO/objc.s +++ b/lld/test/MachO/objc.s @@ -7,12 +7,13 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/has-swift.s -o %t/has-swift.o # RUN: llvm-as %t/has-swift-ir-loaded.ll -o %t/has-swift-ir-loaded.o # RUN: llvm-as %t/has-swift-ir-not-loaded.ll -o %t/has-swift-ir-not-loaded.o +# RUN: llvm-as %t/has-swift-with-space-ir-loaded.ll -o %t/has-swift-with-space-ir-loaded.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/has-swift-proto.s -o %t/has-swift-proto.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/no-objc.s -o %t/no-objc.o ## Make sure we don't mis-parse a 32-bit file as 64-bit # RUN: llvm-mc -filetype=obj -triple=armv7-apple-watchos %t/no-objc.s -o %t/wrong-arch.o -# RUN: llvm-ar rcs %t/libHasSomeObjC.a %t/no-objc.o %t/has-objc-symbol.o %t/has-objc-category.o %t/has-swift.o %t/has-swift-proto.o %t/has-swift-ir-loaded.o %t/has-swift-ir-not-loaded.o %t/wrong-arch.o -# RUN: llvm-ar rcs %t/libHasSomeObjC2.a %t/no-objc.o %t/has-objc-symbol-and-category.o %t/has-swift.o %t/has-swift-proto.o %t/has-swift-ir-loaded.o %t/has-swift-ir-not-loaded.o %t/wrong-arch.o +# RUN: llvm-ar rcs %t/libHasSomeObjC.a %t/no-objc.o %t/has-objc-symbol.o %t/has-objc-category.o %t/has-swift.o %t/has-swift-proto.o %t/has-swift-ir-loaded.o %t/has-swift-ir-not-loaded.o %t/has-swift-with-space-ir-loaded.o %t/wrong-arch.o +# RUN: llvm-ar rcs %t/libHasSomeObjC2.a %t/no-objc.o %t/has-objc-symbol-and-category.o %t/has-swift.o %t/has-swift-proto.o %t/has-swift-ir-loaded.o %t/has-swift-ir-not-loaded.o %t/has-swift-with-space-ir-loaded.o %t/wrong-arch.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-darwin %t/test.s -o %t/test.o @@ -22,7 +23,7 @@ # RUN: %lld -lSystem %t/test.o -o %t/test -L%t -lHasSomeObjC2 -ObjC # RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=OBJC -# RUN: %no-fatal-warnings-lld -lSystem %t/test.o -o %t/test --start-lib %t/no-objc.o %t/has-objc-symbol.o %t/has-objc-category.o %t/has-swift.o %t/has-swift-proto.o %t/has-swift-ir-loaded.o %t/has-swift-ir-not-loaded.o %t/wrong-arch.o --end-lib -ObjC 2>&1 \ +# RUN: %no-fatal-warnings-lld -lSystem %t/test.o -o %t/test --start-lib %t/no-objc.o %t/has-objc-symbol.o %t/has-objc-category.o %t/has-swift.o %t/has-swift-proto.o %t/has-swift-ir-loaded.o %t/has-swift-ir-not-loaded.o %t/has-swift-with-space-ir-loaded.o %t/wrong-arch.o --end-lib -ObjC 2>&1 \ # RUN: | FileCheck -check-prefix=WARNING %s # RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=OBJC @@ -34,14 +35,16 @@ # OBJC-NEXT: 0 __text {{.*}} TEXT # OBJC-NEXT: 1 __swift {{.*}} DATA # OBJC-NEXT: 2 __swift5_fieldmd{{.*}} DATA -# OBJC-NEXT: 3 __objc_catlist {{.*}} DATA -# OBJC-NEXT: 4 has_objc_symbol {{.*}} DATA +# OBJC-NEXT: 3 __swift5_proto {{.*}} DATA +# OBJC-NEXT: 4 __objc_catlist {{.*}} DATA +# OBJC-NEXT: 5 has_objc_symbol {{.*}} DATA # OBJC-EMPTY: # OBJC-NEXT: SYMBOL TABLE: # OBJC-DAG: g O __TEXT,__swift _foo # OBJC-DAG: g F __TEXT,__text _main # OBJC-DAG: g F __TEXT,__text _OBJC_CLASS_$_MyObject # OBJC-DAG: g O __TEXT,__swift5_fieldmd $s7somelib4Blah_pMF +# OBJC-DAG: g O __TEXT,__swift5_proto _baz # RUN: %lld -lSystem %t/test.o -o %t/test -L%t -lHasSomeObjC # RUN: llvm-objdump --section-headers --syms %t/test | FileCheck %s --check-prefix=NO-OBJC @@ -117,6 +120,13 @@ target triple = "x86_64-apple-darwin" @bar = global i64 1234 @llvm.used = appending global [1 x ptr] [ptr @bar] +#--- has-swift-with-space-ir-loaded.ll +target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" +target triple = "x86_64-apple-darwin" + +@baz = global i64 1234, section "__TEXT, __swift5_proto" +@llvm.used = appending global [1 x ptr] [ptr @baz] + #--- has-swift-proto.s .section __TEXT,__swift5_fieldmd .globl $s7somelib4Blah_pMF diff --git a/lld/test/wasm/lto/save-temps.ll b/lld/test/wasm/lto/save-temps.ll index 773978e..e5e96d3 100644 --- a/lld/test/wasm/lto/save-temps.ll +++ b/lld/test/wasm/lto/save-temps.ll @@ -1,4 +1,5 @@ -; RUN: cd %T +; RUN: mkdir -p %t.dir +; RUN: cd %t.dir ; RUN: rm -f a.out a.out.lto.bc a.out.lto.o ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %p/Inputs/save-temps.ll -o %t2.o |