diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:08:33 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 11:08:33 +0000 |
commit | 20d35e67e67f106f617c939725101223211659f0 (patch) | |
tree | 64eb963cbf5ba58765e0a6b64a440965d66a7a4d | |
parent | ae1a339de31cf4065777531959a11e55a2e5fa00 (diff) |
Vendor import of lld trunk r338150:vendor/lld/lld-trunk-r338150
Notes
Notes:
svn path=/vendor/lld/dist/; revision=336821
svn path=/vendor/lld/lld-trunk-r338150/; revision=336822; tag=vendor/lld/lld-trunk-r338150
1593 files changed, 40958 insertions, 11573 deletions
diff --git a/COFF/CMakeLists.txt b/COFF/CMakeLists.txt index 4610ccc880fd..bb241e788c19 100644 --- a/COFF/CMakeLists.txt +++ b/COFF/CMakeLists.txt @@ -18,7 +18,6 @@ add_lld_library(lldCOFF MarkLive.cpp MinGW.cpp PDB.cpp - Strings.cpp SymbolTable.cpp Symbols.cpp Writer.cpp diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 557b02654426..412ff783222b 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -31,8 +31,7 @@ namespace coff { SectionChunk::SectionChunk(ObjFile *F, const coff_section *H) : Chunk(SectionKind), Repl(this), Header(H), File(F), - Relocs(File->getCOFFObj()->getRelocations(Header)), - NumRelocs(std::distance(Relocs.begin(), Relocs.end())) { + Relocs(File->getCOFFObj()->getRelocations(Header)) { // Initialize SectionName. File->getCOFFObj()->getSectionName(Header, SectionName); @@ -51,13 +50,21 @@ static void add64(uint8_t *P, int64_t V) { write64le(P, read64le(P) + V); } static void or16(uint8_t *P, uint16_t V) { write16le(P, read16le(P) | V); } static void or32(uint8_t *P, uint32_t V) { write32le(P, read32le(P) | V); } +// Verify that given sections are appropriate targets for SECREL +// relocations. This check is relaxed because unfortunately debug +// sections have section-relative relocations against absolute symbols. +static bool checkSecRel(const SectionChunk *Sec, OutputSection *OS) { + if (OS) + return true; + if (Sec->isCodeView()) + return false; + fatal("SECREL relocation cannot be applied to absolute symbols"); +} + static void applySecRel(const SectionChunk *Sec, uint8_t *Off, OutputSection *OS, uint64_t S) { - if (!OS) { - if (Sec->isCodeView()) - return; - fatal("SECREL relocation cannot be applied to absolute symbols"); - } + if (!checkSecRel(Sec, OS)) + return; uint64_t SecRel = S - OS->getRVA(); if (SecRel > UINT32_MAX) { error("overflow in SECREL relocation in section: " + Sec->getSectionName()); @@ -67,10 +74,13 @@ static void applySecRel(const SectionChunk *Sec, uint8_t *Off, } static void applySecIdx(uint8_t *Off, OutputSection *OS) { - // If we have no output section, this must be an absolute symbol. Use the - // sentinel absolute symbol section index. - uint16_t SecIdx = OS ? OS->SectionIndex : DefinedAbsolute::OutputSectionIndex; - add16(Off, SecIdx); + // Absolute symbol doesn't have section index, but section index relocation + // against absolute symbol should be resolved to one plus the last output + // section index. This is required for compatibility with MSVC. + if (OS) + add16(Off, OS->SectionIndex); + else + add16(Off, DefinedAbsolute::NumOutputSections + 1); } void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, @@ -88,7 +98,8 @@ void SectionChunk::applyRelX64(uint8_t *Off, uint16_t Type, OutputSection *OS, case IMAGE_REL_AMD64_SECTION: applySecIdx(Off, OS); break; case IMAGE_REL_AMD64_SECREL: applySecRel(this, Off, OS, S); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } @@ -102,7 +113,8 @@ void SectionChunk::applyRelX86(uint8_t *Off, uint16_t Type, OutputSection *OS, case IMAGE_REL_I386_SECTION: applySecIdx(Off, OS); break; case IMAGE_REL_I386_SECREL: applySecRel(this, Off, OS, S); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } @@ -112,11 +124,10 @@ static void applyMOV(uint8_t *Off, uint16_t V) { } static uint16_t readMOV(uint8_t *Off) { - uint16_t Opcode1 = read16le(Off); - uint16_t Opcode2 = read16le(Off + 2); - uint16_t Imm = (Opcode2 & 0x00ff) | ((Opcode2 >> 4) & 0x0700); - Imm |= ((Opcode1 << 1) & 0x0800) | ((Opcode1 & 0x000f) << 12); - return Imm; + uint16_t Op1 = read16le(Off); + uint16_t Op2 = read16le(Off + 2); + return (Op2 & 0x00ff) | ((Op2 >> 4) & 0x0700) | ((Op1 << 1) & 0x0800) | + ((Op1 & 0x000f) << 12); } void applyMOV32T(uint8_t *Off, uint32_t V) { @@ -153,7 +164,7 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { // Pointer to thumb code must have the LSB set. uint64_t SX = S; - if (OS && (OS->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + if (OS && (OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE)) SX |= 1; switch (Type) { case IMAGE_REL_ARM_ADDR32: add32(Off, SX + Config->ImageBase); break; @@ -165,18 +176,19 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, case IMAGE_REL_ARM_SECTION: applySecIdx(Off, OS); break; case IMAGE_REL_ARM_SECREL: applySecRel(this, Off, OS, S); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } // Interpret the existing immediate value as a byte offset to the // target symbol, then update the instruction with the immediate as // the page offset from the current instruction to the target. -static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P) { +static void applyArm64Addr(uint8_t *Off, uint64_t S, uint64_t P, int Shift) { uint32_t Orig = read32le(Off); uint64_t Imm = ((Orig >> 29) & 0x3) | ((Orig >> 3) & 0x1FFFFC); S += Imm; - Imm = (S >> 12) - (P >> 12); + Imm = (S >> Shift) - (P >> Shift); uint32_t ImmLo = (Imm & 0x3) << 29; uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); @@ -213,19 +225,70 @@ static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { applyArm64Imm(Off, Imm >> Size, Size); } +static void applySecRelLow12A(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (checkSecRel(Sec, OS)) + applyArm64Imm(Off, (S - OS->getRVA()) & 0xfff, 0); +} + +static void applySecRelHigh12A(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (!checkSecRel(Sec, OS)) + return; + uint64_t SecRel = (S - OS->getRVA()) >> 12; + if (0xfff < SecRel) { + error("overflow in SECREL_HIGH12A relocation in section: " + + Sec->getSectionName()); + return; + } + applyArm64Imm(Off, SecRel & 0xfff, 0); +} + +static void applySecRelLdr(const SectionChunk *Sec, uint8_t *Off, + OutputSection *OS, uint64_t S) { + if (checkSecRel(Sec, OS)) + applyArm64Ldr(Off, (S - OS->getRVA()) & 0xfff); +} + +static void applyArm64Branch26(uint8_t *Off, int64_t V) { + if (!isInt<28>(V)) + fatal("relocation out of range"); + or32(Off, (V & 0x0FFFFFFC) >> 2); +} + +static void applyArm64Branch19(uint8_t *Off, int64_t V) { + if (!isInt<21>(V)) + fatal("relocation out of range"); + or32(Off, (V & 0x001FFFFC) << 3); +} + +static void applyArm64Branch14(uint8_t *Off, int64_t V) { + if (!isInt<16>(V)) + fatal("relocation out of range"); + or32(Off, (V & 0x0000FFFC) << 3); +} + void SectionChunk::applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const { switch (Type) { - case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P); break; + case IMAGE_REL_ARM64_PAGEBASE_REL21: applyArm64Addr(Off, S, P, 12); break; + case IMAGE_REL_ARM64_REL21: applyArm64Addr(Off, S, P, 0); break; case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff, 0); break; case IMAGE_REL_ARM64_PAGEOFFSET_12L: applyArm64Ldr(Off, S & 0xfff); break; - case IMAGE_REL_ARM64_BRANCH26: or32(Off, ((S - P) & 0x0FFFFFFC) >> 2); break; + case IMAGE_REL_ARM64_BRANCH26: applyArm64Branch26(Off, S - P); break; + case IMAGE_REL_ARM64_BRANCH19: applyArm64Branch19(Off, S - P); break; + case IMAGE_REL_ARM64_BRANCH14: applyArm64Branch14(Off, S - P); break; case IMAGE_REL_ARM64_ADDR32: add32(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM64_ADDR32NB: add32(Off, S); break; case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; case IMAGE_REL_ARM64_SECREL: applySecRel(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_LOW12A: applySecRelLow12A(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_HIGH12A: applySecRelHigh12A(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECREL_LOW12L: applySecRelLdr(this, Off, OS, S); break; + case IMAGE_REL_ARM64_SECTION: applySecIdx(Off, OS); break; default: - fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type) + " in " + + toString(File)); } } @@ -234,7 +297,8 @@ void SectionChunk::writeTo(uint8_t *Buf) const { return; // Copy section contents from source object file to output file. ArrayRef<uint8_t> A = getContents(); - memcpy(Buf + OutputSectionOff, A.data(), A.size()); + if (!A.empty()) + memcpy(Buf + OutputSectionOff, A.data(), A.size()); // Apply relocations. size_t InputSize = getSize(); @@ -350,8 +414,8 @@ bool SectionChunk::hasData() const { return !(Header->Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA); } -uint32_t SectionChunk::getPermissions() const { - return Header->Characteristics & PermMask; +uint32_t SectionChunk::getOutputCharacteristics() const { + return Header->Characteristics & (PermMask | TypeMask); } bool SectionChunk::isCOMDAT() const { @@ -378,6 +442,7 @@ ArrayRef<uint8_t> SectionChunk::getContents() const { } void SectionChunk::replace(SectionChunk *Other) { + Alignment = std::max(Alignment, Other->Alignment); Other->Repl = Repl; Other->Live = false; } @@ -388,7 +453,7 @@ CommonChunk::CommonChunk(const COFFSymbolRef S) : Sym(S) { Alignment = std::min(uint64_t(32), PowerOf2Ceil(Sym.getValue())); } -uint32_t CommonChunk::getPermissions() const { +uint32_t CommonChunk::getOutputCharacteristics() const { return IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE; } @@ -433,7 +498,7 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { int64_t Off = ImpSymbol->getRVA() & 0xfff; memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); - applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA); + applyArm64Addr(Buf + OutputSectionOff, ImpSymbol->getRVA(), RVA, 12); applyArm64Ldr(Buf + OutputSectionOff + 4, Off); } @@ -453,12 +518,14 @@ void LocalImportChunk::writeTo(uint8_t *Buf) const { } } -void SEHTableChunk::writeTo(uint8_t *Buf) const { +void RVATableChunk::writeTo(uint8_t *Buf) const { ulittle32_t *Begin = reinterpret_cast<ulittle32_t *>(Buf + OutputSectionOff); size_t Cnt = 0; - for (Defined *D : Syms) - Begin[Cnt++] = D->getRVA(); + for (const ChunkAndOffset &CO : Syms) + Begin[Cnt++] = CO.InputChunk->getRVA() + CO.Offset; std::sort(Begin, Begin + Cnt); + assert(std::unique(Begin, Begin + Cnt) == Begin + Cnt && + "RVA tables should be de-duplicated"); } // Windows-specific. This class represents a block in .reloc section. @@ -531,5 +598,47 @@ uint8_t Baserel::getDefaultType() { } } +std::map<uint32_t, MergeChunk *> MergeChunk::Instances; + +MergeChunk::MergeChunk(uint32_t Alignment) + : Builder(StringTableBuilder::RAW, Alignment) { + this->Alignment = Alignment; +} + +void MergeChunk::addSection(SectionChunk *C) { + auto *&MC = Instances[C->Alignment]; + if (!MC) + MC = make<MergeChunk>(C->Alignment); + MC->Sections.push_back(C); +} + +void MergeChunk::finalizeContents() { + for (SectionChunk *C : Sections) + if (C->isLive()) + Builder.add(toStringRef(C->getContents())); + Builder.finalize(); + + for (SectionChunk *C : Sections) { + if (!C->isLive()) + continue; + size_t Off = Builder.getOffset(toStringRef(C->getContents())); + C->setOutputSection(Out); + C->setRVA(RVA + Off); + C->OutputSectionOff = OutputSectionOff + Off; + } +} + +uint32_t MergeChunk::getOutputCharacteristics() const { + return IMAGE_SCN_MEM_READ | IMAGE_SCN_CNT_INITIALIZED_DATA; +} + +size_t MergeChunk::getSize() const { + return Builder.getSize(); +} + +void MergeChunk::writeTo(uint8_t *Buf) const { + Builder.write(Buf + OutputSectionOff); +} + } // namespace coff } // namespace lld diff --git a/COFF/Chunks.h b/COFF/Chunks.h index 381527ee6ef2..9e896531bd9a 100644 --- a/COFF/Chunks.h +++ b/COFF/Chunks.h @@ -16,6 +16,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/COFF.h" #include <utility> #include <vector> @@ -37,9 +38,11 @@ class ObjFile; class OutputSection; class Symbol; -// Mask for section types (code, data, bss, disacardable, etc.) -// and permissions (writable, readable or executable). -const uint32_t PermMask = 0xFF0000F0; +// Mask for permissions (discardable, writable, readable, executable, etc). +const uint32_t PermMask = 0xFE000000; + +// Mask for section types (code, data, bss). +const uint32_t TypeMask = 0x000000E0; // A Chunk represents a chunk of data that will occupy space in the // output (if the resolver chose that). It may or may not be backed by @@ -60,6 +63,10 @@ public: // before calling this function. virtual void writeTo(uint8_t *Buf) const {} + // Called by the writer after an RVA is assigned, but before calling + // getSize(). + virtual void finalizeContents() {} + // The writer sets and uses the addresses. uint64_t getRVA() const { return RVA; } void setRVA(uint64_t V) { RVA = V; } @@ -70,7 +77,7 @@ public: virtual bool hasData() const { return true; } // Returns readable/writable/executable bits. - virtual uint32_t getPermissions() const { return 0; } + virtual uint32_t getOutputCharacteristics() const { return 0; } // Returns the section name if this is a section chunk. // It is illegal to call this function on non-section chunks. @@ -137,7 +144,7 @@ public: ArrayRef<uint8_t> getContents() const; void writeTo(uint8_t *Buf) const override; bool hasData() const override; - uint32_t getPermissions() const override; + uint32_t getOutputCharacteristics() const override; StringRef getSectionName() const override { return SectionName; } void getBaserels(std::vector<Baserel> *Res) override; bool isCOMDAT() const; @@ -208,11 +215,11 @@ public: // The COMDAT leader symbol if this is a COMDAT chunk. DefinedRegular *Sym = nullptr; + ArrayRef<coff_relocation> Relocs; + private: StringRef SectionName; std::vector<SectionChunk *> AssocChildren; - llvm::iterator_range<const coff_relocation *> Relocs; - size_t NumRelocs; // Used by the garbage collector. bool Live; @@ -222,13 +229,40 @@ private: uint32_t Class[2] = {0, 0}; }; +// This class is used to implement an lld-specific feature (not implemented in +// MSVC) that minimizes the output size by finding string literals sharing tail +// parts and merging them. +// +// If string tail merging is enabled and a section is identified as containing a +// string literal, it is added to a MergeChunk with an appropriate alignment. +// The MergeChunk then tail merges the strings using the StringTableBuilder +// class and assigns RVAs and section offsets to each of the member chunks based +// on the offsets assigned by the StringTableBuilder. +class MergeChunk : public Chunk { +public: + MergeChunk(uint32_t Alignment); + static void addSection(SectionChunk *C); + void finalizeContents() override; + + uint32_t getOutputCharacteristics() const override; + StringRef getSectionName() const override { return ".rdata"; } + size_t getSize() const override; + void writeTo(uint8_t *Buf) const override; + + static std::map<uint32_t, MergeChunk *> Instances; + std::vector<SectionChunk *> Sections; + +private: + llvm::StringTableBuilder Builder; +}; + // A chunk for common symbols. Common chunks don't have actual data. class CommonChunk : public Chunk { public: CommonChunk(const COFFSymbolRef Sym); size_t getSize() const override { return Sym.getValue(); } bool hasData() const override { return false; } - uint32_t getPermissions() const override; + uint32_t getOutputCharacteristics() const override; StringRef getSectionName() const override { return ".bss"; } private: @@ -320,17 +354,41 @@ private: Defined *Sym; }; -// Windows-specific. -// A chunk for SEH table which contains RVAs of safe exception handler -// functions. x86-only. -class SEHTableChunk : public Chunk { +// Duplicate RVAs are not allowed in RVA tables, so unique symbols by chunk and +// offset into the chunk. Order does not matter as the RVA table will be sorted +// later. +struct ChunkAndOffset { + Chunk *InputChunk; + uint32_t Offset; + + struct DenseMapInfo { + static ChunkAndOffset getEmptyKey() { + return {llvm::DenseMapInfo<Chunk *>::getEmptyKey(), 0}; + } + static ChunkAndOffset getTombstoneKey() { + return {llvm::DenseMapInfo<Chunk *>::getTombstoneKey(), 0}; + } + static unsigned getHashValue(const ChunkAndOffset &CO) { + return llvm::DenseMapInfo<std::pair<Chunk *, uint32_t>>::getHashValue( + {CO.InputChunk, CO.Offset}); + } + static bool isEqual(const ChunkAndOffset &LHS, const ChunkAndOffset &RHS) { + return LHS.InputChunk == RHS.InputChunk && LHS.Offset == RHS.Offset; + } + }; +}; + +using SymbolRVASet = llvm::DenseSet<ChunkAndOffset>; + +// Table which contains symbol RVAs. Used for /safeseh and /guard:cf. +class RVATableChunk : public Chunk { public: - explicit SEHTableChunk(std::set<Defined *> S) : Syms(std::move(S)) {} + explicit RVATableChunk(SymbolRVASet S) : Syms(std::move(S)) {} size_t getSize() const override { return Syms.size() * 4; } void writeTo(uint8_t *Buf) const override; private: - std::set<Defined *> Syms; + SymbolRVASet Syms; }; // Windows-specific. @@ -362,4 +420,10 @@ void applyBranch24T(uint8_t *Off, int32_t V); } // namespace coff } // namespace lld +namespace llvm { +template <> +struct DenseMapInfo<lld::coff::ChunkAndOffset> + : lld::coff::ChunkAndOffset::DenseMapInfo {}; +} + #endif diff --git a/COFF/Config.h b/COFF/Config.h index 93bef23a97f0..3ae50b868333 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -10,6 +10,7 @@ #ifndef LLD_COFF_CONFIG_H #define LLD_COFF_CONFIG_H +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" #include "llvm/Support/CachePruning.h" @@ -71,6 +72,12 @@ enum class DebugType { Fixup = 0x4, /// Relocation Table }; +enum class GuardCFLevel { + Off, + NoLongJmp, // Emit gfids but no longjmp tables + Full, // Enable all protections. +}; + // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; @@ -85,13 +92,19 @@ struct Configuration { std::string ImportName; bool DoGC = true; bool DoICF = true; + bool TailMerge; bool Relocatable = true; bool Force = false; bool Debug = false; bool DebugDwarf = false; bool DebugGHashes = false; + bool DebugSymtab = false; + bool ShowTiming = false; unsigned DebugTypes = static_cast<unsigned>(DebugType::None); + std::vector<std::string> NatvisFiles; + llvm::SmallString<128> PDBAltPath; llvm::SmallString<128> PDBPath; + llvm::SmallString<128> PDBSourcePath; std::vector<llvm::StringRef> Argv; // Symbols in this set are considered as live by the garbage collector. @@ -110,15 +123,18 @@ struct Configuration { bool SaveTemps = false; + // /guard:cf + GuardCFLevel GuardCF = GuardCFLevel::Off; + // Used for SafeSEH. Symbol *SEHTable = nullptr; Symbol *SEHCount = nullptr; // Used for /opt:lldlto=N - unsigned LTOOptLevel = 2; + unsigned LTOO = 2; // Used for /opt:lldltojobs=N - unsigned LTOJobs = 0; + unsigned ThinLTOJobs = 0; // Used for /opt:lldltopartitions=N unsigned LTOPartitions = 1; @@ -152,6 +168,9 @@ struct Configuration { // Used for /alternatename. std::map<StringRef, StringRef> AlternateNames; + // Used for /order. + llvm::StringMap<int> Order; + // Used for /lldmap. std::string MapFile; @@ -164,7 +183,7 @@ struct Configuration { uint32_t MinorImageVersion = 0; uint32_t MajorOSVersion = 6; uint32_t MinorOSVersion = 0; - bool CanExitEarly = false; + uint32_t Timestamp = 0; bool DynamicBase = true; bool AllowBind = true; bool NxCompat = true; @@ -174,7 +193,12 @@ struct Configuration { bool HighEntropyVA = false; bool AppContainer = false; bool MinGW = false; + bool WarnMissingOrderSymbol = true; bool WarnLocallyDefinedImported = true; + bool Incremental = true; + bool IntegrityCheck = false; + bool KillAt = false; + bool Repro = false; }; extern Configuration *Config; diff --git a/COFF/DLL.cpp b/COFF/DLL.cpp index 195839139670..464abe8e0894 100644 --- a/COFF/DLL.cpp +++ b/COFF/DLL.cpp @@ -18,8 +18,8 @@ // //===----------------------------------------------------------------------===// -#include "Chunks.h" #include "DLL.h" +#include "Chunks.h" #include "llvm/Object/COFF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Path.h" diff --git a/COFF/DLL.h b/COFF/DLL.h index ad312789edf1..c5d6e7c93abf 100644 --- a/COFF/DLL.h +++ b/COFF/DLL.h @@ -76,6 +76,11 @@ class EdataContents { public: EdataContents(); std::vector<Chunk *> Chunks; + + uint64_t getRVA() { return Chunks[0]->getRVA(); } + uint64_t getSize() { + return Chunks.back()->getRVA() + Chunks.back()->getSize() - getRVA(); + } }; } // namespace coff diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 1aaec355c7a5..eefdb48beadd 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -9,14 +9,18 @@ #include "Driver.h" #include "Config.h" +#include "ICF.h" #include "InputFiles.h" +#include "MarkLive.h" #include "MinGW.h" #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" +#include "lld/Common/Args.h" #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Timer.h" #include "lld/Common/Version.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSwitch.h" @@ -35,9 +39,8 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/ToolDrivers/llvm-lib/LibDriver.h" #include <algorithm> -#include <memory> - #include <future> +#include <memory> using namespace llvm; using namespace llvm::object; @@ -47,19 +50,20 @@ using llvm::sys::Process; namespace lld { namespace coff { +static Timer InputFileTimer("Input File Reading", Timer::root()); + Configuration *Config; LinkerDriver *Driver; bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) { - errorHandler().LogName = Args[0]; + errorHandler().LogName = sys::path::filename(Args[0]); errorHandler().ErrorOS = &Diag; errorHandler().ColorDiagnostics = Diag.has_colors(); errorHandler().ErrorLimitExceededMsg = "too many errors emitted, stopping now" - " (use /ERRORLIMIT:0 to see all errors)"; + " (use /errorlimit:0 to see all errors)"; + errorHandler().ExitEarly = CanExitEarly; Config = make<Configuration>(); - Config->Argv = {Args.begin(), Args.end()}; - Config->CanExitEarly = CanExitEarly; Symtab = make<SymbolTable>(); @@ -71,6 +75,9 @@ bool link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Diag) { exitLld(errorCount() ? 1 : 0); freeArena(); + ObjFile::Instances.clear(); + ImportFile::Instances.clear(); + BitcodeFile::Instances.clear(); return !errorCount(); } @@ -92,7 +99,7 @@ typedef std::pair<std::unique_ptr<MemoryBuffer>, std::error_code> MBErrPair; // Create a std::future that opens and maps a file using the best strategy for // the host platform. static std::future<MBErrPair> createFutureForFile(std::string Path) { -#if LLVM_ON_WIN32 +#if _WIN32 // On Windows, file I/O is relatively slow so it is best to do this // asynchronously. auto Strategy = std::launch::async; @@ -100,7 +107,9 @@ static std::future<MBErrPair> createFutureForFile(std::string Path) { auto Strategy = std::launch::deferred; #endif return std::async(Strategy, [=]() { - auto MBOrErr = MemoryBuffer::getFile(Path); + auto MBOrErr = MemoryBuffer::getFile(Path, + /*FileSize*/ -1, + /*RequiresNullTerminator*/ false); if (!MBOrErr) return MBErrPair{nullptr, MBOrErr.getError()}; return MBErrPair{std::move(*MBOrErr), std::error_code()}; @@ -119,39 +128,46 @@ MemoryBufferRef LinkerDriver::takeBuffer(std::unique_ptr<MemoryBuffer> MB) { void LinkerDriver::addBuffer(std::unique_ptr<MemoryBuffer> MB, bool WholeArchive) { + StringRef Filename = MB->getBufferIdentifier(); + MemoryBufferRef MBRef = takeBuffer(std::move(MB)); - FilePaths.push_back(MBRef.getBufferIdentifier()); + FilePaths.push_back(Filename); // File type is detected by contents, not by file extension. switch (identify_magic(MBRef.getBuffer())) { case file_magic::windows_resource: Resources.push_back(MBRef); break; - case file_magic::archive: if (WholeArchive) { std::unique_ptr<Archive> File = - CHECK(Archive::create(MBRef), - MBRef.getBufferIdentifier() + ": failed to parse archive"); + CHECK(Archive::create(MBRef), Filename + ": failed to parse archive"); for (MemoryBufferRef M : getArchiveMembers(File.get())) - addArchiveBuffer(M, "<whole-archive>", MBRef.getBufferIdentifier()); + addArchiveBuffer(M, "<whole-archive>", Filename); return; } Symtab->addFile(make<ArchiveFile>(MBRef)); break; - case file_magic::bitcode: Symtab->addFile(make<BitcodeFile>(MBRef)); break; - + case file_magic::coff_object: + case file_magic::coff_import_library: + Symtab->addFile(make<ObjFile>(MBRef)); + break; case file_magic::coff_cl_gl_object: - error(MBRef.getBufferIdentifier() + ": is not a native COFF file. " - "Recompile without /GL"); + error(Filename + ": is not a native COFF file. Recompile without /GL"); break; - + case file_magic::pecoff_executable: + if (Filename.endswith_lower(".dll")) { + error(Filename + ": bad file type. Did you specify a DLL instead of an " + "import library?"); + break; + } + LLVM_FALLTHROUGH; default: - Symtab->addFile(make<ObjFile>(MBRef)); + error(MBRef.getBufferIdentifier() + ": unknown file type"); break; } } @@ -227,7 +243,29 @@ static bool isDecorated(StringRef Sym) { void LinkerDriver::parseDirectives(StringRef S) { ArgParser Parser; // .drectve is always tokenized using Windows shell rules. - opt::InputArgList Args = Parser.parseDirectives(S); + // /EXPORT: option can appear too many times, processing in fastpath. + opt::InputArgList Args; + std::vector<StringRef> Exports; + std::tie(Args, Exports) = Parser.parseDirectives(S); + + for (StringRef E : Exports) { + // If a common header file contains dllexported function + // declarations, many object files may end up with having the + // same /EXPORT options. In order to save cost of parsing them, + // we dedup them first. + if (!DirectivesExports.insert(E).second) + continue; + + Export Exp = parseExport(E); + if (Config->Machine == I386 && Config->MinGW) { + if (!isDecorated(Exp.Name)) + Exp.Name = Saver.save("_" + Exp.Name); + if (!Exp.ExtName.empty() && !isDecorated(Exp.ExtName)) + Exp.ExtName = Saver.save("_" + Exp.ExtName); + } + Exp.Directives = true; + Config->Exports.push_back(Exp); + } for (auto *Arg : Args) { switch (Arg->getOption().getUnaliasedOption().getID()) { @@ -244,25 +282,6 @@ void LinkerDriver::parseDirectives(StringRef S) { case OPT_entry: Config->Entry = addUndefined(mangle(Arg->getValue())); break; - case OPT_export: { - // If a common header file contains dllexported function - // declarations, many object files may end up with having the - // same /EXPORT options. In order to save cost of parsing them, - // we dedup them first. - if (!DirectivesExports.insert(Arg->getValue()).second) - break; - - Export E = parseExport(Arg->getValue()); - if (Config->Machine == I386 && Config->MinGW) { - if (!isDecorated(E.Name)) - E.Name = Saver.save("_" + E.Name); - if (!E.ExtName.empty() && !isDecorated(E.ExtName)) - E.ExtName = Saver.save("_" + E.ExtName); - } - E.Directives = true; - Config->Exports.push_back(E); - break; - } case OPT_failifmismatch: checkFailIfMismatch(Arg->getValue()); break; @@ -315,13 +334,24 @@ StringRef LinkerDriver::doFindFile(StringRef Filename) { return Filename; } +static Optional<sys::fs::UniqueID> getUniqueID(StringRef Path) { + sys::fs::UniqueID Ret; + if (sys::fs::getUniqueID(Path, Ret)) + return None; + return Ret; +} + // Resolves a file path. This never returns the same path // (in that case, it returns None). Optional<StringRef> LinkerDriver::findFile(StringRef Filename) { StringRef Path = doFindFile(Filename); - bool Seen = !VisitedFiles.insert(Path.lower()).second; - if (Seen) - return None; + + if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) { + bool Seen = !VisitedFiles.insert(*ID).second; + if (Seen) + return None; + } + if (Path.endswith_lower(".lib")) VisitedLibs.insert(sys::path::filename(Path)); return Path; @@ -344,11 +374,14 @@ Optional<StringRef> LinkerDriver::findLib(StringRef Filename) { return None; if (!VisitedLibs.insert(Filename.lower()).second) return None; + StringRef Path = doFindLib(Filename); if (Config->NoDefaultLibs.count(Path)) return None; - if (!VisitedFiles.insert(Path.lower()).second) - return None; + + if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) + if (!VisitedFiles.insert(*ID).second) + return None; return Path; } @@ -383,7 +416,24 @@ StringRef LinkerDriver::mangle(StringRef Sym) { } // Windows specific -- find default entry point name. +// +// There are four different entry point functions for Windows executables, +// each of which corresponds to a user-defined "main" function. This function +// infers an entry point from a user-defined "main" function. StringRef LinkerDriver::findDefaultEntry() { + // As a special case, if /nodefaultlib is given, we directly look for an + // entry point. This is because, if no default library is linked, users + // need to define an entry point instead of a "main". + if (Config->NoDefaultLibAll) { + for (StringRef S : {"mainCRTStartup", "wmainCRTStartup", + "WinMainCRTStartup", "wWinMainCRTStartup"}) { + StringRef Entry = Symtab->findMangle(S); + if (!Entry.empty() && !isa<Undefined>(Symtab->find(Entry))) + return mangle(S); + } + return ""; + } + // User-defined main functions and their corresponding entry points. static const char *Entries[][2] = { {"main", "mainCRTStartup"}, @@ -533,10 +583,49 @@ static void createImportLibrary(bool AsLib) { Exports.push_back(E2); } - auto E = writeImportLibrary(getImportName(AsLib), getImplibPath(), Exports, - Config->Machine, false); - handleAllErrors(std::move(E), - [&](ErrorInfoBase &EIB) { error(EIB.message()); }); + auto HandleError = [](Error &&E) { + handleAllErrors(std::move(E), + [](ErrorInfoBase &EIB) { error(EIB.message()); }); + }; + std::string LibName = getImportName(AsLib); + std::string Path = getImplibPath(); + + if (!Config->Incremental) { + HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, + Config->MinGW)); + return; + } + + // If the import library already exists, replace it only if the contents + // have changed. + ErrorOr<std::unique_ptr<MemoryBuffer>> OldBuf = MemoryBuffer::getFile( + Path, /*FileSize*/ -1, /*RequiresNullTerminator*/ false); + if (!OldBuf) { + HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, + Config->MinGW)); + return; + } + + SmallString<128> TmpName; + if (std::error_code EC = + sys::fs::createUniqueFile(Path + ".tmp-%%%%%%%%.lib", TmpName)) + fatal("cannot create temporary file for import library " + Path + ": " + + EC.message()); + + if (Error E = writeImportLibrary(LibName, TmpName, Exports, Config->Machine, + Config->MinGW)) { + HandleError(std::move(E)); + return; + } + + std::unique_ptr<MemoryBuffer> NewBuf = check(MemoryBuffer::getFile( + TmpName, /*FileSize*/ -1, /*RequiresNullTerminator*/ false)); + if ((*OldBuf)->getBuffer() != NewBuf->getBuffer()) { + OldBuf->reset(); + HandleError(errorCodeToError(sys::fs::rename(TmpName, Path))); + } else { + sys::fs::remove(TmpName); + } } static void parseModuleDefs(StringRef Path) { @@ -569,9 +658,18 @@ static void parseModuleDefs(StringRef Path) { for (COFFShortExport E1 : M.Exports) { Export E2; + // In simple cases, only Name is set. Renamed exports are parsed + // and set as "ExtName = Name". If Name has the form "OtherDll.Func", + // it shouldn't be a normal exported function but a forward to another + // DLL instead. This is supported by both MS and GNU linkers. + if (E1.ExtName != E1.Name && StringRef(E1.Name).contains('.')) { + E2.Name = Saver.save(E1.ExtName); + E2.ForwardTo = Saver.save(E1.Name); + Config->Exports.push_back(E2); + continue; + } E2.Name = Saver.save(E1.Name); - if (E1.isWeak()) - E2.ExtName = Saver.save(E1.ExtName); + E2.ExtName = Saver.save(E1.ExtName); E2.Ordinal = E1.Ordinal; E2.Noname = E1.Noname; E2.Data = E1.Data; @@ -634,8 +732,8 @@ filterBitcodeFiles(StringRef Path, std::vector<std::string> &TemporaryFiles) { log("Creating a temporary archive for " + Path + " to remove bitcode files"); SmallString<128> S; - if (auto EC = sys::fs::createTemporaryFile("lld-" + sys::path::stem(Path), - ".lib", S)) + if (std::error_code EC = sys::fs::createTemporaryFile( + "lld-" + sys::path::stem(Path), ".lib", S)) fatal("cannot create a temporary file: " + EC.message()); std::string Temp = S.str(); TemporaryFiles.push_back(Temp); @@ -711,6 +809,8 @@ void LinkerDriver::enqueueTask(std::function<void()> Task) { } bool LinkerDriver::run() { + ScopedTimer T(InputFileTimer); + bool DidWork = !TaskQueue.empty(); while (!TaskQueue.empty()) { TaskQueue.front()(); @@ -719,6 +819,46 @@ bool LinkerDriver::run() { return DidWork; } +// Parse an /order file. If an option is given, the linker places +// COMDAT sections in the same order as their names appear in the +// given file. +static void parseOrderFile(StringRef Arg) { + // For some reason, the MSVC linker requires a filename to be + // preceded by "@". + if (!Arg.startswith("@")) { + error("malformed /order option: '@' missing"); + return; + } + + // Get a list of all comdat sections for error checking. + DenseSet<StringRef> Set; + for (Chunk *C : Symtab->getChunks()) + if (auto *Sec = dyn_cast<SectionChunk>(C)) + if (Sec->Sym) + Set.insert(Sec->Sym->getName()); + + // Open a file. + StringRef Path = Arg.substr(1); + std::unique_ptr<MemoryBuffer> MB = CHECK( + MemoryBuffer::getFile(Path, -1, false, true), "could not open " + Path); + + // Parse a file. An order file contains one symbol per line. + // All symbols that were not present in a given order file are + // considered to have the lowest priority 0 and are placed at + // end of an output section. + for (std::string S : args::getLines(MB->getMemBufferRef())) { + if (Config->Machine == I386 && !isDecorated(S)) + S = "_" + S; + + if (Set.count(S) == 0) { + if (Config->WarnMissingOrderSymbol) + warn("/order:" + Arg + ": missing symbol: " + S + " [LNK4037]"); + } + else + Config->Order[S] = INT_MIN + Config->Order.size(); + } +} + void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // If the first command line argument is "/lib", link.exe acts like lib.exe. // We call our own implementation of lib.exe that understands bitcode files. @@ -734,11 +874,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { InitializeAllTargetMCs(); InitializeAllAsmParsers(); InitializeAllAsmPrinters(); - InitializeAllDisassemblers(); // Parse command line options. ArgParser Parser; - opt::InputArgList Args = Parser.parseLINK(ArgsArr.slice(1)); + opt::InputArgList Args = Parser.parseLINK(ArgsArr); // Parse and evaluate -mllvm options. std::vector<const char *> V; @@ -762,6 +901,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { return; } + if (Args.hasArg(OPT_show_timing)) + Config->ShowTiming = true; + + ScopedTimer T(Timer::root()); // Handle --version, which is an lld extension. This option is a bit odd // because it doesn't start with "/", but we deliberately chose "--" to // avoid conflict with /version and for compatibility with clang-cl. @@ -804,7 +947,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // Handle /ignore for (auto *Arg : Args.filtered(OPT_ignore)) { - if (StringRef(Arg->getValue()) == "4217") + if (StringRef(Arg->getValue()) == "4037") + Config->WarnMissingOrderSymbol = false; + else if (StringRef(Arg->getValue()) == "4217") Config->WarnLocallyDefinedImported = false; // Other warning numbers are ignored. } @@ -825,6 +970,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // Handle /debug if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) { Config->Debug = true; + Config->Incremental = true; if (auto *Arg = Args.getLastArg(OPT_debugtype)) Config->DebugTypes = parseDebugType(Arg->getValue()); else @@ -833,9 +979,17 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // Handle /pdb bool ShouldCreatePDB = Args.hasArg(OPT_debug, OPT_debug_ghash); - if (ShouldCreatePDB) + if (ShouldCreatePDB) { if (auto *Arg = Args.getLastArg(OPT_pdb)) Config->PDBPath = Arg->getValue(); + if (auto *Arg = Args.getLastArg(OPT_pdbaltpath)) + Config->PDBAltPath = Arg->getValue(); + if (Args.hasArg(OPT_natvis)) + Config->NatvisFiles = Args.getAllArgValues(OPT_natvis); + + if (auto *Arg = Args.getLastArg(OPT_pdb_source_path)) + Config->PDBSourcePath = Arg->getValue(); + } // Handle /noentry if (Args.hasArg(OPT_noentry)) { @@ -859,6 +1013,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { DynamicBaseArg->getOption().getID() == OPT_dynamicbase_no) Config->DynamicBase = false; + // MSDN claims "/FIXED:NO is the default setting for a DLL, and /FIXED is the + // default setting for any other project type.", but link.exe defaults to + // /FIXED:NO for exe outputs as well. Match behavior, not docs. bool Fixed = Args.hasFlag(OPT_fixed, OPT_fixed_no, false); if (Fixed) { if (DynamicBaseArg && @@ -894,6 +1051,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { if (auto *Arg = Args.getLastArg(OPT_stack)) parseNumbers(Arg->getValue(), &Config->StackReserve, &Config->StackCommit); + // Handle /guard:cf + if (auto *Arg = Args.getLastArg(OPT_guard)) + parseGuard(Arg->getValue()); + // Handle /heap if (auto *Arg = Args.getLastArg(OPT_heap)) parseNumbers(Arg->getValue(), &Config->HeapReserve, &Config->HeapCommit); @@ -908,6 +1069,23 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { parseSubsystem(Arg->getValue(), &Config->Subsystem, &Config->MajorOSVersion, &Config->MinorOSVersion); + // Handle /timestamp + if (llvm::opt::Arg *Arg = Args.getLastArg(OPT_timestamp, OPT_repro)) { + if (Arg->getOption().getID() == OPT_repro) { + Config->Timestamp = 0; + Config->Repro = true; + } else { + Config->Repro = false; + StringRef Value(Arg->getValue()); + if (Value.getAsInteger(0, Config->Timestamp)) + fatal(Twine("invalid timestamp: ") + Value + + ". Expected 32-bit integer"); + } + } else { + Config->Repro = false; + Config->Timestamp = time(nullptr); + } + // Handle /alternatename for (auto *Arg : Args.filtered(OPT_alternatename)) parseAlternateName(Arg->getValue()); @@ -921,8 +1099,10 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { Config->Implib = Arg->getValue(); // Handle /opt. - bool DoGC = !Args.hasArg(OPT_debug); - unsigned ICFLevel = 1; // 0: off, 1: limited, 2: on + bool DoGC = !Args.hasArg(OPT_debug) || Args.hasArg(OPT_profile); + unsigned ICFLevel = + Args.hasArg(OPT_profile) ? 0 : 1; // 0: off, 1: limited, 2: on + unsigned TailMerge = 1; for (auto *Arg : Args.filtered(OPT_opt)) { std::string Str = StringRef(Arg->getValue()).lower(); SmallVector<StringRef, 1> Vec; @@ -936,14 +1116,18 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { ICFLevel = 2; } else if (S == "noicf") { ICFLevel = 0; + } else if (S == "lldtailmerge") { + TailMerge = 2; + } else if (S == "nolldtailmerge") { + TailMerge = 0; } else if (S.startswith("lldlto=")) { StringRef OptLevel = S.substr(7); - if (OptLevel.getAsInteger(10, Config->LTOOptLevel) || - Config->LTOOptLevel > 3) + if (OptLevel.getAsInteger(10, Config->LTOO) || Config->LTOO > 3) error("/opt:lldlto: invalid optimization level: " + OptLevel); } else if (S.startswith("lldltojobs=")) { StringRef Jobs = S.substr(11); - if (Jobs.getAsInteger(10, Config->LTOJobs) || Config->LTOJobs == 0) + if (Jobs.getAsInteger(10, Config->ThinLTOJobs) || + Config->ThinLTOJobs == 0) error("/opt:lldltojobs: invalid job count: " + Jobs); } else if (S.startswith("lldltopartitions=")) { StringRef N = S.substr(17); @@ -964,11 +1148,16 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { ICFLevel = 0; Config->DoGC = DoGC; Config->DoICF = ICFLevel > 0; + Config->TailMerge = (TailMerge == 1 && Config->DoICF) || TailMerge == 2; // Handle /lldsavetemps if (Args.hasArg(OPT_lldsavetemps)) Config->SaveTemps = true; + // Handle /kill-at + if (Args.hasArg(OPT_kill_at)) + Config->KillAt = true; + // Handle /lldltocache if (auto *Arg = Args.getLastArg(OPT_lldltocache)) Config->LTOCache = Arg->getValue(); @@ -987,6 +1176,14 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { for (auto *Arg : Args.filtered(OPT_merge)) parseMerge(Arg->getValue()); + // Add default section merging rules after user rules. User rules take + // precedence, but we will emit a warning if there is a conflict. + parseMerge(".idata=.rdata"); + parseMerge(".didat=.rdata"); + parseMerge(".edata=.rdata"); + parseMerge(".xdata=.rdata"); + parseMerge(".bss=.data"); + // Handle /section for (auto *Arg : Args.filtered(OPT_section)) parseSection(Arg->getValue()); @@ -1024,39 +1221,77 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { if (!Config->ManifestInput.empty() && Config->Manifest != Configuration::Embed) { - fatal("/MANIFESTINPUT: requires /MANIFEST:EMBED"); + fatal("/manifestinput: requires /manifest:embed"); } // Handle miscellaneous boolean flags. Config->AllowBind = Args.hasFlag(OPT_allowbind, OPT_allowbind_no, true); Config->AllowIsolation = Args.hasFlag(OPT_allowisolation, OPT_allowisolation_no, true); + Config->Incremental = + Args.hasFlag(OPT_incremental, OPT_incremental_no, + !Config->DoGC && !Config->DoICF && !Args.hasArg(OPT_order) && + !Args.hasArg(OPT_profile)); + Config->IntegrityCheck = + Args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false); Config->NxCompat = Args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true); - Config->TerminalServerAware = Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); + Config->TerminalServerAware = + !Config->DLL && Args.hasFlag(OPT_tsaware, OPT_tsaware_no, true); Config->DebugDwarf = Args.hasArg(OPT_debug_dwarf); Config->DebugGHashes = Args.hasArg(OPT_debug_ghash); + Config->DebugSymtab = Args.hasArg(OPT_debug_symtab); Config->MapFile = getMapFile(Args); + if (Config->Incremental && Args.hasArg(OPT_profile)) { + warn("ignoring '/incremental' due to '/profile' specification"); + Config->Incremental = false; + } + + if (Config->Incremental && Args.hasArg(OPT_order)) { + warn("ignoring '/incremental' due to '/order' specification"); + Config->Incremental = false; + } + + if (Config->Incremental && Config->DoGC) { + warn("ignoring '/incremental' because REF is enabled; use '/opt:noref' to " + "disable"); + Config->Incremental = false; + } + + if (Config->Incremental && Config->DoICF) { + warn("ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to " + "disable"); + Config->Incremental = false; + } + if (errorCount()) return; - bool WholeArchiveFlag = Args.hasArg(OPT_wholearchive_flag); + std::set<sys::fs::UniqueID> WholeArchives; + for (auto *Arg : Args.filtered(OPT_wholearchive_file)) + if (Optional<StringRef> Path = doFindFile(Arg->getValue())) + if (Optional<sys::fs::UniqueID> ID = getUniqueID(*Path)) + WholeArchives.insert(*ID); + + // A predicate returning true if a given path is an argument for + // /wholearchive:, or /wholearchive is enabled globally. + // This function is a bit tricky because "foo.obj /wholearchive:././foo.obj" + // needs to be handled as "/wholearchive:foo.obj foo.obj". + auto IsWholeArchive = [&](StringRef Path) -> bool { + if (Args.hasArg(OPT_wholearchive_flag)) + return true; + if (Optional<sys::fs::UniqueID> ID = getUniqueID(Path)) + return WholeArchives.count(*ID); + return false; + }; + // Create a list of input files. Files can be given as arguments // for /defaultlib option. - std::vector<MemoryBufferRef> MBs; - for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) { - switch (Arg->getOption().getID()) { - case OPT_INPUT: - if (Optional<StringRef> Path = findFile(Arg->getValue())) - enqueuePath(*Path, WholeArchiveFlag); - break; - case OPT_wholearchive_file: - if (Optional<StringRef> Path = findFile(Arg->getValue())) - enqueuePath(*Path, true); - break; - } - } + for (auto *Arg : Args.filtered(OPT_INPUT, OPT_wholearchive_file)) + if (Optional<StringRef> Path = findFile(Arg->getValue())) + enqueuePath(*Path, IsWholeArchive(*Path)); + for (auto *Arg : Args.filtered(OPT_defaultlib)) if (Optional<StringRef> Path = findLib(Arg->getValue())) enqueuePath(*Path, false); @@ -1160,10 +1395,24 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { getOutputPath((*Args.filtered(OPT_INPUT).begin())->getValue()); } - // Put the PDB next to the image if no /pdb flag was passed. - if (ShouldCreatePDB && Config->PDBPath.empty()) { - Config->PDBPath = Config->OutputFile; - sys::path::replace_extension(Config->PDBPath, ".pdb"); + if (ShouldCreatePDB) { + // Put the PDB next to the image if no /pdb flag was passed. + if (Config->PDBPath.empty()) { + Config->PDBPath = Config->OutputFile; + sys::path::replace_extension(Config->PDBPath, ".pdb"); + } + + // The embedded PDB path should be the absolute path to the PDB if no + // /pdbaltpath flag was passed. + if (Config->PDBAltPath.empty()) { + Config->PDBAltPath = Config->PDBPath; + + // It's important to make the path absolute and remove dots. This path + // will eventually be written into the PE header, and certain Microsoft + // tools won't work correctly if these assumptions are not held. + sys::fs::make_absolute(Config->PDBAltPath); + sys::path::remove_dots(Config->PDBAltPath); + } } // Set default image base if /base is not given. @@ -1176,11 +1425,9 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { Symtab->addAbsolute("___safe_se_handler_count", 0); } - // We do not support /guard:cf (control flow protection) yet. - // Define CFG symbols anyway so that we can link MSVC 2015 CRT. Symtab->addAbsolute(mangle("__guard_fids_count"), 0); Symtab->addAbsolute(mangle("__guard_fids_table"), 0); - Symtab->addAbsolute(mangle("__guard_flags"), 0x100); + Symtab->addAbsolute(mangle("__guard_flags"), 0); Symtab->addAbsolute(mangle("__guard_iat_count"), 0); Symtab->addAbsolute(mangle("__guard_iat_table"), 0); Symtab->addAbsolute(mangle("__guard_longjmp_count"), 0); @@ -1255,7 +1502,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // Handle /safeseh. if (Args.hasFlag(OPT_safeseh, OPT_safeseh_no, false)) { for (ObjFile *File : ObjFile::Instances) - if (!File->SEHCompat) + if (!File->hasSafeSEH()) error("/safeseh: " + File->getName() + " is not compatible with SEH"); if (errorCount()) return; @@ -1275,7 +1522,7 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { E.Name = Def->getName(); E.Sym = Def; if (Def->getChunk() && - !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) E.Data = true; Config->Exports.push_back(E); }); @@ -1318,6 +1565,12 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { if (Config->Manifest == Configuration::SideBySide) createSideBySideManifest(); + // Handle /order. We want to do this at this moment because we + // need a complete list of comdat sections to warn on nonexistent + // functions. + if (auto *Arg = Args.getLastArg(OPT_order)) + parseOrderFile(Arg->getValue()); + // Identify unreferenced COMDAT sections. if (Config->DoGC) markLive(Symtab->getChunks()); @@ -1328,6 +1581,11 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // Write the result. writeResult(); + + // Stop early so we can print the results. + Timer::root().stop(); + if (Config->ShowTiming) + Timer::root().print(); } } // namespace coff diff --git a/COFF/Driver.h b/COFF/Driver.h index 3f7fad1038f3..627e991a9028 100644 --- a/COFF/Driver.h +++ b/COFF/Driver.h @@ -21,6 +21,7 @@ #include "llvm/Object/COFF.h" #include "llvm/Option/Arg.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/TarWriter.h" #include <memory> #include <set> @@ -36,12 +37,6 @@ using llvm::COFF::MachineTypes; using llvm::COFF::WindowsSubsystem; using llvm::Optional; -// Implemented in MarkLive.cpp. -void markLive(ArrayRef<Chunk *> Chunks); - -// Implemented in ICF.cpp. -void doICF(ArrayRef<Chunk *> Chunks); - class COFFOptTable : public llvm::opt::OptTable { public: COFFOptTable(); @@ -56,8 +51,10 @@ public: llvm::opt::InputArgList parse(StringRef S) { return parse(tokenize(S)); } // Tokenizes a given string and then parses as command line options in - // .drectve section. - llvm::opt::InputArgList parseDirectives(StringRef S); + // .drectve section. /EXPORT options are returned in second element + // to be processed in fastpath. + std::pair<llvm::opt::InputArgList, std::vector<StringRef>> + parseDirectives(StringRef S); private: // Parses command line options. @@ -98,7 +95,11 @@ private: // Library search path. The first element is always "" (current directory). std::vector<StringRef> SearchPaths; - std::set<std::string> VisitedFiles; + + // We don't want to add the same file more than once. + // Files are uniquified by their filesystem and file number. + std::set<llvm::sys::fs::UniqueID> VisitedFiles; + std::set<std::string> VisitedLibs; Symbol *addUndefined(StringRef Sym); @@ -143,6 +144,8 @@ StringRef machineToStr(MachineTypes MT); // Parses a string in the form of "<integer>[,<integer>]". void parseNumbers(StringRef Arg, uint64_t *Addr, uint64_t *Size = nullptr); +void parseGuard(StringRef Arg); + // Parses a string in the form of "<integer>[.<integer>]". // Minor's default value is 0. void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor); diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index e0641e04a017..c12e791f9507 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -61,12 +61,7 @@ public: StringRef Exe = Saver.save(*ExeOrErr); Args.insert(Args.begin(), Exe); - std::vector<const char *> Vec; - for (StringRef S : Args) - Vec.push_back(S.data()); - Vec.push_back(nullptr); - - if (sys::ExecuteAndWait(Args[0], Vec.data()) != 0) + if (sys::ExecuteAndWait(Args[0], Args) != 0) fatal("ExecuteAndWait failed: " + llvm::join(Args.begin(), Args.end(), " ")); } @@ -128,6 +123,21 @@ void parseVersion(StringRef Arg, uint32_t *Major, uint32_t *Minor) { fatal("invalid number: " + S2); } +void parseGuard(StringRef FullArg) { + SmallVector<StringRef, 1> SplitArgs; + FullArg.split(SplitArgs, ","); + for (StringRef Arg : SplitArgs) { + if (Arg.equals_lower("no")) + Config->GuardCF = GuardCFLevel::Off; + else if (Arg.equals_lower("nolongjmp")) + Config->GuardCF = GuardCFLevel::NoLongJmp; + else if (Arg.equals_lower("cf") || Arg.equals_lower("longjmp")) + Config->GuardCF = GuardCFLevel::Full; + else + fatal("invalid argument to /guard: " + Arg); + } +} + // Parses a string in the form of "<subsystem>[,<integer>[.<integer>]]". void parseSubsystem(StringRef Arg, WindowsSubsystem *Sys, uint32_t *Major, uint32_t *Minor) { @@ -170,6 +180,10 @@ void parseMerge(StringRef S) { std::tie(From, To) = S.split('='); if (From.empty() || To.empty()) fatal("/merge: invalid argument: " + S); + if (From == ".rsrc" || To == ".rsrc") + fatal("/merge: cannot merge '.rsrc' with any section"); + if (From == ".reloc" || To == ".reloc") + fatal("/merge: cannot merge '.reloc' with any section"); auto Pair = Config->Merge.insert(std::make_pair(From, To)); bool Inserted = Pair.second; if (!Inserted) { @@ -418,15 +432,15 @@ static std::string createManifestXml() { return createManifestXmlWithExternalMt(DefaultXml); } -static std::unique_ptr<MemoryBuffer> +static std::unique_ptr<WritableMemoryBuffer> createMemoryBufferForManifestRes(size_t ManifestSize) { size_t ResSize = alignTo( object::WIN_RES_MAGIC_SIZE + object::WIN_RES_NULL_ENTRY_SIZE + sizeof(object::WinResHeaderPrefix) + sizeof(object::WinResIDs) + sizeof(object::WinResHeaderSuffix) + ManifestSize, object::WIN_RES_DATA_ALIGNMENT); - return MemoryBuffer::getNewMemBuffer(ResSize, - Config->OutputFile + ".manifest.res"); + return WritableMemoryBuffer::getNewMemBuffer(ResSize, Config->OutputFile + + ".manifest.res"); } static void writeResFileHeader(char *&Buf) { @@ -465,16 +479,16 @@ static void writeResEntryHeader(char *&Buf, size_t ManifestSize) { std::unique_ptr<MemoryBuffer> createManifestRes() { std::string Manifest = createManifestXml(); - std::unique_ptr<MemoryBuffer> Res = + std::unique_ptr<WritableMemoryBuffer> Res = createMemoryBufferForManifestRes(Manifest.size()); - char *Buf = const_cast<char *>(Res->getBufferStart()); + char *Buf = Res->getBufferStart(); writeResFileHeader(Buf); writeResEntryHeader(Buf, Manifest.size()); // Copy the manifest data into the .res file. std::copy(Manifest.begin(), Manifest.end(), Buf); - return Res; + return std::move(Res); } void createSideBySideManifest() { @@ -558,9 +572,35 @@ err: static StringRef undecorate(StringRef Sym) { if (Config->Machine != I386) return Sym; + // In MSVC mode, a fully decorated stdcall function is exported + // as-is with the leading underscore (with type IMPORT_NAME). + // In MinGW mode, a decorated stdcall function gets the underscore + // removed, just like normal cdecl functions. + if (Sym.startswith("_") && Sym.contains('@') && !Config->MinGW) + return Sym; return Sym.startswith("_") ? Sym.substr(1) : Sym; } +// Convert stdcall/fastcall style symbols into unsuffixed symbols, +// with or without a leading underscore. (MinGW specific.) +static StringRef killAt(StringRef Sym, bool Prefix) { + if (Sym.empty()) + return Sym; + // Strip any trailing stdcall suffix + Sym = Sym.substr(0, Sym.find('@', 1)); + if (!Sym.startswith("@")) { + if (Prefix && !Sym.startswith("_")) + return Saver.save("_" + Sym); + return Sym; + } + // For fastcall, remove the leading @ and replace it with an + // underscore, if prefixes are used. + Sym = Sym.substr(1); + if (Prefix) + Sym = Saver.save("_" + Sym); + return Sym; +} + // Performs error checking on all /export arguments. // It also sets ordinals. void fixupExports() { @@ -593,6 +633,15 @@ void fixupExports() { } } + if (Config->KillAt && Config->Machine == I386) { + for (Export &E : Config->Exports) { + E.Name = killAt(E.Name, true); + E.ExportName = killAt(E.ExportName, false); + E.ExtName = killAt(E.ExtName, true); + E.SymbolName = killAt(E.SymbolName, true); + } + } + // Uniquefy by name. DenseMap<StringRef, Export *> Map(Config->Exports.size()); std::vector<Export> V; @@ -702,6 +751,28 @@ static const llvm::opt::OptTable::Info InfoTable[] = { COFFOptTable::COFFOptTable() : OptTable(InfoTable, true) {} +// Set color diagnostics according to --color-diagnostics={auto,always,never} +// or --no-color-diagnostics flags. +static void handleColorDiagnostics(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_color_diagnostics_eq, + OPT_no_color_diagnostics); + if (!Arg) + return; + if (Arg->getOption().getID() == OPT_color_diagnostics) { + errorHandler().ColorDiagnostics = true; + } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { + errorHandler().ColorDiagnostics = false; + } else { + StringRef S = Arg->getValue(); + if (S == "always") + errorHandler().ColorDiagnostics = true; + else if (S == "never") + errorHandler().ColorDiagnostics = false; + else if (S != "auto") + error("unknown option: --color-diagnostics=" + S); + } +} + static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { if (auto *Arg = Args.getLastArg(OPT_rsp_quoting)) { StringRef S = Arg->getValue(); @@ -720,50 +791,73 @@ opt::InputArgList ArgParser::parse(ArrayRef<const char *> Argv) { // Make InputArgList from string vectors. unsigned MissingIndex; unsigned MissingCount; - SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); // We need to get the quoting style for response files before parsing all // options so we parse here before and ignore all the options but // --rsp-quoting. - opt::InputArgList Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); + opt::InputArgList Args = Table.ParseArgs(Argv, MissingIndex, MissingCount); // Expand response files (arguments in the form of @<filename>) // and then parse the argument again. - cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); - Args = Table.ParseArgs(Vec, MissingIndex, MissingCount); + SmallVector<const char *, 256> ExpandedArgv(Argv.data(), Argv.data() + Argv.size()); + cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), ExpandedArgv); + Args = Table.ParseArgs(makeArrayRef(ExpandedArgv).drop_front(), MissingIndex, + MissingCount); // Print the real command line if response files are expanded. - if (Args.hasArg(OPT_verbose) && Argv.size() != Vec.size()) { + if (Args.hasArg(OPT_verbose) && Argv.size() != ExpandedArgv.size()) { std::string Msg = "Command line:"; - for (const char *S : Vec) + for (const char *S : ExpandedArgv) Msg += " " + std::string(S); message(Msg); } + // Save the command line after response file expansion so we can write it to + // the PDB if necessary. + Config->Argv = {ExpandedArgv.begin(), ExpandedArgv.end()}; + // Handle /WX early since it converts missing argument warnings to errors. errorHandler().FatalWarnings = Args.hasFlag(OPT_WX, OPT_WX_no, false); if (MissingCount) fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); + + handleColorDiagnostics(Args); + for (auto *Arg : Args.filtered(OPT_UNKNOWN)) warn("ignoring unknown argument: " + Arg->getSpelling()); + + if (Args.hasArg(OPT_lib)) + warn("ignoring /lib since it's not the first argument"); + return Args; } // Tokenizes and parses a given string as command line in .drective section. -opt::InputArgList ArgParser::parseDirectives(StringRef S) { - // Make InputArgList from string vectors. +// /EXPORT options are processed in fastpath. +std::pair<opt::InputArgList, std::vector<StringRef>> +ArgParser::parseDirectives(StringRef S) { + std::vector<StringRef> Exports; + SmallVector<const char *, 16> Rest; + + for (StringRef Tok : tokenize(S)) { + if (Tok.startswith_lower("/export:") || Tok.startswith_lower("-export:")) + Exports.push_back(Tok.substr(strlen("/export:"))); + else + Rest.push_back(Tok.data()); + } + + // Make InputArgList from unparsed string vectors. unsigned MissingIndex; unsigned MissingCount; - opt::InputArgList Args = - Table.ParseArgs(tokenize(S), MissingIndex, MissingCount); + opt::InputArgList Args = Table.ParseArgs(Rest, MissingIndex, MissingCount); if (MissingCount) fatal(Twine(Args.getArgString(MissingIndex)) + ": missing argument"); for (auto *Arg : Args.filtered(OPT_UNKNOWN)) warn("ignoring unknown argument: " + Arg->getSpelling()); - return Args; + return {std::move(Args), std::move(Exports)}; } // link.exe has an interesting feature. If LINK or _LINK_ environment @@ -773,11 +867,11 @@ opt::InputArgList ArgParser::parseLINK(std::vector<const char *> Argv) { // Concatenate LINK env and command line arguments, and then parse them. if (Optional<std::string> S = Process::GetEnv("LINK")) { std::vector<const char *> V = tokenize(*S); - Argv.insert(Argv.begin(), V.begin(), V.end()); + Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); } if (Optional<std::string> S = Process::GetEnv("_LINK_")) { std::vector<const char *> V = tokenize(*S); - Argv.insert(Argv.begin(), V.begin(), V.end()); + Argv.insert(std::next(Argv.begin()), V.begin(), V.end()); } return parse(Argv); } diff --git a/COFF/ICF.cpp b/COFF/ICF.cpp index 48895c34886c..629720901ab8 100644 --- a/COFF/ICF.cpp +++ b/COFF/ICF.cpp @@ -18,9 +18,11 @@ // //===----------------------------------------------------------------------===// +#include "ICF.h" #include "Chunks.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" +#include "lld/Common/Timer.h" #include "llvm/ADT/Hashing.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Parallel.h" @@ -34,6 +36,8 @@ using namespace llvm; namespace lld { namespace coff { +static Timer ICFTimer("ICF", Timer::root()); + class ICF { public: void run(ArrayRef<Chunk *> V); @@ -41,6 +45,8 @@ public: private: void segregate(size_t Begin, size_t End, bool Constant); + bool assocEquals(const SectionChunk *A, const SectionChunk *B); + bool equalsConstant(const SectionChunk *A, const SectionChunk *B); bool equalsVariable(const SectionChunk *A, const SectionChunk *B); @@ -61,8 +67,8 @@ private: // Returns a hash value for S. uint32_t ICF::getHash(SectionChunk *C) { - return hash_combine(C->getPermissions(), C->SectionName, C->NumRelocs, - C->Alignment, uint32_t(C->Header->SizeOfRawData), + return hash_combine(C->getOutputCharacteristics(), C->SectionName, + C->Relocs.size(), uint32_t(C->Header->SizeOfRawData), C->Checksum, C->getContents()); } @@ -73,21 +79,27 @@ uint32_t ICF::getHash(SectionChunk *C) { // 2017) says that /opt:icf folds both functions and read-only data. // Despite that, the MSVC linker folds only functions. We found // a few instances of programs that are not safe for data merging. -// Therefore, we merge only functions just like the MSVC tool. However, we merge -// identical .xdata sections, because the address of unwind information is -// insignificant to the user program and the Visual C++ linker does this. +// Therefore, we merge only functions just like the MSVC tool. However, we also +// merge read-only sections in a couple of cases where the address of the +// section is insignificant to the user program and the behaviour matches that +// of the Visual C++ linker. bool ICF::isEligible(SectionChunk *C) { // Non-comdat chunks, dead chunks, and writable chunks are not elegible. - bool Writable = C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_WRITE; + bool Writable = C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_WRITE; if (!C->isCOMDAT() || !C->isLive() || Writable) return false; // Code sections are eligible. - if (C->getPermissions() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) + if (C->getOutputCharacteristics() & llvm::COFF::IMAGE_SCN_MEM_EXECUTE) + return true; + + // .pdata and .xdata unwind info sections are eligible. + StringRef OutSecName = C->getSectionName().split('$').first; + if (OutSecName == ".pdata" || OutSecName == ".xdata") return true; - // .xdata unwind info sections are eligble. - return C->getSectionName().split('$').first == ".xdata"; + // So are vtables. + return C->Sym && C->Sym->getName().startswith("??_7"); } // Split an equivalence class into smaller classes. @@ -116,10 +128,23 @@ void ICF::segregate(size_t Begin, size_t End, bool Constant) { } } +// Returns true if two sections' associative children are equal. +bool ICF::assocEquals(const SectionChunk *A, const SectionChunk *B) { + auto ChildClasses = [&](const SectionChunk *SC) { + std::vector<uint32_t> Classes; + for (const SectionChunk *C : SC->children()) + if (!C->SectionName.startswith(".debug") && + C->SectionName != ".gfids$y" && C->SectionName != ".gljmp$y") + Classes.push_back(C->Class[Cnt % 2]); + return Classes; + }; + return ChildClasses(A) == ChildClasses(B); +} + // Compare "non-moving" part of two sections, namely everything // except relocation targets. bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { - if (A->NumRelocs != B->NumRelocs) + if (A->Relocs.size() != B->Relocs.size()) return false; // Compare relocations. @@ -142,10 +167,11 @@ bool ICF::equalsConstant(const SectionChunk *A, const SectionChunk *B) { return false; // Compare section attributes and contents. - return A->getPermissions() == B->getPermissions() && - A->SectionName == B->SectionName && A->Alignment == B->Alignment && + return A->getOutputCharacteristics() == B->getOutputCharacteristics() && + A->SectionName == B->SectionName && A->Header->SizeOfRawData == B->Header->SizeOfRawData && - A->Checksum == B->Checksum && A->getContents() == B->getContents(); + A->Checksum == B->Checksum && A->getContents() == B->getContents() && + assocEquals(A, B); } // Compare "moving" part of two sections, namely relocation targets. @@ -161,9 +187,12 @@ bool ICF::equalsVariable(const SectionChunk *A, const SectionChunk *B) { return D1->getChunk()->Class[Cnt % 2] == D2->getChunk()->Class[Cnt % 2]; return false; }; - return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), Eq); + return std::equal(A->Relocs.begin(), A->Relocs.end(), B->Relocs.begin(), + Eq) && + assocEquals(A, B); } +// Find the first Chunk after Begin that has a different class from Begin. size_t ICF::findBoundary(size_t Begin, size_t End) { for (size_t I = Begin + 1; I < End; ++I) if (Chunks[Begin]->Class[Cnt % 2] != Chunks[I]->Class[Cnt % 2]) @@ -173,11 +202,8 @@ size_t ICF::findBoundary(size_t Begin, size_t End) { void ICF::forEachClassRange(size_t Begin, size_t End, std::function<void(size_t, size_t)> Fn) { - if (Begin > 0) - Begin = findBoundary(Begin - 1, End); - while (Begin < End) { - size_t Mid = findBoundary(Begin, Chunks.size()); + size_t Mid = findBoundary(Begin, End); Fn(Begin, Mid); Begin = Mid; } @@ -193,12 +219,22 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) { return; } - // Split sections into 256 shards and call Fn in parallel. - size_t NumShards = 256; + // Shard into non-overlapping intervals, and call Fn in parallel. + // The sharding must be completed before any calls to Fn are made + // so that Fn can modify the Chunks in its shard without causing data + // races. + const size_t NumShards = 256; size_t Step = Chunks.size() / NumShards; - for_each_n(parallel::par, size_t(0), NumShards, [&](size_t I) { - size_t End = (I == NumShards - 1) ? Chunks.size() : (I + 1) * Step; - forEachClassRange(I * Step, End, Fn); + size_t Boundaries[NumShards + 1]; + Boundaries[0] = 0; + Boundaries[NumShards] = Chunks.size(); + for_each_n(parallel::par, size_t(1), NumShards, [&](size_t I) { + Boundaries[I] = findBoundary((I - 1) * Step, Chunks.size()); + }); + for_each_n(parallel::par, size_t(1), NumShards + 1, [&](size_t I) { + if (Boundaries[I - 1] < Boundaries[I]) { + forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); + } }); ++Cnt; } @@ -207,6 +243,8 @@ void ICF::forEachClass(std::function<void(size_t, size_t)> Fn) { // Two sections are considered the same if their section headers, // contents and relocations are all the same. void ICF::run(ArrayRef<Chunk *> Vec) { + ScopedTimer T(ICFTimer); + // Collect only mergeable sections and group by hash value. uint32_t NextId = 1; for (Chunk *C : Vec) { @@ -218,6 +256,12 @@ void ICF::run(ArrayRef<Chunk *> Vec) { } } + // Make sure that ICF doesn't merge sections that are being handled by string + // tail merging. + for (auto &P : MergeChunk::Instances) + for (SectionChunk *SC : P.second->Sections) + SC->Class[0] = NextId++; + // Initially, we use hash values to partition sections. for_each(parallel::par, Chunks.begin(), Chunks.end(), [&](SectionChunk *SC) { // Set MSB to 1 to avoid collisions with non-hash classs. diff --git a/COFF/Strings.h b/COFF/ICF.h index 67fc1c773c66..9c54e0c9ec2d 100644 --- a/COFF/Strings.h +++ b/COFF/ICF.h @@ -1,4 +1,4 @@ -//===- Strings.h ------------------------------------------------*- C++ -*-===// +//===- ICF.h --------------------------------------------------------------===// // // The LLVM Linker // @@ -7,17 +7,20 @@ // //===----------------------------------------------------------------------===// -#ifndef LLD_COFF_STRINGS_H -#define LLD_COFF_STRINGS_H +#ifndef LLD_COFF_ICF_H +#define LLD_COFF_ICF_H -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include <string> +#include "lld/Common/LLVM.h" +#include "llvm/ADT/ArrayRef.h" namespace lld { namespace coff { -llvm::Optional<std::string> demangleMSVC(llvm::StringRef S); -} -} + +class Chunk; + +void doICF(ArrayRef<Chunk *> Chunks); + +} // namespace coff +} // namespace lld #endif diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index a8f52e0391f7..2b3e65fae04b 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Target/TargetOptions.h" #include <cstring> #include <system_error> @@ -138,12 +139,13 @@ void ObjFile::initializeChunks() { if (Sec->Characteristics & IMAGE_SCN_LNK_COMDAT) SparseChunks[I] = PendingComdat; else - SparseChunks[I] = readSection(I, nullptr); + SparseChunks[I] = readSection(I, nullptr, ""); } } SectionChunk *ObjFile::readSection(uint32_t SectionNumber, - const coff_aux_section_definition *Def) { + const coff_aux_section_definition *Def, + StringRef LeaderName) { const coff_section *Sec; StringRef Name; if (auto EC = COFFObj->getSection(SectionNumber, Sec)) @@ -151,15 +153,7 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber, if (auto EC = COFFObj->getSectionName(Sec, Name)) fatal("getSectionName failed: #" + Twine(SectionNumber) + ": " + EC.message()); - if (Name == ".sxdata") { - ArrayRef<uint8_t> Data; - COFFObj->getSectionContents(Sec, Data); - if (Data.size() % 4 != 0) - fatal(".sxdata must be an array of symbol table indices"); - SXData = {reinterpret_cast<const ulittle32_t *>(Data.data()), - Data.size() / 4}; - return nullptr; - } + if (Name == ".drectve") { ArrayRef<uint8_t> Data; COFFObj->getSectionContents(Sec, Data); @@ -177,8 +171,8 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber, // CodeView needs a linker support. We need to interpret and debug // info, and then write it to a separate .pdb file. - // Ignore debug info unless /debug is given. - if (!Config->Debug && Name.startswith(".debug")) + // Ignore DWARF debug info unless /debug is given. + if (!Config->Debug && Name.startswith(".debug_")) return nullptr; if (Sec->Characteristics & llvm::COFF::IMAGE_SCN_LNK_REMOVE) @@ -191,6 +185,18 @@ SectionChunk *ObjFile::readSection(uint32_t SectionNumber, // linked in the regular manner. if (C->isCodeView()) DebugChunks.push_back(C); + else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gfids$y") + GuardFidChunks.push_back(C); + else if (Config->GuardCF != GuardCFLevel::Off && Name == ".gljmp$y") + GuardLJmpChunks.push_back(C); + else if (Name == ".sxdata") + SXDataChunks.push_back(C); + else if (Config->TailMerge && Sec->NumberOfRelocations == 0 && + Name == ".rdata" && LeaderName.startswith("??_C@")) + // COFF sections that look like string literal sections (i.e. no + // relocations, in .rdata, leader symbol name matches the MSVC name mangling + // for string literals) are subject to string tail merging. + MergeChunk::addSection(C); else Chunks.push_back(C); @@ -211,7 +217,7 @@ void ObjFile::readAssociativeDefinition( // the section; otherwise mark it as discarded. int32_t SectionNumber = Sym.getSectionNumber(); if (Parent) { - SparseChunks[SectionNumber] = readSection(SectionNumber, Def); + SparseChunks[SectionNumber] = readSection(SectionNumber, Def, ""); if (SparseChunks[SectionNumber]) Parent->addAssociative(SparseChunks[SectionNumber]); } else { @@ -275,6 +281,13 @@ void ObjFile::initializeSymbols() { if (auto *Def = Sym.getSectionDefinition()) if (Def->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) readAssociativeDefinition(Sym, Def); + if (SparseChunks[Sym.getSectionNumber()] == PendingComdat) { + StringRef Name; + COFFObj->getSymbolName(Sym, Name); + log("comdat section " + Name + + " without leader and unassociated, discarding"); + continue; + } Symbols[I] = createRegular(Sym); } @@ -294,43 +307,46 @@ Symbol *ObjFile::createUndefined(COFFSymbolRef Sym) { Optional<Symbol *> ObjFile::createDefined( COFFSymbolRef Sym, std::vector<const coff_aux_section_definition *> &ComdatDefs) { - StringRef Name; + auto GetName = [&]() { + StringRef S; + COFFObj->getSymbolName(Sym, S); + return S; + }; + if (Sym.isCommon()) { auto *C = make<CommonChunk>(Sym); Chunks.push_back(C); - COFFObj->getSymbolName(Sym, Name); - Symbol *S = - Symtab->addCommon(this, Name, Sym.getValue(), Sym.getGeneric(), C); - return S; + return Symtab->addCommon(this, GetName(), Sym.getValue(), Sym.getGeneric(), + C); } + if (Sym.isAbsolute()) { - COFFObj->getSymbolName(Sym, Name); + StringRef Name = GetName(); + // Skip special symbols. if (Name == "@comp.id") return nullptr; - // COFF spec 5.10.1. The .sxdata section. if (Name == "@feat.00") { - if (Sym.getValue() & 1) - SEHCompat = true; + Feat00Flags = Sym.getValue(); return nullptr; } + if (Sym.isExternal()) return Symtab->addAbsolute(Name, Sym); - else - return make<DefinedAbsolute>(Name, Sym); + return make<DefinedAbsolute>(Name, Sym); } + int32_t SectionNumber = Sym.getSectionNumber(); if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG) return nullptr; - // Reserved sections numbers don't have contents. if (llvm::COFF::isReservedSectionNumber(SectionNumber)) - fatal("broken object file: " + toString(this)); + fatal(toString(this) + ": " + GetName() + + " should not refer to special section " + Twine(SectionNumber)); - // This symbol references a section which is not present in the section - // header. if ((uint32_t)SectionNumber >= SparseChunks.size()) - fatal("broken object file: " + toString(this)); + fatal(toString(this) + ": " + GetName() + + " should not refer to non-existent section " + Twine(SectionNumber)); // Handle comdat leader symbols. if (const coff_aux_section_definition *Def = ComdatDefs[SectionNumber]) { @@ -338,16 +354,16 @@ Optional<Symbol *> ObjFile::createDefined( Symbol *Leader; bool Prevailing; if (Sym.isExternal()) { - COFFObj->getSymbolName(Sym, Name); std::tie(Leader, Prevailing) = - Symtab->addComdat(this, Name, Sym.getGeneric()); + Symtab->addComdat(this, GetName(), Sym.getGeneric()); } else { Leader = make<DefinedRegular>(this, /*Name*/ "", false, /*IsExternal*/ false, Sym.getGeneric()); Prevailing = true; } + if (Prevailing) { - SectionChunk *C = readSection(SectionNumber, Def); + SectionChunk *C = readSection(SectionNumber, Def, GetName()); SparseChunks[SectionNumber] = C; C->Sym = cast<DefinedRegular>(Leader); cast<DefinedRegular>(Leader)->Data = &C->Repl; @@ -429,7 +445,8 @@ void ImportFile::parse() { // address pointed by the __imp_ symbol. (This allows you to call // DLL functions just like regular non-DLL functions.) if (Hdr->getType() == llvm::COFF::IMPORT_CODE) - ThunkSym = Symtab->addImportThunk(Name, ImpSym, Hdr->Machine); + ThunkSym = Symtab->addImportThunk( + Name, cast_or_null<DefinedImportData>(ImpSym), Hdr->Machine); } void BitcodeFile::parse() { @@ -462,7 +479,7 @@ void BitcodeFile::parse() { } else { Sym = Symtab->addRegular(this, SymName); } - SymbolBodies.push_back(Sym); + Symbols.push_back(Sym); } Directives = Obj->getCOFFLinkerOpts(); } @@ -486,10 +503,7 @@ MachineTypes BitcodeFile::getMachineType() { // Returns the last element of a path, which is supposed to be a filename. static StringRef getBasename(StringRef Path) { - size_t Pos = Path.find_last_of("\\/"); - if (Pos == StringRef::npos) - return Path; - return Path.substr(Pos + 1); + return sys::path::filename(Path, sys::path::Style::windows); } // Returns a string in the format of "foo.obj" or "foo.obj(bar.lib)". diff --git a/COFF/InputFiles.h b/COFF/InputFiles.h index adedbc2ad7a8..4ee4b363886f 100644 --- a/COFF/InputFiles.h +++ b/COFF/InputFiles.h @@ -110,6 +110,9 @@ public: MachineTypes getMachineType() override; ArrayRef<Chunk *> getChunks() { return Chunks; } ArrayRef<SectionChunk *> getDebugChunks() { return DebugChunks; } + ArrayRef<SectionChunk *> getSXDataChunks() { return SXDataChunks; } + ArrayRef<SectionChunk *> getGuardFidChunks() { return GuardFidChunks; } + ArrayRef<SectionChunk *> getGuardLJmpChunks() { return GuardLJmpChunks; } ArrayRef<Symbol *> getSymbols() { return Symbols; } // Returns a Symbol object for the SymbolIndex'th symbol in the @@ -123,13 +126,17 @@ public: static std::vector<ObjFile *> Instances; - // True if this object file is compatible with SEH. - // COFF-specific and x86-only. - bool SEHCompat = false; + // Flags in the absolute @feat.00 symbol if it is present. These usually + // indicate if an object was compiled with certain security features enabled + // like stack guard, safeseh, /guard:cf, or other things. + uint32_t Feat00Flags = 0; - // The symbol table indexes of the safe exception handlers. - // COFF-specific and x86-only. - ArrayRef<llvm::support::ulittle32_t> SXData; + // True if this object file is compatible with SEH. COFF-specific and + // x86-only. COFF spec 5.10.1. The .sxdata section. + bool hasSafeSEH() { return Feat00Flags & 0x1; } + + // True if this file was compiled with /guard:cf. + bool hasGuardCF() { return Feat00Flags & 0x800; } // Pointer to the PDB module descriptor builder. Various debug info records // will reference object files by "module index", which is here. Things like @@ -143,7 +150,8 @@ private: SectionChunk * readSection(uint32_t SectionNumber, - const llvm::object::coff_aux_section_definition *Def); + const llvm::object::coff_aux_section_definition *Def, + StringRef LeaderName); void readAssociativeDefinition( COFFSymbolRef COFFSym, @@ -165,6 +173,15 @@ private: // CodeView debug info sections. std::vector<SectionChunk *> DebugChunks; + // Chunks containing symbol table indices of exception handlers. Only used for + // 32-bit x86. + std::vector<SectionChunk *> SXDataChunks; + + // Chunks containing symbol table indices of address taken symbols and longjmp + // targets. These are not linked into the final binary when /guard:cf is set. + std::vector<SectionChunk *> GuardFidChunks; + std::vector<SectionChunk *> GuardLJmpChunks; + // This vector contains the same chunks as Chunks, but they are // indexed such that you can get a SectionChunk by section index. // Nonexistent section indices are filled with null pointers. @@ -184,15 +201,14 @@ private: // for details about the format. class ImportFile : public InputFile { public: - explicit ImportFile(MemoryBufferRef M) - : InputFile(ImportKind, M), Live(!Config->DoGC) {} + explicit ImportFile(MemoryBufferRef M) : InputFile(ImportKind, M) {} static bool classof(const InputFile *F) { return F->kind() == ImportKind; } static std::vector<ImportFile *> Instances; - DefinedImportData *ImpSym = nullptr; - DefinedImportThunk *ThunkSym = nullptr; + Symbol *ImpSym = nullptr; + Symbol *ThunkSym = nullptr; std::string DLLName; private: @@ -204,12 +220,15 @@ public: Chunk *Location = nullptr; // We want to eliminate dllimported symbols if no one actually refers them. - // This "Live" bit is used to keep track of which import library members + // These "Live" bits are used to keep track of which import library members // are actually in use. // // If the Live bit is turned off by MarkLive, Writer will ignore dllimported - // symbols provided by this import library member. - bool Live; + // symbols provided by this import library member. We also track whether the + // imported symbol is used separately from whether the thunk is used in order + // to avoid creating unnecessary thunks. + bool Live = !Config->DoGC; + bool ThunkLive = !Config->DoGC; }; // Used for LTO. @@ -217,7 +236,7 @@ class BitcodeFile : public InputFile { public: explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } - ArrayRef<Symbol *> getSymbols() { return SymbolBodies; } + ArrayRef<Symbol *> getSymbols() { return Symbols; } MachineTypes getMachineType() override; static std::vector<BitcodeFile *> Instances; std::unique_ptr<llvm::lto::InputFile> Obj; @@ -225,7 +244,7 @@ public: private: void parse() override; - std::vector<Symbol *> SymbolBodies; + std::vector<Symbol *> Symbols; }; } // namespace coff diff --git a/COFF/LTO.cpp b/COFF/LTO.cpp index fa2a54b61841..93f7ba3f9e4c 100644 --- a/COFF/LTO.cpp +++ b/COFF/LTO.cpp @@ -12,6 +12,7 @@ #include "InputFiles.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" +#include "lld/Common/Strings.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" @@ -40,47 +41,32 @@ using namespace llvm::object; using namespace lld; using namespace lld::coff; -static void diagnosticHandler(const DiagnosticInfo &DI) { - SmallString<128> ErrStorage; - raw_svector_ostream OS(ErrStorage); - DiagnosticPrinterRawOStream DP(OS); - DI.print(DP); - warn(ErrStorage); -} - -static void checkError(Error E) { - handleAllErrors(std::move(E), - [&](ErrorInfoBase &EIB) { error(EIB.message()); }); -} +static std::unique_ptr<lto::LTO> createLTO() { + lto::Config C; + C.Options = InitTargetOptionsFromCodeGenFlags(); -static void saveBuffer(StringRef Buffer, const Twine &Path) { - std::error_code EC; - raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); - if (EC) - error("cannot create " + Path + ": " + EC.message()); - OS << Buffer; -} + // Always emit a section per function/datum with LTO. LLVM LTO should get most + // of the benefit of linker GC, but there are still opportunities for ICF. + C.Options.FunctionSections = true; + C.Options.DataSections = true; -static std::unique_ptr<lto::LTO> createLTO() { - lto::Config Conf; - Conf.Options = InitTargetOptionsFromCodeGenFlags(); // Use static reloc model on 32-bit x86 because it usually results in more // compact code, and because there are also known code generation bugs when // using the PIC model (see PR34306). if (Config->Machine == COFF::IMAGE_FILE_MACHINE_I386) - Conf.RelocModel = Reloc::Static; + C.RelocModel = Reloc::Static; else - Conf.RelocModel = Reloc::PIC_; - Conf.DisableVerify = true; - Conf.DiagHandler = diagnosticHandler; - Conf.OptLevel = Config->LTOOptLevel; + C.RelocModel = Reloc::PIC_; + C.DisableVerify = true; + C.DiagHandler = diagnosticHandler; + C.OptLevel = Config->LTOO; if (Config->SaveTemps) - checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", - /*UseInputModulePath*/ true)); + checkError(C.addSaveTemps(std::string(Config->OutputFile) + ".", + /*UseInputModulePath*/ true)); lto::ThinBackend Backend; - if (Config->LTOJobs != 0) - Backend = lto::createInProcessThinBackend(Config->LTOJobs); - return llvm::make_unique<lto::LTO>(std::move(Conf), Backend, + if (Config->ThinLTOJobs != 0) + Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); + return llvm::make_unique<lto::LTO>(std::move(C), Backend, Config->LTOPartitions); } @@ -119,7 +105,7 @@ void BitcodeCompiler::add(BitcodeFile &F) { // and return the resulting objects. std::vector<StringRef> BitcodeCompiler::compile() { unsigned MaxTasks = LTOObj->getMaxTasks(); - Buff.resize(MaxTasks); + Buf.resize(MaxTasks); Files.resize(MaxTasks); // The /lldltocache option specifies the path to a directory in which to cache @@ -127,15 +113,15 @@ std::vector<StringRef> BitcodeCompiler::compile() { // specified, configure LTO to use it as the cache directory. lto::NativeObjectCache Cache; if (!Config->LTOCache.empty()) - Cache = check( - lto::localCache(Config->LTOCache, - [&](size_t Task, std::unique_ptr<MemoryBuffer> MB, - StringRef Path) { Files[Task] = std::move(MB); })); + Cache = check(lto::localCache( + Config->LTOCache, [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { + Files[Task] = std::move(MB); + })); checkError(LTOObj->run( [&](size_t Task) { return llvm::make_unique<lto::NativeObjectStream>( - llvm::make_unique<raw_svector_ostream>(Buff[Task])); + llvm::make_unique<raw_svector_ostream>(Buf[Task])); }, Cache)); @@ -144,15 +130,15 @@ std::vector<StringRef> BitcodeCompiler::compile() { std::vector<StringRef> Ret; for (unsigned I = 0; I != MaxTasks; ++I) { - if (Buff[I].empty()) + if (Buf[I].empty()) continue; if (Config->SaveTemps) { if (I == 0) - saveBuffer(Buff[I], Config->OutputFile + ".lto.obj"); + saveBuffer(Buf[I], Config->OutputFile + ".lto.obj"); else - saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.obj"); + saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.obj"); } - Ret.emplace_back(Buff[I].data(), Buff[I].size()); + Ret.emplace_back(Buf[I].data(), Buf[I].size()); } for (std::unique_ptr<MemoryBuffer> &File : Files) diff --git a/COFF/LTO.h b/COFF/LTO.h index a444aa7ac4fe..f00924654780 100644 --- a/COFF/LTO.h +++ b/COFF/LTO.h @@ -48,7 +48,7 @@ public: private: std::unique_ptr<llvm::lto::LTO> LTOObj; - std::vector<SmallString<0>> Buff; + std::vector<SmallString<0>> Buf; std::vector<std::unique_ptr<MemoryBuffer>> Files; }; } diff --git a/COFF/MapFile.cpp b/COFF/MapFile.cpp index 717ed3419ea5..6ca1b6647bd7 100644 --- a/COFF/MapFile.cpp +++ b/COFF/MapFile.cpp @@ -23,7 +23,6 @@ #include "SymbolTable.h" #include "Symbols.h" #include "Writer.h" - #include "lld/Common/ErrorHandler.h" #include "llvm/Support/Parallel.h" #include "llvm/Support/raw_ostream.h" @@ -37,14 +36,15 @@ using namespace lld::coff; typedef DenseMap<const SectionChunk *, SmallVector<DefinedRegular *, 4>> SymbolMapTy; +static const std::string Indent8 = " "; // 8 spaces +static const std::string Indent16 = " "; // 16 spaces + // Print out the first three columns of a line. static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, uint64_t Align) { OS << format("%08llx %08llx %5lld ", Addr, Size, Align); } -static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } - // Returns a list of all symbols that we want to print out. static std::vector<DefinedRegular *> getSymbols() { std::vector<DefinedRegular *> V; @@ -79,7 +79,7 @@ getSymbolStrings(ArrayRef<DefinedRegular *> Syms) { for_each_n(parallel::par, (size_t)0, Syms.size(), [&](size_t I) { raw_string_ostream OS(Str[I]); writeHeader(OS, Syms[I]->getRVA(), 0, 0); - OS << indent(2) << toString(*Syms[I]); + OS << Indent16 << toString(*Syms[I]); }); DenseMap<DefinedRegular *, std::string> Ret; @@ -108,7 +108,7 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) { // Print out file contents. for (OutputSection *Sec : OutputSections) { writeHeader(OS, Sec->getRVA(), Sec->getVirtualSize(), /*Align=*/PageSize); - OS << Sec->getName() << '\n'; + OS << Sec->Name << '\n'; for (Chunk *C : Sec->getChunks()) { auto *SC = dyn_cast<SectionChunk>(C); @@ -116,7 +116,7 @@ void coff::writeMapFile(ArrayRef<OutputSection *> OutputSections) { continue; writeHeader(OS, SC->getRVA(), SC->getSize(), SC->Alignment); - OS << indent(1) << SC->File->getName() << ":(" << SC->getSectionName() + OS << Indent8 << SC->File->getName() << ":(" << SC->getSectionName() << ")\n"; for (DefinedRegular *Sym : SectionSyms[SC]) OS << SymStr[Sym] << '\n'; diff --git a/COFF/MarkLive.cpp b/COFF/MarkLive.cpp index 01be60d12d82..57ae450a9138 100644 --- a/COFF/MarkLive.cpp +++ b/COFF/MarkLive.cpp @@ -9,16 +9,21 @@ #include "Chunks.h" #include "Symbols.h" +#include "lld/Common/Timer.h" #include "llvm/ADT/STLExtras.h" #include <vector> namespace lld { namespace coff { +static Timer GCTimer("GC", Timer::root()); + // Set live bit on for each reachable chunk. Unmarked (unreachable) // COMDAT chunks will be ignored by Writer, so they will be excluded // from the final output. void markLive(ArrayRef<Chunk *> Chunks) { + ScopedTimer T(GCTimer); + // We build up a worklist of sections which have been marked as live. We only // push into the worklist when we discover an unmarked section, and we mark // as we push, so sections never appear twice in the list. @@ -43,7 +48,7 @@ void markLive(ArrayRef<Chunk *> Chunks) { else if (auto *Sym = dyn_cast<DefinedImportData>(B)) Sym->File->Live = true; else if (auto *Sym = dyn_cast<DefinedImportThunk>(B)) - Sym->WrappedSym->File->Live = true; + Sym->WrappedSym->File->Live = Sym->WrappedSym->File->ThunkLive = true; }; // Add GC root chunks. diff --git a/COFF/MarkLive.h b/COFF/MarkLive.h new file mode 100644 index 000000000000..5b652dd48196 --- /dev/null +++ b/COFF/MarkLive.h @@ -0,0 +1,24 @@ +//===- MarkLive.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COFF_MARKLIVE_H +#define LLD_COFF_MARKLIVE_H + +#include "lld/Common/LLVM.h" +#include "llvm/ADT/ArrayRef.h" + +namespace lld { +namespace coff { + +void markLive(ArrayRef<Chunk *> Chunks); + +} // namespace coff +} // namespace lld + +#endif // LLD_COFF_MARKLIVE_H diff --git a/COFF/MinGW.cpp b/COFF/MinGW.cpp index b7a47165640d..2ca00587331f 100644 --- a/COFF/MinGW.cpp +++ b/COFF/MinGW.cpp @@ -138,7 +138,7 @@ void coff::writeDefFile(StringRef Name) { << "@" << E.Ordinal; if (auto *Def = dyn_cast_or_null<Defined>(E.Sym)) { if (Def && Def->getChunk() && - !(Def->getChunk()->getPermissions() & IMAGE_SCN_MEM_EXECUTE)) + !(Def->getChunk()->getOutputCharacteristics() & IMAGE_SCN_MEM_EXECUTE)) OS << " DATA"; } OS << "\n"; diff --git a/COFF/Options.td b/COFF/Options.td index 7d4cdba14f75..871bad8bd655 100644 --- a/COFF/Options.td +++ b/COFF/Options.td @@ -20,6 +20,10 @@ def align : P<"align", "Section alignment">; def aligncomm : P<"aligncomm", "Set common symbol alignment">; def alternatename : P<"alternatename", "Define weak alias">; def base : P<"base", "Base address of the program">; +def color_diagnostics: Flag<["--"], "color-diagnostics">, + HelpText<"Use colors in diagnostics">; +def color_diagnostics_eq: Joined<["--"], "color-diagnostics=">, + HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">; def defaultlib : P<"defaultlib", "Add the library to the list of input files">; def delayload : P<"delayload", "Delay loaded DLL name">; def entry : P<"entry", "Name of entry point symbol">; @@ -28,9 +32,12 @@ def errorlimit : P<"errorlimit", def export : P<"export", "Export a function">; // No help text because /failifmismatch is not intended to be used by the user. def failifmismatch : P<"failifmismatch", "">; +def guard : P<"guard", "Control flow guard">; def heap : P<"heap", "Size of the heap">; def ignore : P<"ignore", "Specify warning codes to ignore">; def implib : P<"implib", "Import library name">; +def lib : F<"lib">, + HelpText<"Act like lib.exe; must be first argument if present">; def libpath : P<"libpath", "Additional library search path">; def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">; @@ -42,12 +49,18 @@ def merge : P<"merge", "Combine sections">; def mllvm : P<"mllvm", "Options to pass to LLVM">; def nodefaultlib : P<"nodefaultlib", "Remove a default library">; def opt : P<"opt", "Control optimizations">; +def order : P<"order", "Put functions in order">; def out : P<"out", "Path to file to write output">; +def natvis : P<"natvis", "Path to natvis file to embed in the PDB">; +def no_color_diagnostics: F<"no-color-diagnostics">, + HelpText<"Do not use colors in diagnostics">; def pdb : P<"pdb", "PDB file path">; +def pdbaltpath : P<"pdbaltpath", "PDB file path to embed in the image">; def section : P<"section", "Specify section attributes">; def stack : P<"stack", "Size of the stack">; def stub : P<"stub", "Specify DOS stub file">; def subsystem : P<"subsystem", "Specify subsystem">; +def timestamp : P<"timestamp", "Specify the PE header timestamp">; def version : P<"version", "Specify a version number in the PE header">; def wholearchive_file : P<"wholearchive", "Include all object files from this archive">; @@ -72,12 +85,14 @@ def deffile : Joined<["/", "-"], "def:">, HelpText<"Use module-definition file">; def debug : F<"debug">, HelpText<"Embed a symbol table in the image">; +def debug_full : F<"debug:full">, Alias<debug>; def debugtype : P<"debugtype", "Debug Info Options">; def dll : F<"dll">, HelpText<"Create a DLL">; def driver : P<"driver", "Generate a Windows NT Kernel Mode Driver">; def nodefaultlib_all : F<"nodefaultlib">; def noentry : F<"noentry">; def profile : F<"profile">; +def repro : F<"Brepro">, HelpText<"Use a hash of the executable as the PE header timestamp">; def swaprun_cd : F<"swaprun:cd">; def swaprun_net : F<"swaprun:net">; def verbose : F<"verbose">; @@ -102,6 +117,12 @@ defm fixed : B<"fixed", "Disable base relocations", defm highentropyva : B<"highentropyva", "Enable 64-bit ASLR (default on 64-bit)", "Disable 64-bit ASLR">; +defm incremental : B<"incremental", + "Keep original import library if contents are unchanged", + "Overwrite import library even if contents are unchanged">; +defm integritycheck : B<"integritycheck", + "Set FORCE_INTEGRITY bit in PE header", + "No effect (default)">; defm largeaddressaware : B<"largeaddressaware", "Enable large addresses (default on 64-bit)", "Disable large addresses (default on 32-bit)">; @@ -120,10 +141,14 @@ def help_q : Flag<["/?", "-?"], "">, Alias<help>; // LLD extensions def debug_ghash : F<"debug:ghash">; def debug_dwarf : F<"debug:dwarf">; +def debug_symtab : F<"debug:symtab">; def export_all_symbols : F<"export-all-symbols">; +def kill_at : F<"kill-at">; def lldmingw : F<"lldmingw">; def msvclto : F<"msvclto">; def output_def : Joined<["/", "-"], "output-def:">; +def pdb_source_path : P<"pdbsourcepath", + "Base path used to make relative source file path absolute in PDB">; def rsp_quoting : Joined<["--"], "rsp-quoting=">, HelpText<"Quoting style for response files, 'windows' (default) or 'posix'">; def dash_dash_version : Flag<["--"], "version">, @@ -132,6 +157,7 @@ def dash_dash_version : Flag<["--"], "version">, // Flags for debugging def lldmap : F<"lldmap">; def lldmap_file : Joined<["/", "-"], "lldmap:">; +def show_timing : F<"time">; //============================================================================== // The flags below do nothing. They are defined only for link.exe compatibility. @@ -146,8 +172,6 @@ multiclass QB<string name> { def functionpadmin : F<"functionpadmin">; def ignoreidl : F<"ignoreidl">; -def incremental : F<"incremental">; -def no_incremental : F<"incremental:no">; def nologo : F<"nologo">; def throwingnew : F<"throwingnew">; def editandcontinue : F<"editandcontinue">; @@ -157,8 +181,6 @@ def delay : QF<"delay">; def errorreport : QF<"errorreport">; def idlout : QF<"idlout">; def maxilksize : QF<"maxilksize">; -def natvis : QF<"natvis">; -def pdbaltpath : QF<"pdbaltpath">; def tlbid : QF<"tlbid">; def tlbout : QF<"tlbout">; def verbose_all : QF<"verbose">; diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index 91a9a01db569..766bf3f6b456 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -15,7 +15,7 @@ #include "Symbols.h" #include "Writer.h" #include "lld/Common/ErrorHandler.h" -#include "llvm/DebugInfo/CodeView/CVDebugRecord.h" +#include "lld/Common/Timer.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" @@ -45,8 +45,10 @@ #include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h" #include "llvm/DebugInfo/PDB/PDB.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/CVDebugRecord.h" #include "llvm/Support/BinaryByteStream.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/JamCRC.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" @@ -61,6 +63,15 @@ using llvm::object::coff_section; static ExitOnError ExitOnErr; +static Timer TotalPdbLinkTimer("PDB Emission (Cumulative)", Timer::root()); + +static Timer AddObjectsTimer("Add Objects", TotalPdbLinkTimer); +static Timer TypeMergingTimer("Type Merging", AddObjectsTimer); +static Timer SymbolMergingTimer("Symbol Merging", AddObjectsTimer); +static Timer GlobalsLayoutTimer("Globals Stream Layout", TotalPdbLinkTimer); +static Timer TpiStreamLayoutTimer("TPI Stream Layout", TotalPdbLinkTimer); +static Timer DiskCommitTimer("Commit to Disk", TotalPdbLinkTimer); + namespace { /// Map from type index and item index in a type server PDB to the /// corresponding index in the destination PDB. @@ -74,11 +85,19 @@ class PDBLinker { public: PDBLinker(SymbolTable *Symtab) : Alloc(), Symtab(Symtab), Builder(Alloc), TypeTable(Alloc), - IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) {} + IDTable(Alloc), GlobalTypeTable(Alloc), GlobalIDTable(Alloc) { + // This isn't strictly necessary, but link.exe usually puts an empty string + // as the first "valid" string in the string table, so we do the same in + // order to maintain as much byte-for-byte compatibility as possible. + PDBStrTab.insert(""); + } /// Emit the basic PDB structure: initial streams, headers, etc. void initialize(const llvm::codeview::DebugInfo &BuildId); + /// Add natvis files specified on the command line. + void addNatvisFiles(); + /// Link CodeView from each object file in the symbol table into the PDB. void addObjectsToPDB(); @@ -96,18 +115,16 @@ public: /// If the object does not use a type server PDB (compiled with /Z7), we merge /// all the type and item records from the .debug$S stream and fill in the /// caller-provided ObjectIndexMap. - const CVIndexMap &mergeDebugT(ObjFile *File, CVIndexMap &ObjectIndexMap); + Expected<const CVIndexMap&> mergeDebugT(ObjFile *File, + CVIndexMap &ObjectIndexMap); - const CVIndexMap &maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS); + Expected<const CVIndexMap&> maybeMergeTypeServerPDB(ObjFile *File, + TypeServer2Record &TS); /// Add the section map and section contributions to the PDB. void addSections(ArrayRef<OutputSection *> OutputSections, ArrayRef<uint8_t> SectionTable); - void addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule, - OutputSection *OS, Chunk *C); - /// Write the PDB to disk. void commit(); @@ -136,10 +153,19 @@ private: llvm::SmallString<128> NativePath; + /// A list of other PDBs which are loaded during the linking process and which + /// we need to keep around since the linking operation may reference pointers + /// inside of these PDBs. + llvm::SmallVector<std::unique_ptr<pdb::NativeSession>, 2> LoadedPDBs; + std::vector<pdb::SecMapEntry> SectionMap; /// Type index mappings of type server PDBs that we've loaded so far. std::map<GUID, CVIndexMap> TypeServerIndexMappings; + + /// List of TypeServer PDBs which cannot be loaded. + /// Cached to prevent repeated load attempts. + std::set<GUID> MissingTypeServerPDBs; }; } @@ -179,8 +205,8 @@ static bool canUseDebugH(ArrayRef<uint8_t> DebugH) { DebugH = DebugH.drop_front(sizeof(object::debug_h_header)); return Header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC && Header->Version == 0 && - Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1) && - (DebugH.size() % 20 == 0); + Header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) && + (DebugH.size() % 8 == 0); } static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *File) { @@ -230,8 +256,10 @@ maybeReadTypeServerRecord(CVTypeArray &Types) { return std::move(TS); } -const CVIndexMap &PDBLinker::mergeDebugT(ObjFile *File, - CVIndexMap &ObjectIndexMap) { +Expected<const CVIndexMap&> PDBLinker::mergeDebugT(ObjFile *File, + CVIndexMap &ObjectIndexMap) { + ScopedTimer T(TypeMergingTimer); + ArrayRef<uint8_t> Data = getDebugSection(File, ".debug$T"); if (Data.empty()) return ObjectIndexMap; @@ -304,11 +332,19 @@ tryToLoadPDB(const GUID &GuidFromObj, StringRef TSPath) { return std::move(NS); } -const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, - TypeServer2Record &TS) { - // First, check if we already loaded a PDB with this GUID. Return the type +Expected<const CVIndexMap&> PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, + TypeServer2Record &TS) { + const GUID& TSId = TS.getGuid(); + StringRef TSPath = TS.getName(); + + // First, check if the PDB has previously failed to load. + if (MissingTypeServerPDBs.count(TSId)) + return make_error<pdb::GenericError>( + pdb::generic_error_code::type_server_not_found, TSPath); + + // Second, check if we already loaded a PDB with this GUID. Return the type // index mapping if we have it. - auto Insertion = TypeServerIndexMappings.insert({TS.getGuid(), CVIndexMap()}); + auto Insertion = TypeServerIndexMappings.insert({TSId, CVIndexMap()}); CVIndexMap &IndexMap = Insertion.first->second; if (!Insertion.second) return IndexMap; @@ -319,23 +355,32 @@ const CVIndexMap &PDBLinker::maybeMergeTypeServerPDB(ObjFile *File, // Check for a PDB at: // 1. The given file path // 2. Next to the object file or archive file - auto ExpectedSession = tryToLoadPDB(TS.getGuid(), TS.getName()); + auto ExpectedSession = tryToLoadPDB(TSId, TSPath); if (!ExpectedSession) { consumeError(ExpectedSession.takeError()); StringRef LocalPath = !File->ParentName.empty() ? File->ParentName : File->getName(); SmallString<128> Path = sys::path::parent_path(LocalPath); sys::path::append( - Path, sys::path::filename(TS.getName(), sys::path::Style::windows)); - ExpectedSession = tryToLoadPDB(TS.getGuid(), Path); + Path, sys::path::filename(TSPath, sys::path::Style::windows)); + ExpectedSession = tryToLoadPDB(TSId, Path); + } + if (auto E = ExpectedSession.takeError()) { + TypeServerIndexMappings.erase(TSId); + MissingTypeServerPDBs.emplace(TSId); + return std::move(E); } - if (auto E = ExpectedSession.takeError()) - fatal("Type server PDB was not found: " + toString(std::move(E))); - auto ExpectedTpi = (*ExpectedSession)->getPDBFile().getPDBTpiStream(); + pdb::NativeSession *Session = ExpectedSession->get(); + + // Keep a strong reference to this PDB, so that it's safe to hold pointers + // into the file. + LoadedPDBs.push_back(std::move(*ExpectedSession)); + + auto ExpectedTpi = Session->getPDBFile().getPDBTpiStream(); if (auto E = ExpectedTpi.takeError()) fatal("Type server does not have TPI stream: " + toString(std::move(E))); - auto ExpectedIpi = (*ExpectedSession)->getPDBFile().getPDBIpiStream(); + auto ExpectedIpi = Session->getPDBFile().getPDBIpiStream(); if (auto E = ExpectedIpi.takeError()) fatal("Type server does not have TPI stream: " + toString(std::move(E))); @@ -412,6 +457,38 @@ static void remapTypesInSymbolRecord(ObjFile *File, SymbolKind SymKind, } } +static void +recordStringTableReferenceAtOffset(MutableArrayRef<uint8_t> Contents, + uint32_t Offset, + std::vector<ulittle32_t *> &StrTableRefs) { + Contents = + Contents.drop_front(Offset).take_front(sizeof(support::ulittle32_t)); + ulittle32_t *Index = reinterpret_cast<ulittle32_t *>(Contents.data()); + StrTableRefs.push_back(Index); +} + +static void +recordStringTableReferences(SymbolKind Kind, MutableArrayRef<uint8_t> Contents, + std::vector<ulittle32_t *> &StrTableRefs) { + // For now we only handle S_FILESTATIC, but we may need the same logic for + // S_DEFRANGE and S_DEFRANGE_SUBFIELD. However, I cannot seem to generate any + // PDBs that contain these types of records, so because of the uncertainty + // they are omitted here until we can prove that it's necessary. + switch (Kind) { + case SymbolKind::S_FILESTATIC: + // FileStaticSym::ModFileOffset + recordStringTableReferenceAtOffset(Contents, 4, StrTableRefs); + break; + case SymbolKind::S_DEFRANGE: + case SymbolKind::S_DEFRANGE_SUBFIELD: + log("Not fixing up string table reference in S_DEFRANGE / " + "S_DEFRANGE_SUBFIELD record"); + break; + default: + break; + } +} + static SymbolKind symbolKind(ArrayRef<uint8_t> RecordData) { const RecordPrefix *Prefix = reinterpret_cast<const RecordPrefix *>(RecordData.data()); @@ -628,53 +705,65 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjFile *File, pdb::GSIStreamBuilder &GsiBuilder, const CVIndexMap &IndexMap, TypeCollection &IDTable, + std::vector<ulittle32_t *> &StringTableRefs, BinaryStreamRef SymData) { // FIXME: Improve error recovery by warning and skipping records when // possible. - CVSymbolArray Syms; - BinaryStreamReader Reader(SymData); - ExitOnErr(Reader.readArray(Syms, Reader.getLength())); + ArrayRef<uint8_t> SymsBuffer; + cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer)); SmallVector<SymbolScope, 4> Scopes; - for (CVSymbol Sym : Syms) { - // Discover type index references in the record. Skip it if we don't know - // where they are. - SmallVector<TiReference, 32> TypeRefs; - if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { - log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind())); - continue; - } - - // Copy the symbol record so we can mutate it. - MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc); - - // Re-map all the type index references. - MutableArrayRef<uint8_t> Contents = - NewData.drop_front(sizeof(RecordPrefix)); - remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs); - // An object file may have S_xxx_ID symbols, but these get converted to - // "real" symbols in a PDB. - translateIdSymbols(NewData, IDTable); - - SymbolKind NewKind = symbolKind(NewData); - - // Fill in "Parent" and "End" fields by maintaining a stack of scopes. - CVSymbol NewSym(NewKind, NewData); - if (symbolOpensScope(NewKind)) - scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym); - else if (symbolEndsScope(NewKind)) - scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); - - // Add the symbol to the globals stream if necessary. Do this before adding - // the symbol to the module since we may need to get the next symbol offset, - // and writing to the module's symbol stream will update that offset. - if (symbolGoesInGlobalsStream(NewSym)) - addGlobalSymbol(GsiBuilder, *File, NewSym); + auto EC = forEachCodeViewRecord<CVSymbol>( + SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error { + // Discover type index references in the record. Skip it if we don't + // know where they are. + SmallVector<TiReference, 32> TypeRefs; + if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) { + log("ignoring unknown symbol record with kind 0x" + + utohexstr(Sym.kind())); + return Error::success(); + } - // Add the symbol to the module. - if (symbolGoesInModuleStream(NewSym)) - File->ModuleDBI->addSymbol(NewSym); - } + // Copy the symbol record so we can mutate it. + MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc); + + // Re-map all the type index references. + MutableArrayRef<uint8_t> Contents = + NewData.drop_front(sizeof(RecordPrefix)); + remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, + TypeRefs); + + // An object file may have S_xxx_ID symbols, but these get converted to + // "real" symbols in a PDB. + translateIdSymbols(NewData, IDTable); + + // If this record refers to an offset in the object file's string table, + // add that item to the global PDB string table and re-write the index. + recordStringTableReferences(Sym.kind(), Contents, StringTableRefs); + + SymbolKind NewKind = symbolKind(NewData); + + // Fill in "Parent" and "End" fields by maintaining a stack of scopes. + CVSymbol NewSym(NewKind, NewData); + if (symbolOpensScope(NewKind)) + scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), + NewSym); + else if (symbolEndsScope(NewKind)) + scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); + + // Add the symbol to the globals stream if necessary. Do this before + // adding the symbol to the module since we may need to get the next + // symbol offset, and writing to the module's symbol stream will update + // that offset. + if (symbolGoesInGlobalsStream(NewSym)) + addGlobalSymbol(GsiBuilder, *File, NewSym); + + // Add the symbol to the module. + if (symbolGoesInModuleStream(NewSym)) + File->ModuleDBI->addSymbol(NewSym); + return Error::success(); + }); + cantFail(std::move(EC)); } // Allocate memory for a .debug$S section and relocate it. @@ -688,6 +777,32 @@ static ArrayRef<uint8_t> relocateDebugChunk(BumpPtrAllocator &Alloc, ".debug$S"); } +static pdb::SectionContrib createSectionContrib(const Chunk *C, uint32_t Modi) { + OutputSection *OS = C->getOutputSection(); + pdb::SectionContrib SC; + memset(&SC, 0, sizeof(SC)); + SC.ISect = OS->SectionIndex; + SC.Off = C->getRVA() - OS->getRVA(); + SC.Size = C->getSize(); + if (auto *SecChunk = dyn_cast<SectionChunk>(C)) { + SC.Characteristics = SecChunk->Header->Characteristics; + SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); + ArrayRef<uint8_t> Contents = SecChunk->getContents(); + JamCRC CRC(0); + ArrayRef<char> CharContents = makeArrayRef( + reinterpret_cast<const char *>(Contents.data()), Contents.size()); + CRC.update(CharContents); + SC.DataCrc = CRC.getCRC(); + } else { + SC.Characteristics = OS->Header.Characteristics; + // FIXME: When we start creating DBI for import libraries, use those here. + SC.Imod = Modi; + } + SC.RelocCrc = 0; // FIXME + + return SC; +} + void PDBLinker::addObjFile(ObjFile *File) { // Add a module descriptor for every object file. We need to put an absolute // path to the object into the PDB. If this is a plain object, we make its @@ -702,14 +817,39 @@ void PDBLinker::addObjFile(ObjFile *File) { File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); + auto Chunks = File->getChunks(); + uint32_t Modi = File->ModuleDBI->getModuleIndex(); + for (Chunk *C : Chunks) { + auto *SecChunk = dyn_cast<SectionChunk>(C); + if (!SecChunk || !SecChunk->isLive()) + continue; + pdb::SectionContrib SC = createSectionContrib(SecChunk, Modi); + File->ModuleDBI->setFirstSectionContrib(SC); + break; + } + // Before we can process symbol substreams from .debug$S, we need to process // type information, file checksums, and the string table. Add type info to // the PDB first, so that we can get the map from object file type and item // indices to PDB type and item indices. CVIndexMap ObjectIndexMap; - const CVIndexMap &IndexMap = mergeDebugT(File, ObjectIndexMap); + auto IndexMapResult = mergeDebugT(File, ObjectIndexMap); + + // If the .debug$T sections fail to merge, assume there is no debug info. + if (!IndexMapResult) { + warn("Type server PDB for " + Name + " is invalid, ignoring debug info. " + + toString(IndexMapResult.takeError())); + return; + } + + const CVIndexMap &IndexMap = *IndexMapResult; + + ScopedTimer T(SymbolMergingTimer); // Now do all live .debug$S sections. + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + std::vector<ulittle32_t *> StringTableReferences; for (SectionChunk *DebugChunk : File->getDebugChunks()) { if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") continue; @@ -723,14 +863,17 @@ void PDBLinker::addObjFile(ObjFile *File) { BinaryStreamReader Reader(RelocatedDebugContents, support::little); ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); - DebugStringTableSubsectionRef CVStrTab; - DebugChecksumsSubsectionRef Checksums; for (const DebugSubsectionRecord &SS : Subsections) { switch (SS.kind()) { - case DebugSubsectionKind::StringTable: + case DebugSubsectionKind::StringTable: { + assert(!CVStrTab.valid() && + "Encountered multiple string table subsections!"); ExitOnErr(CVStrTab.initialize(SS.getRecordData())); break; + } case DebugSubsectionKind::FileChecksums: + assert(!Checksums.valid() && + "Encountered multiple checksum subsections!"); ExitOnErr(Checksums.initialize(SS.getRecordData())); break; case DebugSubsectionKind::Lines: @@ -741,10 +884,12 @@ void PDBLinker::addObjFile(ObjFile *File) { case DebugSubsectionKind::Symbols: if (Config->DebugGHashes) { mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - GlobalIDTable, SS.getRecordData()); + GlobalIDTable, StringTableReferences, + SS.getRecordData()); } else { mergeSymbolRecords(Alloc, File, Builder.getGsiBuilder(), IndexMap, - IDTable, SS.getRecordData()); + IDTable, StringTableReferences, + SS.getRecordData()); } break; default: @@ -752,25 +897,55 @@ void PDBLinker::addObjFile(ObjFile *File) { break; } } + } + + // We should have seen all debug subsections across the entire object file now + // which means that if a StringTable subsection and Checksums subsection were + // present, now is the time to handle them. + if (!CVStrTab.valid()) { + if (Checksums.valid()) + fatal(".debug$S sections with a checksums subsection must also contain a " + "string table subsection"); + + if (!StringTableReferences.empty()) + warn("No StringTable subsection was encountered, but there are string " + "table references"); + return; + } + + // Rewrite each string table reference based on the value that the string + // assumes in the final PDB. + for (ulittle32_t *Ref : StringTableReferences) { + auto ExpectedString = CVStrTab.getString(*Ref); + if (!ExpectedString) { + warn("Invalid string table reference"); + consumeError(ExpectedString.takeError()); + continue; + } - if (Checksums.valid()) { - // Make a new file checksum table that refers to offsets in the PDB-wide - // string table. Generally the string table subsection appears after the - // checksum table, so we have to do this after looping over all the - // subsections. - if (!CVStrTab.valid()) - fatal(".debug$S sections must have both a string table subsection " - "and a checksum subsection table or neither"); - auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab); - for (FileChecksumEntry &FC : Checksums) { - StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); - ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, - FileName)); - NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); - } - File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); + *Ref = PDBStrTab.insert(*ExpectedString); + } + + // Make a new file checksum table that refers to offsets in the PDB-wide + // string table. Generally the string table subsection appears after the + // checksum table, so we have to do this after looping over all the + // subsections. + auto NewChecksums = make_unique<DebugChecksumsSubsection>(PDBStrTab); + for (FileChecksumEntry &FC : Checksums) { + SmallString<128> FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); + if (!sys::path::is_absolute(FileName) && + !Config->PDBSourcePath.empty()) { + SmallString<128> AbsoluteFileName = Config->PDBSourcePath; + sys::path::append(AbsoluteFileName, FileName); + sys::path::native(AbsoluteFileName); + sys::path::remove_dots(AbsoluteFileName, /*remove_dot_dots=*/true); + FileName = std::move(AbsoluteFileName); } + ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile(*File->ModuleDBI, + FileName)); + NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); } + File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); } static PublicSym32 createPublic(Defined *Def) { @@ -793,12 +968,15 @@ static PublicSym32 createPublic(Defined *Def) { // Add all object files to the PDB. Merge .debug$T sections into IpiData and // TpiData. void PDBLinker::addObjectsToPDB() { + ScopedTimer T1(AddObjectsTimer); for (ObjFile *File : ObjFile::Instances) addObjFile(File); Builder.getStringTableBuilder().setStrings(PDBStrTab); + T1.stop(); // Construct TPI and IPI stream contents. + ScopedTimer T2(TpiStreamLayoutTimer); if (Config->DebugGHashes) { addTypeInfo(Builder.getTpiBuilder(), GlobalTypeTable); addTypeInfo(Builder.getIpiBuilder(), GlobalIDTable); @@ -806,7 +984,9 @@ void PDBLinker::addObjectsToPDB() { addTypeInfo(Builder.getTpiBuilder(), TypeTable); addTypeInfo(Builder.getIpiBuilder(), IDTable); } + T2.stop(); + ScopedTimer T3(GlobalsLayoutTimer); // Compute the public and global symbols. auto &GsiBuilder = Builder.getGsiBuilder(); std::vector<PublicSym32> Publics; @@ -828,6 +1008,35 @@ void PDBLinker::addObjectsToPDB() { } } +void PDBLinker::addNatvisFiles() { + for (StringRef File : Config->NatvisFiles) { + ErrorOr<std::unique_ptr<MemoryBuffer>> DataOrErr = + MemoryBuffer::getFile(File); + if (!DataOrErr) { + warn("Cannot open input file: " + File); + continue; + } + Builder.addInjectedSource(File, std::move(*DataOrErr)); + } +} + +static codeview::CPUType toCodeViewMachine(COFF::MachineTypes Machine) { + switch (Machine) { + case COFF::IMAGE_FILE_MACHINE_AMD64: + return codeview::CPUType::X64; + case COFF::IMAGE_FILE_MACHINE_ARM: + return codeview::CPUType::ARM7; + case COFF::IMAGE_FILE_MACHINE_ARM64: + return codeview::CPUType::ARM64; + case COFF::IMAGE_FILE_MACHINE_ARMNT: + return codeview::CPUType::ARMNT; + case COFF::IMAGE_FILE_MACHINE_I386: + return codeview::CPUType::Intel80386; + default: + llvm_unreachable("Unsupported CPU Type"); + } +} + static void addCommonLinkerModuleSymbols(StringRef Path, pdb::DbiModuleDescriptorBuilder &Mod, BumpPtrAllocator &Allocator) { @@ -838,7 +1047,7 @@ static void addCommonLinkerModuleSymbols(StringRef Path, ONS.Name = "* Linker *"; ONS.Signature = 0; - CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386; + CS.Machine = toCodeViewMachine(Config->Machine); // Interestingly, if we set the string to 0.0.0.0, then when trying to view // local variables WinDbg emits an error that private symbols are not present. // By setting this to a valid MSVC linker version string, local variables are @@ -889,9 +1098,9 @@ static void addLinkerModuleSectionSymbol(pdb::DbiModuleDescriptorBuilder &Mod, BumpPtrAllocator &Allocator) { SectionSym Sym(SymbolRecordKind::SectionSym); Sym.Alignment = 12; // 2^12 = 4KB - Sym.Characteristics = OS.getCharacteristics(); + Sym.Characteristics = OS.Header.Characteristics; Sym.Length = OS.getVirtualSize(); - Sym.Name = OS.getName(); + Sym.Name = OS.Name; Sym.Rva = OS.getRVA(); Sym.SectionNumber = OS.SectionIndex; Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( @@ -903,10 +1112,15 @@ void coff::createPDB(SymbolTable *Symtab, ArrayRef<OutputSection *> OutputSections, ArrayRef<uint8_t> SectionTable, const llvm::codeview::DebugInfo &BuildId) { + ScopedTimer T1(TotalPdbLinkTimer); PDBLinker PDB(Symtab); + PDB.initialize(BuildId); PDB.addObjectsToPDB(); PDB.addSections(OutputSections, SectionTable); + PDB.addNatvisFiles(); + + ScopedTimer T2(DiskCommitTimer); PDB.commit(); } @@ -920,44 +1134,22 @@ void PDBLinker::initialize(const llvm::codeview::DebugInfo &BuildId) { // Add an Info stream. auto &InfoBuilder = Builder.getInfoBuilder(); - InfoBuilder.setAge(BuildId.PDB70.Age); - GUID uuid; memcpy(&uuid, &BuildId.PDB70.Signature, sizeof(uuid)); + InfoBuilder.setAge(BuildId.PDB70.Age); InfoBuilder.setGuid(uuid); - InfoBuilder.setSignature(time(nullptr)); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); // Add an empty DBI stream. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); DbiBuilder.setAge(BuildId.PDB70.Age); DbiBuilder.setVersionHeader(pdb::PdbDbiV70); - ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); -} - -void PDBLinker::addSectionContrib(pdb::DbiModuleDescriptorBuilder &LinkerModule, - OutputSection *OS, Chunk *C) { - pdb::SectionContrib SC; - memset(&SC, 0, sizeof(SC)); - SC.ISect = OS->SectionIndex; - SC.Off = C->getRVA() - OS->getRVA(); - SC.Size = C->getSize(); - if (auto *SecChunk = dyn_cast<SectionChunk>(C)) { - SC.Characteristics = SecChunk->Header->Characteristics; - SC.Imod = SecChunk->File->ModuleDBI->getModuleIndex(); - ArrayRef<uint8_t> Contents = SecChunk->getContents(); - JamCRC CRC(0); - ArrayRef<char> CharContents = makeArrayRef( - reinterpret_cast<const char *>(Contents.data()), Contents.size()); - CRC.update(CharContents); - SC.DataCrc = CRC.getCRC(); - } else { - SC.Characteristics = OS->getCharacteristics(); - // FIXME: When we start creating DBI for import libraries, use those here. - SC.Imod = LinkerModule.getModuleIndex(); - } - SC.RelocCrc = 0; // FIXME - Builder.getDbiBuilder().addSectionContrib(SC); + DbiBuilder.setMachineType(Config->Machine); + // Technically we are not link.exe 14.11, but there are known cases where + // debugging tools on Windows expect Microsoft-specific version numbers or + // they fail to work at all. Since we know we produce PDBs that are + // compatible with LINK 14.11, we set that version number here. + DbiBuilder.setBuildNumber(14, 11); } void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections, @@ -975,8 +1167,11 @@ void PDBLinker::addSections(ArrayRef<OutputSection *> OutputSections, // Add section contributions. They must be ordered by ascending RVA. for (OutputSection *OS : OutputSections) { addLinkerModuleSectionSymbol(LinkerModule, *OS, Alloc); - for (Chunk *C : OS->getChunks()) - addSectionContrib(LinkerModule, OS, C); + for (Chunk *C : OS->getChunks()) { + pdb::SectionContrib SC = + createSectionContrib(C, LinkerModule.getModuleIndex()); + Builder.getDbiBuilder().addSectionContrib(SC); + } } // Add Section Map stream. @@ -995,3 +1190,145 @@ void PDBLinker::commit() { // Write to a file. ExitOnErr(Builder.commit(Config->PDBPath)); } + +static Expected<StringRef> +getFileName(const DebugStringTableSubsectionRef &Strings, + const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) { + auto Iter = Checksums.getArray().at(FileID); + if (Iter == Checksums.getArray().end()) + return make_error<CodeViewError>(cv_error_code::no_records); + uint32_t Offset = Iter->FileNameOffset; + return Strings.getString(Offset); +} + +static uint32_t getSecrelReloc() { + switch (Config->Machine) { + case AMD64: + return COFF::IMAGE_REL_AMD64_SECREL; + case I386: + return COFF::IMAGE_REL_I386_SECREL; + case ARMNT: + return COFF::IMAGE_REL_ARM_SECREL; + case ARM64: + return COFF::IMAGE_REL_ARM64_SECREL; + default: + llvm_unreachable("unknown machine type"); + } +} + +// Try to find a line table for the given offset Addr into the given chunk C. +// If a line table was found, the line table, the string and checksum tables +// that are used to interpret the line table, and the offset of Addr in the line +// table are stored in the output arguments. Returns whether a line table was +// found. +static bool findLineTable(const SectionChunk *C, uint32_t Addr, + DebugStringTableSubsectionRef &CVStrTab, + DebugChecksumsSubsectionRef &Checksums, + DebugLinesSubsectionRef &Lines, + uint32_t &OffsetInLinetable) { + ExitOnError ExitOnErr; + uint32_t SecrelReloc = getSecrelReloc(); + + for (SectionChunk *DbgC : C->File->getDebugChunks()) { + if (DbgC->getSectionName() != ".debug$S") + continue; + + // Build a mapping of SECREL relocations in DbgC that refer to C. + DenseMap<uint32_t, uint32_t> Secrels; + for (const coff_relocation &R : DbgC->Relocs) { + if (R.Type != SecrelReloc) + continue; + + if (auto *S = dyn_cast_or_null<DefinedRegular>( + C->File->getSymbols()[R.SymbolTableIndex])) + if (S->getChunk() == C) + Secrels[R.VirtualAddress] = S->getValue(); + } + + ArrayRef<uint8_t> Contents = + consumeDebugMagic(DbgC->getContents(), ".debug$S"); + DebugSubsectionArray Subsections; + BinaryStreamReader Reader(Contents, support::little); + ExitOnErr(Reader.readArray(Subsections, Contents.size())); + + for (const DebugSubsectionRecord &SS : Subsections) { + switch (SS.kind()) { + case DebugSubsectionKind::StringTable: { + assert(!CVStrTab.valid() && + "Encountered multiple string table subsections!"); + ExitOnErr(CVStrTab.initialize(SS.getRecordData())); + break; + } + case DebugSubsectionKind::FileChecksums: + assert(!Checksums.valid() && + "Encountered multiple checksum subsections!"); + ExitOnErr(Checksums.initialize(SS.getRecordData())); + break; + case DebugSubsectionKind::Lines: { + ArrayRef<uint8_t> Bytes; + auto Ref = SS.getRecordData(); + ExitOnErr(Ref.readLongestContiguousChunk(0, Bytes)); + size_t OffsetInDbgC = Bytes.data() - DbgC->getContents().data(); + + // Check whether this line table refers to C. + auto I = Secrels.find(OffsetInDbgC); + if (I == Secrels.end()) + break; + + // Check whether this line table covers Addr in C. + DebugLinesSubsectionRef LinesTmp; + ExitOnErr(LinesTmp.initialize(BinaryStreamReader(Ref))); + uint32_t OffsetInC = I->second + LinesTmp.header()->RelocOffset; + if (Addr < OffsetInC || Addr >= OffsetInC + LinesTmp.header()->CodeSize) + break; + + assert(!Lines.header() && + "Encountered multiple line tables for function!"); + ExitOnErr(Lines.initialize(BinaryStreamReader(Ref))); + OffsetInLinetable = Addr - OffsetInC; + break; + } + default: + break; + } + + if (CVStrTab.valid() && Checksums.valid() && Lines.header()) + return true; + } + } + + return false; +} + +// Use CodeView line tables to resolve a file and line number for the given +// offset into the given chunk and return them, or {"", 0} if a line table was +// not found. +std::pair<StringRef, uint32_t> coff::getFileLine(const SectionChunk *C, + uint32_t Addr) { + ExitOnError ExitOnErr; + + DebugStringTableSubsectionRef CVStrTab; + DebugChecksumsSubsectionRef Checksums; + DebugLinesSubsectionRef Lines; + uint32_t OffsetInLinetable; + + if (!findLineTable(C, Addr, CVStrTab, Checksums, Lines, OffsetInLinetable)) + return {"", 0}; + + uint32_t NameIndex; + uint32_t LineNumber; + for (LineColumnEntry &Entry : Lines) { + for (const LineNumberEntry &LN : Entry.LineNumbers) { + if (LN.Offset > OffsetInLinetable) { + StringRef Filename = + ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex)); + return {Filename, LineNumber}; + } + LineInfo LI(LN.Flags); + NameIndex = Entry.NameIndex; + LineNumber = LI.getStartLine(); + } + } + StringRef Filename = ExitOnErr(getFileName(CVStrTab, Checksums, NameIndex)); + return {Filename, LineNumber}; +} diff --git a/COFF/PDB.h b/COFF/PDB.h index defd7d236790..a98d129a633b 100644 --- a/COFF/PDB.h +++ b/COFF/PDB.h @@ -22,12 +22,16 @@ union DebugInfo; namespace lld { namespace coff { class OutputSection; +class SectionChunk; class SymbolTable; void createPDB(SymbolTable *Symtab, llvm::ArrayRef<OutputSection *> OutputSections, llvm::ArrayRef<uint8_t> SectionTable, const llvm::codeview::DebugInfo &BuildId); + +std::pair<llvm::StringRef, uint32_t> getFileLine(const SectionChunk *C, + uint32_t Addr); } } diff --git a/COFF/Strings.cpp b/COFF/Strings.cpp deleted file mode 100644 index 89b9c5186fd1..000000000000 --- a/COFF/Strings.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//===- Strings.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Strings.h" -#include <mutex> - -#if defined(_MSC_VER) -#include <Windows.h> -#include <DbgHelp.h> -#pragma comment(lib, "dbghelp.lib") -#endif - -using namespace lld; -using namespace lld::coff; -using namespace llvm; - -Optional<std::string> coff::demangleMSVC(StringRef S) { -#if defined(_MSC_VER) - // UnDecorateSymbolName is not thread-safe, so we need a mutex. - static std::mutex Mu; - std::lock_guard<std::mutex> Lock(Mu); - - char Buf[4096]; - if (S.startswith("?")) - if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) - return std::string(Buf, Len); -#endif - return None; -} diff --git a/COFF/SymbolTable.cpp b/COFF/SymbolTable.cpp index df76679535cb..b286d865caaf 100644 --- a/COFF/SymbolTable.cpp +++ b/COFF/SymbolTable.cpp @@ -11,9 +11,11 @@ #include "Config.h" #include "Driver.h" #include "LTO.h" +#include "PDB.h" #include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Timer.h" #include "llvm/IR/LLVMContext.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -24,6 +26,8 @@ using namespace llvm; namespace lld { namespace coff { +static Timer LTOTimer("LTO", Timer::root()); + SymbolTable *Symtab; void SymbolTable::addFile(InputFile *File) { @@ -34,8 +38,9 @@ void SymbolTable::addFile(InputFile *File) { if (Config->Machine == IMAGE_FILE_MACHINE_UNKNOWN) { Config->Machine = MT; } else if (MT != IMAGE_FILE_MACHINE_UNKNOWN && Config->Machine != MT) { - fatal(toString(File) + ": machine type " + machineToStr(MT) + + error(toString(File) + ": machine type " + machineToStr(MT) + " conflicts with " + machineToStr(Config->Machine)); + return; } if (auto *F = dyn_cast<ObjFile>(File)) { @@ -61,6 +66,66 @@ static void errorOrWarn(const Twine &S) { error(S); } +// Returns the name of the symbol in SC whose value is <= Addr that is closest +// to Addr. This is generally the name of the global variable or function whose +// definition contains Addr. +static StringRef getSymbolName(SectionChunk *SC, uint32_t Addr) { + DefinedRegular *Candidate = nullptr; + + for (Symbol *S : SC->File->getSymbols()) { + auto *D = dyn_cast_or_null<DefinedRegular>(S); + if (!D || D->getChunk() != SC || D->getValue() > Addr || + (Candidate && D->getValue() < Candidate->getValue())) + continue; + + Candidate = D; + } + + if (!Candidate) + return ""; + return Candidate->getName(); +} + +static std::string getSymbolLocations(ObjFile *File, uint32_t SymIndex) { + struct Location { + StringRef SymName; + std::pair<StringRef, uint32_t> FileLine; + }; + std::vector<Location> Locations; + + for (Chunk *C : File->getChunks()) { + auto *SC = dyn_cast<SectionChunk>(C); + if (!SC) + continue; + for (const coff_relocation &R : SC->Relocs) { + if (R.SymbolTableIndex != SymIndex) + continue; + std::pair<StringRef, uint32_t> FileLine = + getFileLine(SC, R.VirtualAddress); + StringRef SymName = getSymbolName(SC, R.VirtualAddress); + if (!FileLine.first.empty() || !SymName.empty()) + Locations.push_back({SymName, FileLine}); + } + } + + if (Locations.empty()) + return "\n>>> referenced by " + toString(File) + "\n"; + + std::string Out; + llvm::raw_string_ostream OS(Out); + for (Location Loc : Locations) { + OS << "\n>>> referenced by "; + if (!Loc.FileLine.first.empty()) + OS << Loc.FileLine.first << ":" << Loc.FileLine.second + << "\n>>> "; + OS << toString(File); + if (!Loc.SymName.empty()) + OS << ":(" << Loc.SymName << ')'; + } + OS << '\n'; + return OS.str(); +} + void SymbolTable::reportRemainingUndefines() { SmallPtrSet<Symbol *, 8> Undefs; DenseMap<Symbol *, Symbol *> LocalImports; @@ -120,20 +185,23 @@ void SymbolTable::reportRemainingUndefines() { if (Config->WarnLocallyDefinedImported) if (Symbol *Imp = LocalImports.lookup(B)) warn("<root>: locally defined symbol imported: " + Imp->getName() + - " (defined in " + toString(Imp->getFile()) + ")"); + " (defined in " + toString(Imp->getFile()) + ") [LNK4217]"); } for (ObjFile *File : ObjFile::Instances) { + size_t SymIndex = (size_t)-1; for (Symbol *Sym : File->getSymbols()) { + ++SymIndex; if (!Sym) continue; if (Undefs.count(Sym)) - errorOrWarn(toString(File) + ": undefined symbol: " + Sym->getName()); + errorOrWarn("undefined symbol: " + Sym->getName() + + getSymbolLocations(File, SymIndex)); if (Config->WarnLocallyDefinedImported) if (Symbol *Imp = LocalImports.lookup(Sym)) warn(toString(File) + ": locally defined symbol imported: " + Imp->getName() + " (defined in " + toString(Imp->getFile()) + - ")"); + ") [LNK4217]"); } } } @@ -142,7 +210,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; if (Sym) return {Sym, false}; - Sym = (Symbol *)make<SymbolUnion>(); + Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); Sym->IsUsedInRegularObj = false; Sym->PendingArchiveLoad = false; return {Sym, true}; @@ -274,30 +342,29 @@ Symbol *SymbolTable::addCommon(InputFile *F, StringRef N, uint64_t Size, return S; } -DefinedImportData *SymbolTable::addImportData(StringRef N, ImportFile *F) { +Symbol *SymbolTable::addImportData(StringRef N, ImportFile *F) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(N); S->IsUsedInRegularObj = true; if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) { replaceSymbol<DefinedImportData>(S, N, F); - return cast<DefinedImportData>(S); + return S; } reportDuplicate(S, F); return nullptr; } -DefinedImportThunk *SymbolTable::addImportThunk(StringRef Name, - DefinedImportData *ID, - uint16_t Machine) { +Symbol *SymbolTable::addImportThunk(StringRef Name, DefinedImportData *ID, + uint16_t Machine) { Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); S->IsUsedInRegularObj = true; if (WasInserted || isa<Undefined>(S) || isa<Lazy>(S)) { replaceSymbol<DefinedImportThunk>(S, Name, ID, Machine); - return cast<DefinedImportThunk>(S); + return S; } reportDuplicate(S, ID->File); @@ -314,10 +381,7 @@ std::vector<Chunk *> SymbolTable::getChunks() { } Symbol *SymbolTable::find(StringRef Name) { - auto It = SymMap.find(CachedHashStringRef(Name)); - if (It == SymMap.end()) - return nullptr; - return It->second; + return SymMap.lookup(CachedHashStringRef(Name)); } Symbol *SymbolTable::findUnderscore(StringRef Name) { @@ -384,6 +448,8 @@ std::vector<StringRef> SymbolTable::compileBitcodeFiles() { void SymbolTable::addCombinedLTOObjects() { if (BitcodeFile::Instances.empty()) return; + + ScopedTimer T(LTOTimer); for (StringRef Object : compileBitcodeFiles()) { auto *Obj = make<ObjFile>(MemoryBufferRef(Object, "lto.tmp")); Obj->parse(); diff --git a/COFF/SymbolTable.h b/COFF/SymbolTable.h index 55481e6475bb..30cb1a5410c3 100644 --- a/COFF/SymbolTable.h +++ b/COFF/SymbolTable.h @@ -92,9 +92,9 @@ public: Symbol *addCommon(InputFile *F, StringRef N, uint64_t Size, const llvm::object::coff_symbol_generic *S = nullptr, CommonChunk *C = nullptr); - DefinedImportData *addImportData(StringRef N, ImportFile *F); - DefinedImportThunk *addImportThunk(StringRef Name, DefinedImportData *S, - uint16_t Machine); + Symbol *addImportData(StringRef N, ImportFile *F); + Symbol *addImportThunk(StringRef Name, DefinedImportData *S, + uint16_t Machine); void reportDuplicate(Symbol *Existing, InputFile *NewFile); diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp index 4c5ab48c7565..7c8b7d5e8fc5 100644 --- a/COFF/Symbols.cpp +++ b/COFF/Symbols.cpp @@ -9,9 +9,9 @@ #include "Symbols.h" #include "InputFiles.h" -#include "Strings.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -21,7 +21,7 @@ using namespace llvm::object; // Returns a symbol name for an error message. std::string lld::toString(coff::Symbol &B) { - if (Optional<std::string> S = coff::demangleMSVC(B.getName())) + if (Optional<std::string> S = lld::demangleMSVC(B.getName())) return ("\"" + *S + "\" (" + B.getName() + ")").str(); return B.getName(); } @@ -58,7 +58,7 @@ bool Symbol::isLive() const { if (auto *Imp = dyn_cast<DefinedImportData>(this)) return Imp->File->Live; if (auto *Imp = dyn_cast<DefinedImportThunk>(this)) - return Imp->WrappedSym->File->Live; + return Imp->WrappedSym->File->ThunkLive; // Assume any other kind of symbol is live. return true; } @@ -71,7 +71,7 @@ COFFSymbolRef DefinedCOFF::getCOFFSymbol() { return COFFSymbolRef(reinterpret_cast<const coff_symbol32 *>(Sym)); } -uint16_t DefinedAbsolute::OutputSectionIndex = 0; +uint16_t DefinedAbsolute::NumOutputSections; static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { if (Machine == AMD64) diff --git a/COFF/Symbols.h b/COFF/Symbols.h index d8a030705e27..783965adbd9a 100644 --- a/COFF/Symbols.h +++ b/COFF/Symbols.h @@ -213,11 +213,10 @@ public: uint64_t getRVA() { return VA - Config->ImageBase; } void setVA(uint64_t V) { VA = V; } - // The sentinel absolute symbol section index. Section index relocations - // against absolute symbols resolve to this 16 bit number, and it is the - // largest valid section index plus one. This is written by the Writer. - static uint16_t OutputSectionIndex; - uint16_t getSecIdx() { return OutputSectionIndex; } + // Section index relocations against absolute symbols resolve to + // this 16 bit number, and it is the largest valid section index + // plus one. This variable keeps it. + static uint16_t NumOutputSections; private: uint64_t VA; @@ -416,6 +415,8 @@ union SymbolUnion { template <typename T, typename... ArgT> void replaceSymbol(Symbol *S, ArgT &&... Arg) { + static_assert(std::is_trivially_destructible<T>(), + "Symbol types must be trivially destructible"); static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small"); static_assert(alignof(T) <= alignof(SymbolUnion), "SymbolUnion not aligned enough"); diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index 584f0621bea3..d17405ec26ab 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -17,6 +17,7 @@ #include "Symbols.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Timer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" @@ -25,7 +26,9 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Parallel.h" +#include "llvm/Support/Path.h" #include "llvm/Support/RandomNumberGenerator.h" +#include "llvm/Support/xxhash.h" #include <algorithm> #include <cstdio> #include <map> @@ -40,8 +43,40 @@ using namespace llvm::support::endian; using namespace lld; using namespace lld::coff; +/* To re-generate DOSProgram: +$ cat > /tmp/DOSProgram.asm +org 0 + ; Copy cs to ds. + push cs + pop ds + ; Point ds:dx at the $-terminated string. + mov dx, str + ; Int 21/AH=09h: Write string to standard output. + mov ah, 0x9 + int 0x21 + ; Int 21/AH=4Ch: Exit with return code (in AL). + mov ax, 0x4C01 + int 0x21 +str: + db 'This program cannot be run in DOS mode.$' +align 8, db 0 +$ nasm -fbin /tmp/DOSProgram.asm -o /tmp/DOSProgram.bin +$ xxd -i /tmp/DOSProgram.bin +*/ +static unsigned char DOSProgram[] = { + 0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd, 0x21, 0xb8, 0x01, 0x4c, + 0xcd, 0x21, 0x54, 0x68, 0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, + 0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x20, 0x62, 0x65, + 0x20, 0x72, 0x75, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20, + 0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x24, 0x00, 0x00 +}; +static_assert(sizeof(DOSProgram) % 8 == 0, + "DOSProgram size must be multiple of 8"); + static const int SectorSize = 512; -static const int DOSStubSize = 64; +static const int DOSStubSize = sizeof(dos_header) + sizeof(DOSProgram); +static_assert(DOSStubSize % 8 == 0, "DOSStub size must be multiple of 8"); + static const int NumberfOfDataDirectory = 16; namespace { @@ -69,24 +104,25 @@ public: uint64_t Offs = OS->getFileOff() + (Record->getRVA() - OS->getRVA()); D->PointerToRawData = Offs; + TimeDateStamps.push_back(&D->TimeDateStamp); ++D; } } + void setTimeDateStamp(uint32_t TimeDateStamp) { + for (support::ulittle32_t *TDS : TimeDateStamps) + *TDS = TimeDateStamp; + } + private: + mutable std::vector<support::ulittle32_t *> TimeDateStamps; const std::vector<Chunk *> &Records; }; class CVDebugRecordChunk : public Chunk { public: - CVDebugRecordChunk() { - PDBAbsPath = Config->PDBPath; - if (!PDBAbsPath.empty()) - llvm::sys::fs::make_absolute(PDBAbsPath); - } - size_t getSize() const override { - return sizeof(codeview::DebugInfo) + PDBAbsPath.size() + 1; + return sizeof(codeview::DebugInfo) + Config->PDBAltPath.size() + 1; } void writeTo(uint8_t *B) const override { @@ -96,12 +132,11 @@ public: // variable sized field (PDB Path) char *P = reinterpret_cast<char *>(B + OutputSectionOff + sizeof(*BuildId)); - if (!PDBAbsPath.empty()) - memcpy(P, PDBAbsPath.data(), PDBAbsPath.size()); - P[PDBAbsPath.size()] = '\0'; + if (!Config->PDBAltPath.empty()) + memcpy(P, Config->PDBAltPath.data(), Config->PDBAltPath.size()); + P[Config->PDBAltPath.size()] = '\0'; } - SmallString<128> PDBAbsPath; mutable codeview::DebugInfo *BuildId = nullptr; }; @@ -116,12 +151,19 @@ private: void createMiscChunks(); void createImportTables(); void createExportTable(); + void mergeSections(); void assignAddresses(); void removeEmptySections(); void createSymbolAndStringTable(); void openFile(StringRef OutputPath); template <typename PEHeaderTy> void writeHeader(); - void createSEHTable(OutputSection *RData); + void createSEHTable(); + void createGuardCFTables(); + void markSymbolsForRVATable(ObjFile *File, + ArrayRef<SectionChunk *> SymIdxChunks, + SymbolRVASet &TableSymbols); + void maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, + StringRef CountSym); void setSectionPermissions(); void writeSections(); void writeBuildId(); @@ -131,9 +173,8 @@ private: size_t addEntryToStringTable(StringRef Str); OutputSection *findSection(StringRef Name); - OutputSection *createSection(StringRef Name); - void addBaserels(OutputSection *Dest); - void addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V); + void addBaserels(); + void addBaserelBlocks(std::vector<Baserel> &V); uint32_t getSizeOfInitializedData(); std::map<StringRef, std::vector<DefinedImportData *>> binImports(); @@ -145,9 +186,9 @@ private: IdataContents Idata; DelayLoadContents DelayIdata; EdataContents Edata; - SEHTableChunk *SEHTable = nullptr; + bool SetNoSEHCharacteristic = false; - Chunk *DebugDirectory = nullptr; + DebugDirectoryChunk *DebugDirectory = nullptr; std::vector<Chunk *> DebugRecords; CVDebugRecordChunk *BuildId = nullptr; Optional<codeview::DebugInfo> PreviousBuildId; @@ -157,50 +198,55 @@ private: uint32_t PointerToSymbolTable = 0; uint64_t SizeOfImage; uint64_t SizeOfHeaders; + + OutputSection *TextSec; + OutputSection *RdataSec; + OutputSection *BuildidSec; + OutputSection *DataSec; + OutputSection *PdataSec; + OutputSection *IdataSec; + OutputSection *EdataSec; + OutputSection *DidatSec; + OutputSection *RsrcSec; + OutputSection *RelocSec; + + // The first and last .pdata sections in the output file. + // + // We need to keep track of the location of .pdata in whichever section it + // gets merged into so that we can sort its contents and emit a correct data + // directory entry for the exception table. This is also the case for some + // other sections (such as .edata) but because the contents of those sections + // are entirely linker-generated we can keep track of their locations using + // the chunks that the linker creates. All .pdata chunks come from input + // files, so we need to keep track of them separately. + Chunk *FirstPdata = nullptr; + Chunk *LastPdata; }; } // anonymous namespace namespace lld { namespace coff { -void writeResult() { Writer().run(); } - -void OutputSection::setRVA(uint64_t RVA) { - Header.VirtualAddress = RVA; - for (Chunk *C : Chunks) - C->setRVA(C->getRVA() + RVA); -} +static Timer CodeLayoutTimer("Code Layout", Timer::root()); +static Timer DiskCommitTimer("Commit Output File", Timer::root()); -void OutputSection::setFileOffset(uint64_t Off) { - // If a section has no actual data (i.e. BSS section), we want to - // set 0 to its PointerToRawData. Otherwise the output is rejected - // by the loader. - if (Header.SizeOfRawData == 0) - return; - Header.PointerToRawData = Off; -} +void writeResult() { Writer().run(); } void OutputSection::addChunk(Chunk *C) { Chunks.push_back(C); C->setOutputSection(this); - uint64_t Off = Header.VirtualSize; - Off = alignTo(Off, C->Alignment); - C->setRVA(Off); - C->OutputSectionOff = Off; - Off += C->getSize(); - if (Off > UINT32_MAX) - error("section larger than 4 GiB: " + Name); - Header.VirtualSize = Off; - if (C->hasData()) - Header.SizeOfRawData = alignTo(Off, SectorSize); } -void OutputSection::addPermissions(uint32_t C) { - Header.Characteristics |= C & PermMask; +void OutputSection::setPermissions(uint32_t C) { + Header.Characteristics &= ~PermMask; + Header.Characteristics |= C; } -void OutputSection::setPermissions(uint32_t C) { - Header.Characteristics = C & PermMask; +void OutputSection::merge(OutputSection *Other) { + for (Chunk *C : Other->Chunks) + C->setOutputSection(this); + Chunks.insert(Chunks.end(), Other->Chunks.begin(), Other->Chunks.end()); + Other->Chunks.clear(); } // Write the section header to a given buffer. @@ -284,17 +330,22 @@ static Optional<codeview::DebugInfo> loadExistingBuildId(StringRef Path) { // The main function of the writer. void Writer::run() { + ScopedTimer T1(CodeLayoutTimer); + createSections(); createMiscChunks(); createImportTables(); createExportTable(); - if (Config->Relocatable) - createSection(".reloc"); + mergeSections(); assignAddresses(); removeEmptySections(); setSectionPermissions(); createSymbolAndStringTable(); + if (FileSize > UINT32_MAX) + fatal("image size (" + Twine(FileSize) + ") " + + "exceeds maximum allowable size (" + Twine(UINT32_MAX) + ")"); + // We must do this before opening the output file, as it depends on being able // to read the contents of the existing output file. PreviousBuildId = loadExistingBuildId(Config->OutputFile); @@ -308,35 +359,79 @@ void Writer::run() { sortExceptionTable(); writeBuildId(); - if (!Config->PDBPath.empty() && Config->Debug) { + T1.stop(); + if (!Config->PDBPath.empty() && Config->Debug) { assert(BuildId); createPDB(Symtab, OutputSections, SectionTable, *BuildId->BuildId); } writeMapFile(OutputSections); + ScopedTimer T2(DiskCommitTimer); if (auto E = Buffer->commit()) fatal("failed to write the output file: " + toString(std::move(E))); } -static StringRef getOutputSection(StringRef Name) { +static StringRef getOutputSectionName(StringRef Name) { StringRef S = Name.split('$').first; // Treat a later period as a separator for MinGW, for sections like // ".ctors.01234". - S = S.substr(0, S.find('.', 1)); + return S.substr(0, S.find('.', 1)); +} - auto It = Config->Merge.find(S); - if (It == Config->Merge.end()) - return S; - return It->second; +// For /order. +static void sortBySectionOrder(std::vector<Chunk *> &Chunks) { + auto GetPriority = [](const Chunk *C) { + if (auto *Sec = dyn_cast<SectionChunk>(C)) + if (Sec->Sym) + return Config->Order.lookup(Sec->Sym->getName()); + return 0; + }; + + std::stable_sort(Chunks.begin(), Chunks.end(), + [=](const Chunk *A, const Chunk *B) { + return GetPriority(A) < GetPriority(B); + }); } // Create output section objects and add them to OutputSections. void Writer::createSections() { - // First, bin chunks by name. - std::map<StringRef, std::vector<Chunk *>> Map; + // First, create the builtin sections. + const uint32_t DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; + const uint32_t BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; + const uint32_t CODE = IMAGE_SCN_CNT_CODE; + const uint32_t DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; + const uint32_t R = IMAGE_SCN_MEM_READ; + const uint32_t W = IMAGE_SCN_MEM_WRITE; + const uint32_t X = IMAGE_SCN_MEM_EXECUTE; + + SmallDenseMap<std::pair<StringRef, uint32_t>, OutputSection *> Sections; + auto CreateSection = [&](StringRef Name, uint32_t OutChars) { + OutputSection *&Sec = Sections[{Name, OutChars}]; + if (!Sec) { + Sec = make<OutputSection>(Name, OutChars); + OutputSections.push_back(Sec); + } + return Sec; + }; + + // Try to match the section order used by link.exe. + TextSec = CreateSection(".text", CODE | R | X); + CreateSection(".bss", BSS | R | W); + RdataSec = CreateSection(".rdata", DATA | R); + BuildidSec = CreateSection(".buildid", DATA | R); + DataSec = CreateSection(".data", DATA | R | W); + PdataSec = CreateSection(".pdata", DATA | R); + IdataSec = CreateSection(".idata", DATA | R); + EdataSec = CreateSection(".edata", DATA | R); + DidatSec = CreateSection(".didat", DATA | R); + RsrcSec = CreateSection(".rsrc", DATA | R); + RelocSec = CreateSection(".reloc", DATA | DISCARDABLE | R); + + // Then bin chunks by name and output characteristics. + std::map<std::pair<StringRef, uint32_t>, std::vector<Chunk *>> Map; for (Chunk *C : Symtab->getChunks()) { auto *SC = dyn_cast<SectionChunk>(C); if (SC && !SC->isLive()) { @@ -344,42 +439,71 @@ void Writer::createSections() { SC->printDiscardedMessage(); continue; } - Map[C->getSectionName()].push_back(C); + Map[{C->getSectionName(), C->getOutputCharacteristics()}].push_back(C); } + // Process an /order option. + if (!Config->Order.empty()) + for (auto &Pair : Map) + sortBySectionOrder(Pair.second); + // Then create an OutputSection for each section. // '$' and all following characters in input section names are // discarded when determining output section. So, .text$foo // contributes to .text, for example. See PE/COFF spec 3.2. - SmallDenseMap<StringRef, OutputSection *> Sections; for (auto Pair : Map) { - StringRef Name = getOutputSection(Pair.first); - OutputSection *&Sec = Sections[Name]; - if (!Sec) { - Sec = make<OutputSection>(Name); - OutputSections.push_back(Sec); - } + StringRef Name = getOutputSectionName(Pair.first.first); + uint32_t OutChars = Pair.first.second; + + // In link.exe, there is a special case for the I386 target where .CRT + // sections are treated as if they have output characteristics DATA | R if + // their characteristics are DATA | R | W. This implements the same special + // case for all architectures. + if (Name == ".CRT") + OutChars = DATA | R; + + OutputSection *Sec = CreateSection(Name, OutChars); std::vector<Chunk *> &Chunks = Pair.second; - for (Chunk *C : Chunks) { + for (Chunk *C : Chunks) Sec->addChunk(C); - Sec->addPermissions(C->getPermissions()); - } } + + // Finally, move some output sections to the end. + auto SectionOrder = [&](OutputSection *S) { + // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because + // the loader cannot handle holes. Stripping can remove other discardable ones + // than .reloc, which is first of them (created early). + if (S->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) + return 2; + // .rsrc should come at the end of the non-discardable sections because its + // size may change by the Win32 UpdateResources() function, causing + // subsequent sections to move (see https://crbug.com/827082). + if (S == RsrcSec) + return 1; + return 0; + }; + std::stable_sort(OutputSections.begin(), OutputSections.end(), + [&](OutputSection *S, OutputSection *T) { + return SectionOrder(S) < SectionOrder(T); + }); } void Writer::createMiscChunks() { - OutputSection *RData = createSection(".rdata"); + for (auto &P : MergeChunk::Instances) + RdataSec->addChunk(P.second); // Create thunks for locally-dllimported symbols. if (!Symtab->LocalImportChunks.empty()) { for (Chunk *C : Symtab->LocalImportChunks) - RData->addChunk(C); + RdataSec->addChunk(C); } // Create Debug Information Chunks if (Config->Debug) { DebugDirectory = make<DebugDirectoryChunk>(DebugRecords); + OutputSection *DebugInfoSec = Config->MinGW ? BuildidSec : RdataSec; + // Make a CVDebugRecordChunk even when /DEBUG:CV is not specified. We // output a PDB no matter what, and this chunk provides the only means of // allowing a debugger to match a PDB and an executable. So we need it even @@ -388,12 +512,18 @@ void Writer::createMiscChunks() { BuildId = CVChunk; DebugRecords.push_back(CVChunk); - RData->addChunk(DebugDirectory); + DebugInfoSec->addChunk(DebugDirectory); for (Chunk *C : DebugRecords) - RData->addChunk(C); + DebugInfoSec->addChunk(C); } - createSEHTable(RData); + // Create SEH table. x86-only. + if (Config->Machine == I386) + createSEHTable(); + + // Create /guard:cf tables if requested. + if (Config->GuardCF != GuardCFLevel::Off) + createGuardCFTables(); } // Create .idata section for the DLL-imported symbol table. @@ -414,53 +544,49 @@ void Writer::createImportTables() { std::string DLL = StringRef(File->DLLName).lower(); if (Config->DLLOrder.count(DLL) == 0) Config->DLLOrder[DLL] = Config->DLLOrder.size(); - } - OutputSection *Text = createSection(".text"); - for (ImportFile *File : ImportFile::Instances) { - if (!File->Live) - continue; - - if (DefinedImportThunk *Thunk = File->ThunkSym) - Text->addChunk(Thunk->getChunk()); + if (File->ThunkSym) { + if (!isa<DefinedImportThunk>(File->ThunkSym)) + fatal(toString(*File->ThunkSym) + " was replaced"); + DefinedImportThunk *Thunk = cast<DefinedImportThunk>(File->ThunkSym); + if (File->ThunkLive) + TextSec->addChunk(Thunk->getChunk()); + } + if (File->ImpSym && !isa<DefinedImportData>(File->ImpSym)) + fatal(toString(*File->ImpSym) + " was replaced"); + DefinedImportData *ImpSym = cast_or_null<DefinedImportData>(File->ImpSym); if (Config->DelayLoads.count(StringRef(File->DLLName).lower())) { if (!File->ThunkSym) fatal("cannot delay-load " + toString(File) + - " due to import of data: " + toString(*File->ImpSym)); - DelayIdata.add(File->ImpSym); + " due to import of data: " + toString(*ImpSym)); + DelayIdata.add(ImpSym); } else { - Idata.add(File->ImpSym); + Idata.add(ImpSym); } } - if (!Idata.empty()) { - OutputSection *Sec = createSection(".idata"); + if (!Idata.empty()) for (Chunk *C : Idata.getChunks()) - Sec->addChunk(C); - } + IdataSec->addChunk(C); if (!DelayIdata.empty()) { Defined *Helper = cast<Defined>(Config->DelayLoadHelper); DelayIdata.create(Helper); - OutputSection *Sec = createSection(".didat"); for (Chunk *C : DelayIdata.getChunks()) - Sec->addChunk(C); - Sec = createSection(".data"); + DidatSec->addChunk(C); for (Chunk *C : DelayIdata.getDataChunks()) - Sec->addChunk(C); - Sec = createSection(".text"); + DataSec->addChunk(C); for (Chunk *C : DelayIdata.getCodeChunks()) - Sec->addChunk(C); + TextSec->addChunk(C); } } void Writer::createExportTable() { if (Config->Exports.empty()) return; - OutputSection *Sec = createSection(".edata"); for (Chunk *C : Edata.Chunks) - Sec->addChunk(C); + EdataSec->addChunk(C); } // The Windows loader doesn't seem to like empty sections, @@ -484,19 +610,31 @@ size_t Writer::addEntryToStringTable(StringRef Str) { } Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { - // Relative symbols are unrepresentable in a COFF symbol table. - if (isa<DefinedSynthetic>(Def)) - return None; - - // Don't write dead symbols or symbols in codeview sections to the symbol - // table. - if (!Def->isLive()) + coff_symbol16 Sym; + switch (Def->kind()) { + case Symbol::DefinedAbsoluteKind: + Sym.Value = Def->getRVA(); + Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; + break; + case Symbol::DefinedSyntheticKind: + // Relative symbols are unrepresentable in a COFF symbol table. return None; - if (auto *D = dyn_cast<DefinedRegular>(Def)) - if (D->getChunk()->isCodeView()) + default: { + // Don't write symbols that won't be written to the output to the symbol + // table. + Chunk *C = Def->getChunk(); + if (!C) + return None; + OutputSection *OS = C->getOutputSection(); + if (!OS) return None; - coff_symbol16 Sym; + Sym.Value = Def->getRVA() - OS->getRVA(); + Sym.SectionNumber = OS->SectionIndex; + break; + } + } + StringRef Name = Def->getName(); if (Name.size() > COFF::NameSize) { Sym.Name.Offset.Zeroes = 0; @@ -515,46 +653,27 @@ Optional<coff_symbol16> Writer::createSymbol(Defined *Def) { Sym.StorageClass = IMAGE_SYM_CLASS_EXTERNAL; } Sym.NumberOfAuxSymbols = 0; - - switch (Def->kind()) { - case Symbol::DefinedAbsoluteKind: - Sym.Value = Def->getRVA(); - Sym.SectionNumber = IMAGE_SYM_ABSOLUTE; - break; - default: { - uint64_t RVA = Def->getRVA(); - OutputSection *Sec = nullptr; - for (OutputSection *S : OutputSections) { - if (S->getRVA() > RVA) - break; - Sec = S; - } - Sym.Value = RVA - Sec->getRVA(); - Sym.SectionNumber = Sec->SectionIndex; - break; - } - } return Sym; } void Writer::createSymbolAndStringTable() { - // Name field in the section table is 8 byte long. Longer names need - // to be written to the string table. First, construct string table. + // PE/COFF images are limited to 8 byte section names. Longer names can be + // supported by writing a non-standard string table, but this string table is + // not mapped at runtime and the long names will therefore be inaccessible. + // link.exe always truncates section names to 8 bytes, whereas binutils always + // preserves long section names via the string table. LLD adopts a hybrid + // solution where discardable sections have long names preserved and + // non-discardable sections have their names truncated, to ensure that any + // section which is mapped at runtime also has its name mapped at runtime. for (OutputSection *Sec : OutputSections) { - StringRef Name = Sec->getName(); - if (Name.size() <= COFF::NameSize) + if (Sec->Name.size() <= COFF::NameSize) continue; - // If a section isn't discardable (i.e. will be mapped at runtime), - // prefer a truncated section name over a long section name in - // the string table that is unavailable at runtime. This is different from - // what link.exe does, but finding ".eh_fram" instead of "/4" is useful - // to libunwind. - if ((Sec->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0) + if ((Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) == 0) continue; - Sec->setStringTableOff(addEntryToStringTable(Name)); + Sec->setStringTableOff(addEntryToStringTable(Sec->Name)); } - if (Config->DebugDwarf) { + if (Config->DebugDwarf || Config->DebugSymtab) { for (ObjFile *File : ObjFile::Instances) { for (Symbol *B : File->getSymbols()) { auto *D = dyn_cast_or_null<Defined>(B); @@ -571,16 +690,45 @@ void Writer::createSymbolAndStringTable() { if (OutputSymtab.empty() && Strtab.empty()) return; - OutputSection *LastSection = OutputSections.back(); // We position the symbol table to be adjacent to the end of the last section. - uint64_t FileOff = LastSection->getFileOff() + - alignTo(LastSection->getRawSize(), SectorSize); + uint64_t FileOff = FileSize; PointerToSymbolTable = FileOff; FileOff += OutputSymtab.size() * sizeof(coff_symbol16); FileOff += 4 + Strtab.size(); FileSize = alignTo(FileOff, SectorSize); } +void Writer::mergeSections() { + if (!PdataSec->getChunks().empty()) { + FirstPdata = PdataSec->getChunks().front(); + LastPdata = PdataSec->getChunks().back(); + } + + for (auto &P : Config->Merge) { + StringRef ToName = P.second; + if (P.first == ToName) + continue; + StringSet<> Names; + while (1) { + if (!Names.insert(ToName).second) + fatal("/merge: cycle found for section '" + P.first + "'"); + auto I = Config->Merge.find(ToName); + if (I == Config->Merge.end()) + break; + ToName = I->second; + } + OutputSection *From = findSection(P.first); + OutputSection *To = findSection(ToName); + if (!From) + continue; + if (!To) { + From->Name = ToName; + continue; + } + To->merge(From); + } +} + // Visits all sections to assign incremental, non-overlapping RVAs and // file offsets. void Writer::assignAddresses() { @@ -590,35 +738,57 @@ void Writer::assignAddresses() { SizeOfHeaders += Config->is64() ? sizeof(pe32plus_header) : sizeof(pe32_header); SizeOfHeaders = alignTo(SizeOfHeaders, SectorSize); - uint64_t RVA = 0x1000; // The first page is kept unmapped. + uint64_t RVA = PageSize; // The first page is kept unmapped. FileSize = SizeOfHeaders; - // Move DISCARDABLE (or non-memory-mapped) sections to the end of file because - // the loader cannot handle holes. - std::stable_partition( - OutputSections.begin(), OutputSections.end(), [](OutputSection *S) { - return (S->getPermissions() & IMAGE_SCN_MEM_DISCARDABLE) == 0; - }); + for (OutputSection *Sec : OutputSections) { - if (Sec->getName() == ".reloc") - addBaserels(Sec); - Sec->setRVA(RVA); - Sec->setFileOffset(FileSize); - RVA += alignTo(Sec->getVirtualSize(), PageSize); - FileSize += alignTo(Sec->getRawSize(), SectorSize); + if (Sec == RelocSec) + addBaserels(); + uint64_t RawSize = 0, VirtualSize = 0; + Sec->Header.VirtualAddress = RVA; + for (Chunk *C : Sec->getChunks()) { + VirtualSize = alignTo(VirtualSize, C->Alignment); + C->setRVA(RVA + VirtualSize); + C->OutputSectionOff = VirtualSize; + C->finalizeContents(); + VirtualSize += C->getSize(); + if (C->hasData()) + RawSize = alignTo(VirtualSize, SectorSize); + } + if (VirtualSize > UINT32_MAX) + error("section larger than 4 GiB: " + Sec->Name); + Sec->Header.VirtualSize = VirtualSize; + Sec->Header.SizeOfRawData = RawSize; + if (RawSize != 0) + Sec->Header.PointerToRawData = FileSize; + RVA += alignTo(VirtualSize, PageSize); + FileSize += alignTo(RawSize, SectorSize); } SizeOfImage = alignTo(RVA, PageSize); } template <typename PEHeaderTy> void Writer::writeHeader() { - // Write DOS stub + // Write DOS header. For backwards compatibility, the first part of a PE/COFF + // executable consists of an MS-DOS MZ executable. If the executable is run + // under DOS, that program gets run (usually to just print an error message). + // When run under Windows, the loader looks at AddressOfNewExeHeader and uses + // the PE header instead. uint8_t *Buf = Buffer->getBufferStart(); auto *DOS = reinterpret_cast<dos_header *>(Buf); - Buf += DOSStubSize; + Buf += sizeof(dos_header); DOS->Magic[0] = 'M'; DOS->Magic[1] = 'Z'; + DOS->UsedBytesInTheLastPage = DOSStubSize % 512; + DOS->FileSizeInPages = divideCeil(DOSStubSize, 512); + DOS->HeaderSizeInParagraphs = sizeof(dos_header) / 16; + DOS->AddressOfRelocationTable = sizeof(dos_header); DOS->AddressOfNewExeHeader = DOSStubSize; + // Write DOS program. + memcpy(Buf, DOSProgram, sizeof(DOSProgram)); + Buf += sizeof(DOSProgram); + // Write PE magic memcpy(Buf, PEMagic, sizeof(PEMagic)); Buf += sizeof(PEMagic); @@ -688,24 +858,27 @@ template <typename PEHeaderTy> void Writer::writeHeader() { PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NX_COMPAT; if (!Config->AllowIsolation) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_ISOLATION; - if (Config->Machine == I386 && !SEHTable && - !Symtab->findUnderscore("_load_config_used")) + if (Config->GuardCF != GuardCFLevel::Off) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_GUARD_CF; + if (Config->IntegrityCheck) + PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY; + if (SetNoSEHCharacteristic) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_NO_SEH; if (Config->TerminalServerAware) PE->DLLCharacteristics |= IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE; PE->NumberOfRvaAndSize = NumberfOfDataDirectory; - if (OutputSection *Text = findSection(".text")) { - PE->BaseOfCode = Text->getRVA(); - PE->SizeOfCode = Text->getRawSize(); + if (TextSec->getVirtualSize()) { + PE->BaseOfCode = TextSec->getRVA(); + PE->SizeOfCode = TextSec->getRawSize(); } PE->SizeOfInitializedData = getSizeOfInitializedData(); // Write data directory auto *Dir = reinterpret_cast<data_directory *>(Buf); Buf += sizeof(*Dir) * NumberfOfDataDirectory; - if (OutputSection *Sec = findSection(".edata")) { - Dir[EXPORT_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[EXPORT_TABLE].Size = Sec->getVirtualSize(); + if (!Config->Exports.empty()) { + Dir[EXPORT_TABLE].RelativeVirtualAddress = Edata.getRVA(); + Dir[EXPORT_TABLE].Size = Edata.getSize(); } if (!Idata.empty()) { Dir[IMPORT_TABLE].RelativeVirtualAddress = Idata.getDirRVA(); @@ -713,17 +886,18 @@ template <typename PEHeaderTy> void Writer::writeHeader() { Dir[IAT].RelativeVirtualAddress = Idata.getIATRVA(); Dir[IAT].Size = Idata.getIATSize(); } - if (OutputSection *Sec = findSection(".rsrc")) { - Dir[RESOURCE_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[RESOURCE_TABLE].Size = Sec->getVirtualSize(); + if (RsrcSec->getVirtualSize()) { + Dir[RESOURCE_TABLE].RelativeVirtualAddress = RsrcSec->getRVA(); + Dir[RESOURCE_TABLE].Size = RsrcSec->getVirtualSize(); } - if (OutputSection *Sec = findSection(".pdata")) { - Dir[EXCEPTION_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[EXCEPTION_TABLE].Size = Sec->getVirtualSize(); + if (FirstPdata) { + Dir[EXCEPTION_TABLE].RelativeVirtualAddress = FirstPdata->getRVA(); + Dir[EXCEPTION_TABLE].Size = + LastPdata->getRVA() + LastPdata->getSize() - FirstPdata->getRVA(); } - if (OutputSection *Sec = findSection(".reloc")) { - Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = Sec->getRVA(); - Dir[BASE_RELOCATION_TABLE].Size = Sec->getVirtualSize(); + if (RelocSec->getVirtualSize()) { + Dir[BASE_RELOCATION_TABLE].RelativeVirtualAddress = RelocSec->getRVA(); + Dir[BASE_RELOCATION_TABLE].Size = RelocSec->getVirtualSize(); } if (Symbol *Sym = Symtab->findUnderscore("_tls_used")) { if (Defined *B = dyn_cast<Defined>(Sym)) { @@ -792,35 +966,172 @@ void Writer::openFile(StringRef Path) { "failed to open " + Path); } -void Writer::createSEHTable(OutputSection *RData) { - // Create SEH table. x86-only. - if (Config->Machine != I386) - return; - - std::set<Defined *> Handlers; +void Writer::createSEHTable() { + // Set the no SEH characteristic on x86 binaries unless we find exception + // handlers. + SetNoSEHCharacteristic = true; + SymbolRVASet Handlers; for (ObjFile *File : ObjFile::Instances) { - if (!File->SEHCompat) + // FIXME: We should error here instead of earlier unless /safeseh:no was + // passed. + if (!File->hasSafeSEH()) return; - for (uint32_t I : File->SXData) - if (Symbol *B = File->getSymbol(I)) - if (B->isLive()) - Handlers.insert(cast<Defined>(B)); + + markSymbolsForRVATable(File, File->getSXDataChunks(), Handlers); + } + + // Remove the "no SEH" characteristic if all object files were built with + // safeseh, we found some exception handlers, and there is a load config in + // the object. + SetNoSEHCharacteristic = + Handlers.empty() || !Symtab->findUnderscore("_load_config_used"); + + maybeAddRVATable(std::move(Handlers), "__safe_se_handler_table", + "__safe_se_handler_count"); +} + +// Add a symbol to an RVA set. Two symbols may have the same RVA, but an RVA set +// cannot contain duplicates. Therefore, the set is uniqued by Chunk and the +// symbol's offset into that Chunk. +static void addSymbolToRVASet(SymbolRVASet &RVASet, Defined *S) { + Chunk *C = S->getChunk(); + if (auto *SC = dyn_cast<SectionChunk>(C)) + C = SC->Repl; // Look through ICF replacement. + uint32_t Off = S->getRVA() - (C ? C->getRVA() : 0); + RVASet.insert({C, Off}); +} + +// Visit all relocations from all section contributions of this object file and +// mark the relocation target as address-taken. +static void markSymbolsWithRelocations(ObjFile *File, + SymbolRVASet &UsedSymbols) { + for (Chunk *C : File->getChunks()) { + // We only care about live section chunks. Common chunks and other chunks + // don't generally contain relocations. + SectionChunk *SC = dyn_cast<SectionChunk>(C); + if (!SC || !SC->isLive()) + continue; + + // Look for relocations in this section against symbols in executable output + // sections. + for (Symbol *Ref : SC->symbols()) { + // FIXME: Do further testing to see if the relocation type matters, + // especially for 32-bit where taking the address of something usually + // uses an absolute relocation instead of a relative one. + if (auto *D = dyn_cast_or_null<Defined>(Ref)) { + Chunk *RefChunk = D->getChunk(); + OutputSection *OS = RefChunk ? RefChunk->getOutputSection() : nullptr; + if (OS && OS->Header.Characteristics & IMAGE_SCN_MEM_EXECUTE) + addSymbolToRVASet(UsedSymbols, D); + } + } + } +} + +// Create the guard function id table. This is a table of RVAs of all +// address-taken functions. It is sorted and uniqued, just like the safe SEH +// table. +void Writer::createGuardCFTables() { + SymbolRVASet AddressTakenSyms; + SymbolRVASet LongJmpTargets; + for (ObjFile *File : ObjFile::Instances) { + // If the object was compiled with /guard:cf, the address taken symbols + // are in .gfids$y sections, and the longjmp targets are in .gljmp$y + // sections. If the object was not compiled with /guard:cf, we assume there + // were no setjmp targets, and that all code symbols with relocations are + // possibly address-taken. + if (File->hasGuardCF()) { + markSymbolsForRVATable(File, File->getGuardFidChunks(), AddressTakenSyms); + markSymbolsForRVATable(File, File->getGuardLJmpChunks(), LongJmpTargets); + } else { + markSymbolsWithRelocations(File, AddressTakenSyms); + } + } + + // Mark the image entry as address-taken. + if (Config->Entry) + addSymbolToRVASet(AddressTakenSyms, cast<Defined>(Config->Entry)); + + // Ensure sections referenced in the gfid table are 16-byte aligned. + for (const ChunkAndOffset &C : AddressTakenSyms) + if (C.InputChunk->Alignment < 16) + C.InputChunk->Alignment = 16; + + maybeAddRVATable(std::move(AddressTakenSyms), "__guard_fids_table", + "__guard_fids_count"); + + // Add the longjmp target table unless the user told us not to. + if (Config->GuardCF == GuardCFLevel::Full) + maybeAddRVATable(std::move(LongJmpTargets), "__guard_longjmp_table", + "__guard_longjmp_count"); + + // Set __guard_flags, which will be used in the load config to indicate that + // /guard:cf was enabled. + uint32_t GuardFlags = uint32_t(coff_guard_flags::CFInstrumented) | + uint32_t(coff_guard_flags::HasFidTable); + if (Config->GuardCF == GuardCFLevel::Full) + GuardFlags |= uint32_t(coff_guard_flags::HasLongJmpTable); + Symbol *FlagSym = Symtab->findUnderscore("__guard_flags"); + cast<DefinedAbsolute>(FlagSym)->setVA(GuardFlags); +} + +// Take a list of input sections containing symbol table indices and add those +// symbols to an RVA table. The challenge is that symbol RVAs are not known and +// depend on the table size, so we can't directly build a set of integers. +void Writer::markSymbolsForRVATable(ObjFile *File, + ArrayRef<SectionChunk *> SymIdxChunks, + SymbolRVASet &TableSymbols) { + for (SectionChunk *C : SymIdxChunks) { + // Skip sections discarded by linker GC. This comes up when a .gfids section + // is associated with something like a vtable and the vtable is discarded. + // In this case, the associated gfids section is discarded, and we don't + // mark the virtual member functions as address-taken by the vtable. + if (!C->isLive()) + continue; + + // Validate that the contents look like symbol table indices. + ArrayRef<uint8_t> Data = C->getContents(); + if (Data.size() % 4 != 0) { + warn("ignoring " + C->getSectionName() + + " symbol table index section in object " + toString(File)); + continue; + } + + // Read each symbol table index and check if that symbol was included in the + // final link. If so, add it to the table symbol set. + ArrayRef<ulittle32_t> SymIndices( + reinterpret_cast<const ulittle32_t *>(Data.data()), Data.size() / 4); + ArrayRef<Symbol *> ObjSymbols = File->getSymbols(); + for (uint32_t SymIndex : SymIndices) { + if (SymIndex >= ObjSymbols.size()) { + warn("ignoring invalid symbol table index in section " + + C->getSectionName() + " in object " + toString(File)); + continue; + } + if (Symbol *S = ObjSymbols[SymIndex]) { + if (S->isLive()) + addSymbolToRVASet(TableSymbols, cast<Defined>(S)); + } + } } +} - if (Handlers.empty()) +// Replace the absolute table symbol with a synthetic symbol pointing to +// TableChunk so that we can emit base relocations for it and resolve section +// relative relocations. +void Writer::maybeAddRVATable(SymbolRVASet TableSymbols, StringRef TableSym, + StringRef CountSym) { + if (TableSymbols.empty()) return; - SEHTable = make<SEHTableChunk>(Handlers); - RData->addChunk(SEHTable); + RVATableChunk *TableChunk = make<RVATableChunk>(std::move(TableSymbols)); + RdataSec->addChunk(TableChunk); - // Replace the absolute table symbol with a synthetic symbol pointing to the - // SEHTable chunk so that we can emit base relocations for it and resolve - // section relative relocations. - Symbol *T = Symtab->find("___safe_se_handler_table"); - Symbol *C = Symtab->find("___safe_se_handler_count"); - replaceSymbol<DefinedSynthetic>(T, T->getName(), SEHTable); - cast<DefinedAbsolute>(C)->setVA(SEHTable->getSize() / 4); + Symbol *T = Symtab->findUnderscore(TableSym); + Symbol *C = Symtab->findUnderscore(CountSym); + replaceSymbol<DefinedSynthetic>(T, T->getName(), TableChunk); + cast<DefinedAbsolute>(C)->setVA(TableChunk->getSize() / 4); } // Handles /section options to allow users to overwrite @@ -829,16 +1140,17 @@ void Writer::setSectionPermissions() { for (auto &P : Config->Section) { StringRef Name = P.first; uint32_t Perm = P.second; - if (auto *Sec = findSection(Name)) - Sec->setPermissions(Perm); + for (OutputSection *Sec : OutputSections) + if (Sec->Name == Name) + Sec->setPermissions(Perm); } } // Write section contents to a mmap'ed file. void Writer::writeSections() { - // Record the section index that should be used when resolving a section - // relocation against an absolute symbol. - DefinedAbsolute::OutputSectionIndex = OutputSections.size() + 1; + // Record the number of sections to apply section index relocations + // against absolute symbols. See applySecIdx in Chunks.cpp.. + DefinedAbsolute::NumOutputSections = OutputSections.size(); uint8_t *Buf = Buffer->getBufferStart(); for (OutputSection *Sec : OutputSections) { @@ -846,7 +1158,7 @@ void Writer::writeSections() { // Fill gaps between functions in .text with INT3 instructions // instead of leaving as NUL bytes (which can be interpreted as // ADD instructions). - if (Sec->getPermissions() & IMAGE_SCN_CNT_CODE) + if (Sec->Header.Characteristics & IMAGE_SCN_CNT_CODE) memset(SecBuf, 0xCC, Sec->getRawSize()); for_each(parallel::par, Sec->getChunks().begin(), Sec->getChunks().end(), [&](Chunk *C) { C->writeTo(SecBuf); }); @@ -854,32 +1166,65 @@ void Writer::writeSections() { } void Writer::writeBuildId() { - // If we're not writing a build id (e.g. because /debug is not specified), - // then just return; - if (!Config->Debug) - return; + // There are two important parts to the build ID. + // 1) If building with debug info, the COFF debug directory contains a + // timestamp as well as a Guid and Age of the PDB. + // 2) In all cases, the PE COFF file header also contains a timestamp. + // For reproducibility, instead of a timestamp we want to use a hash of the + // binary, however when building with debug info the hash needs to take into + // account the debug info, since it's possible to add blank lines to a file + // which causes the debug info to change but not the generated code. + // + // To handle this, we first set the Guid and Age in the debug directory (but + // only if we're doing a debug build). Then, we hash the binary (thus causing + // the hash to change if only the debug info changes, since the Age will be + // different). Finally, we write that hash into the debug directory (if + // present) as well as the COFF file header (always). + if (Config->Debug) { + assert(BuildId && "BuildId is not set!"); + if (PreviousBuildId.hasValue()) { + *BuildId->BuildId = *PreviousBuildId; + BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; + } else { + BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; + BuildId->BuildId->PDB70.Age = 1; + llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); + } + } - assert(BuildId && "BuildId is not set!"); + // At this point the only fields in the COFF file which remain unset are the + // "timestamp" in the COFF file header, and the ones in the coff debug + // directory. Now we can hash the file and write that hash to the various + // timestamp fields in the file. + StringRef OutputFileData( + reinterpret_cast<const char *>(Buffer->getBufferStart()), + Buffer->getBufferSize()); - if (PreviousBuildId.hasValue()) { - *BuildId->BuildId = *PreviousBuildId; - BuildId->BuildId->PDB70.Age = BuildId->BuildId->PDB70.Age + 1; - return; - } + uint32_t Timestamp = Config->Timestamp; + if (Config->Repro) + Timestamp = static_cast<uint32_t>(xxHash64(OutputFileData)); + + if (DebugDirectory) + DebugDirectory->setTimeDateStamp(Timestamp); - BuildId->BuildId->Signature.CVSignature = OMF::Signature::PDB70; - BuildId->BuildId->PDB70.Age = 1; - llvm::getRandomBytes(BuildId->BuildId->PDB70.Signature, 16); + uint8_t *Buf = Buffer->getBufferStart(); + Buf += DOSStubSize + sizeof(PEMagic); + object::coff_file_header *CoffHeader = + reinterpret_cast<coff_file_header *>(Buf); + CoffHeader->TimeDateStamp = Timestamp; } // Sort .pdata section contents according to PE/COFF spec 5.5. void Writer::sortExceptionTable() { - OutputSection *Sec = findSection(".pdata"); - if (!Sec) + if (!FirstPdata) return; // We assume .pdata contains function table entries only. - uint8_t *Begin = Buffer->getBufferStart() + Sec->getFileOff(); - uint8_t *End = Begin + Sec->getVirtualSize(); + auto BufAddr = [&](Chunk *C) { + return Buffer->getBufferStart() + C->getOutputSection()->getFileOff() + + C->getRVA() - C->getOutputSection()->getRVA(); + }; + uint8_t *Begin = BufAddr(FirstPdata); + uint8_t *End = BufAddr(LastPdata) + LastPdata->getSize(); if (Config->Machine == AMD64) { struct Entry { ulittle32_t Begin, End, Unwind; }; sort(parallel::par, (Entry *)Begin, (Entry *)End, @@ -897,7 +1242,7 @@ void Writer::sortExceptionTable() { OutputSection *Writer::findSection(StringRef Name) { for (OutputSection *Sec : OutputSections) - if (Sec->getName() == Name) + if (Sec->Name == Name) return Sec; return nullptr; } @@ -905,55 +1250,31 @@ OutputSection *Writer::findSection(StringRef Name) { uint32_t Writer::getSizeOfInitializedData() { uint32_t Res = 0; for (OutputSection *S : OutputSections) - if (S->getPermissions() & IMAGE_SCN_CNT_INITIALIZED_DATA) + if (S->Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) Res += S->getRawSize(); return Res; } -// Returns an existing section or create a new one if not found. -OutputSection *Writer::createSection(StringRef Name) { - if (auto *Sec = findSection(Name)) - return Sec; - const auto DATA = IMAGE_SCN_CNT_INITIALIZED_DATA; - const auto BSS = IMAGE_SCN_CNT_UNINITIALIZED_DATA; - const auto CODE = IMAGE_SCN_CNT_CODE; - const auto DISCARDABLE = IMAGE_SCN_MEM_DISCARDABLE; - const auto R = IMAGE_SCN_MEM_READ; - const auto W = IMAGE_SCN_MEM_WRITE; - const auto X = IMAGE_SCN_MEM_EXECUTE; - uint32_t Perms = StringSwitch<uint32_t>(Name) - .Case(".bss", BSS | R | W) - .Case(".data", DATA | R | W) - .Cases(".didat", ".edata", ".idata", ".rdata", DATA | R) - .Case(".reloc", DATA | DISCARDABLE | R) - .Case(".text", CODE | R | X) - .Default(0); - if (!Perms) - llvm_unreachable("unknown section name"); - auto Sec = make<OutputSection>(Name); - Sec->addPermissions(Perms); - OutputSections.push_back(Sec); - return Sec; -} - -// Dest is .reloc section. Add contents to that section. -void Writer::addBaserels(OutputSection *Dest) { +// Add base relocations to .reloc section. +void Writer::addBaserels() { + if (!Config->Relocatable) + return; std::vector<Baserel> V; for (OutputSection *Sec : OutputSections) { - if (Sec == Dest) + if (Sec->Header.Characteristics & IMAGE_SCN_MEM_DISCARDABLE) continue; // Collect all locations for base relocations. for (Chunk *C : Sec->getChunks()) C->getBaserels(&V); // Add the addresses to .reloc section. if (!V.empty()) - addBaserelBlocks(Dest, V); + addBaserelBlocks(V); V.clear(); } } // Add addresses to .reloc section. Note that addresses are grouped by page. -void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) { +void Writer::addBaserelBlocks(std::vector<Baserel> &V) { const uint32_t Mask = ~uint32_t(PageSize - 1); uint32_t Page = V[0].RVA & Mask; size_t I = 0, J = 1; @@ -961,11 +1282,11 @@ void Writer::addBaserelBlocks(OutputSection *Dest, std::vector<Baserel> &V) { uint32_t P = V[J].RVA & Mask; if (P == Page) continue; - Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); + RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); I = J; Page = P; } if (I == J) return; - Dest->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); + RelocSec->addChunk(make<BaserelChunk>(Page, &V[I], &V[0] + J)); } diff --git a/COFF/Writer.h b/COFF/Writer.h index 21be1be6e92a..d37276cb6d91 100644 --- a/COFF/Writer.h +++ b/COFF/Writer.h @@ -13,6 +13,7 @@ #include "Chunks.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" +#include <chrono> #include <cstdint> #include <vector> @@ -29,16 +30,14 @@ void writeResult(); // non-overlapping file offsets and RVAs. class OutputSection { public: - OutputSection(llvm::StringRef N) : Name(N), Header({}) {} - void setRVA(uint64_t); - void setFileOffset(uint64_t); + OutputSection(llvm::StringRef N, uint32_t Chars) : Name(N) { + Header.Characteristics = Chars; + } void addChunk(Chunk *C); - llvm::StringRef getName() { return Name; } + void merge(OutputSection *Other); ArrayRef<Chunk *> getChunks() { return Chunks; } void addPermissions(uint32_t C); void setPermissions(uint32_t C); - uint32_t getPermissions() { return Header.Characteristics & PermMask; } - uint32_t getCharacteristics() { return Header.Characteristics; } uint64_t getRVA() { return Header.VirtualAddress; } uint64_t getFileOff() { return Header.PointerToRawData; } void writeHeaderTo(uint8_t *Buf); @@ -60,9 +59,10 @@ public: // N.B. The section index is one based. uint32_t SectionIndex = 0; -private: llvm::StringRef Name; - llvm::object::coff_section Header; + llvm::object::coff_section Header = {}; + +private: uint32_t StringTableOff = 0; std::vector<Chunk *> Chunks; }; diff --git a/Common/Args.cpp b/Common/Args.cpp index 680cf5bd0a6e..ff77bfcc3b76 100644 --- a/Common/Args.cpp +++ b/Common/Args.cpp @@ -18,13 +18,17 @@ using namespace llvm; using namespace lld; int lld::args::getInteger(opt::InputArgList &Args, unsigned Key, int Default) { - int V = Default; - if (auto *Arg = Args.getLastArg(Key)) { - StringRef S = Arg->getValue(); - if (!to_integer(S, V, 10)) - error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); - } - return V; + auto *A = Args.getLastArg(Key); + if (!A) + return Default; + + int V; + if (to_integer(A->getValue(), V, 10)) + return V; + + StringRef Spelling = Args.getArgString(A->getIndex()); + error(Spelling + ": number expected, but got '" + A->getValue() + "'"); + return 0; } std::vector<StringRef> lld::args::getStrings(opt::InputArgList &Args, int Id) { diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt index b376893f35a4..a45fe209f06f 100644 --- a/Common/CMakeLists.txt +++ b/Common/CMakeLists.txt @@ -10,6 +10,7 @@ add_lld_library(lldCommon Strings.cpp TargetOptionsCommandFlags.cpp Threads.cpp + Timer.cpp Version.cpp ADDITIONAL_HEADER_DIRS diff --git a/Common/ErrorHandler.cpp b/Common/ErrorHandler.cpp index 18affce4d5a6..d1cb3dbbe03c 100644 --- a/Common/ErrorHandler.cpp +++ b/Common/ErrorHandler.cpp @@ -12,7 +12,8 @@ #include "lld/Common/Threads.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/Error.h" +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/IR/DiagnosticPrinter.h" #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include <mutex> @@ -59,6 +60,30 @@ void lld::exitLld(int Val) { _exit(Val); } +void lld::diagnosticHandler(const DiagnosticInfo &DI) { + SmallString<128> S; + raw_svector_ostream OS(S); + DiagnosticPrinterRawOStream DP(OS); + DI.print(DP); + switch (DI.getSeverity()) { + case DS_Error: + error(S); + break; + case DS_Warning: + warn(S); + break; + case DS_Remark: + case DS_Note: + message(S); + break; + } +} + +void lld::checkError(Error E) { + handleAllErrors(std::move(E), + [&](ErrorInfoBase &EIB) { error(EIB.message()); }); +} + void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { *ErrorOS << LogName << ": "; if (ColorDiagnostics) { diff --git a/Common/Strings.cpp b/Common/Strings.cpp index 6cd4ad8d600a..36f4f77d8476 100644 --- a/Common/Strings.cpp +++ b/Common/Strings.cpp @@ -8,7 +8,21 @@ //===----------------------------------------------------------------------===// #include "lld/Common/Strings.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/LLVM.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/Support/GlobPattern.h" +#include <algorithm> +#include <mutex> +#include <vector> + +#if defined(_MSC_VER) +#include <Windows.h> + +// DbgHelp.h must be included after Windows.h. +#include <DbgHelp.h> +#pragma comment(lib, "dbghelp.lib") +#endif using namespace llvm; using namespace lld; @@ -30,3 +44,66 @@ Optional<std::string> lld::demangleItanium(StringRef Name) { free(Buf); return S; } + +Optional<std::string> lld::demangleMSVC(StringRef S) { +#if defined(_MSC_VER) + // UnDecorateSymbolName is not thread-safe, so we need a mutex. + static std::mutex Mu; + std::lock_guard<std::mutex> Lock(Mu); + + char Buf[4096]; + if (S.startswith("?")) + if (size_t Len = UnDecorateSymbolName(S.str().c_str(), Buf, sizeof(Buf), 0)) + return std::string(Buf, Len); +#endif + return None; +} + +StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) { + for (StringRef S : Pat) { + Expected<GlobPattern> Pat = GlobPattern::create(S); + if (!Pat) + error(toString(Pat.takeError())); + else + Patterns.push_back(*Pat); + } +} + +bool StringMatcher::match(StringRef S) const { + for (const GlobPattern &Pat : Patterns) + if (Pat.match(S)) + return true; + return false; +} + +// Converts a hex string (e.g. "deadbeef") to a vector. +std::vector<uint8_t> lld::parseHex(StringRef S) { + std::vector<uint8_t> Hex; + while (!S.empty()) { + StringRef B = S.substr(0, 2); + S = S.substr(2); + uint8_t H; + if (!to_integer(B, H, 16)) { + error("not a hexadecimal value: " + B); + return {}; + } + Hex.push_back(H); + } + return Hex; +} + +// Returns true if S is valid as a C language identifier. +bool lld::isValidCIdentifier(StringRef S) { + return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && + std::all_of(S.begin() + 1, S.end(), + [](char C) { return C == '_' || isAlnum(C); }); +} + +// Write the contents of the a buffer to a file +void lld::saveBuffer(StringRef Buffer, const Twine &Path) { + std::error_code EC; + raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); + if (EC) + error("cannot create " + Path + ": " + EC.message()); + OS << Buffer; +} diff --git a/Common/TargetOptionsCommandFlags.cpp b/Common/TargetOptionsCommandFlags.cpp index e8e582f4c256..b46df363c361 100644 --- a/Common/TargetOptionsCommandFlags.cpp +++ b/Common/TargetOptionsCommandFlags.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// // // This file exists as a place for global variables defined in LLVM's -// CodeGen/CommandFlags.def. By putting the resulting object file in +// CodeGen/CommandFlags.inc. By putting the resulting object file in // an archive and linking with it, the definitions will automatically be // included when needed and skipped when already present. // @@ -16,12 +16,12 @@ #include "lld/Common/TargetOptionsCommandFlags.h" -#include "llvm/CodeGen/CommandFlags.def" +#include "llvm/CodeGen/CommandFlags.inc" #include "llvm/Target/TargetOptions.h" // Define an externally visible version of // InitTargetOptionsFromCodeGenFlags, so that its functionality can be -// used without having to include llvm/CodeGen/CommandFlags.def, which +// used without having to include llvm/CodeGen/CommandFlags.inc, which // would lead to multiple definitions of the command line flags. llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() { return ::InitTargetOptionsFromCodeGenFlags(); @@ -30,3 +30,5 @@ llvm::TargetOptions lld::InitTargetOptionsFromCodeGenFlags() { llvm::Optional<llvm::CodeModel::Model> lld::GetCodeModelFromCMModel() { return getCodeModel(); } + +std::string lld::GetCPUStr() { return ::getCPUStr(); } diff --git a/Common/Timer.cpp b/Common/Timer.cpp new file mode 100644 index 000000000000..89f9829b47cf --- /dev/null +++ b/Common/Timer.cpp @@ -0,0 +1,80 @@ +//===- Timer.cpp ----------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lld/Common/Timer.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Support/Format.h" + +using namespace lld; +using namespace llvm; + +ScopedTimer::ScopedTimer(Timer &T) : T(&T) { T.start(); } + +void ScopedTimer::stop() { + if (!T) + return; + T->stop(); + T = nullptr; +} + +ScopedTimer::~ScopedTimer() { stop(); } + +Timer::Timer(llvm::StringRef Name) : Name(Name), Parent(nullptr) {} +Timer::Timer(llvm::StringRef Name, Timer &Parent) + : Name(Name), Parent(&Parent) {} + +void Timer::start() { + if (Parent && Total.count() == 0) + Parent->Children.push_back(this); + StartTime = std::chrono::high_resolution_clock::now(); +} + +void Timer::stop() { + Total += (std::chrono::high_resolution_clock::now() - StartTime); +} + +Timer &Timer::root() { + static Timer RootTimer("Total Link Time"); + return RootTimer; +} + +void Timer::print() { + double TotalDuration = static_cast<double>(root().millis()); + + // We want to print the grand total under all the intermediate phases, so we + // print all children first, then print the total under that. + for (const auto &Child : Children) + Child->print(1, TotalDuration); + + message(std::string(49, '-')); + + root().print(0, root().millis(), false); +} + +double Timer::millis() const { + return std::chrono::duration_cast<std::chrono::duration<double, std::milli>>( + Total) + .count(); +} + +void Timer::print(int Depth, double TotalDuration, bool Recurse) const { + double P = 100.0 * millis() / TotalDuration; + + SmallString<32> Str; + llvm::raw_svector_ostream Stream(Str); + std::string S = std::string(Depth * 2, ' ') + Name + std::string(":"); + Stream << format("%-30s%5d ms (%5.1f%%)", S.c_str(), (int)millis(), P); + + message(Str); + + if (Recurse) { + for (const auto &Child : Children) + Child->print(Depth + 1, TotalDuration); + } +} diff --git a/ELF/AArch64ErrataFix.cpp b/ELF/AArch64ErrataFix.cpp index 9c0d536dea71..7551919cf86f 100644 --- a/ELF/AArch64ErrataFix.cpp +++ b/ELF/AArch64ErrataFix.cpp @@ -34,12 +34,11 @@ #include "LinkerScript.h" #include "OutputSections.h" #include "Relocations.h" -#include "Strings.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Memory.h" - +#include "lld/Common/Strings.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -47,6 +46,7 @@ using namespace llvm; using namespace llvm::ELF; using namespace llvm::object; +using namespace llvm::support; using namespace llvm::support::endian; using namespace lld; @@ -341,7 +341,7 @@ static bool is843419ErratumSequence(uint32_t Instr1, uint32_t Instr2, // patch or 0 if no patch required. static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, uint64_t Limit) { - uint64_t ISAddr = IS->getParent()->Addr + IS->OutSecOff; + uint64_t ISAddr = IS->getVA(0); // Advance Off so that (ISAddr + Off) modulo 0x1000 is at least 0xff8. uint64_t InitialPageOff = (ISAddr + Off) & 0xfff; @@ -357,7 +357,7 @@ static uint64_t scanCortexA53Errata843419(InputSection *IS, uint64_t &Off, uint64_t PatchOff = 0; const uint8_t *Buf = IS->Data.begin(); - const uint32_t *InstBuf = reinterpret_cast<const uint32_t *>(Buf + Off); + const ulittle32_t *InstBuf = reinterpret_cast<const ulittle32_t *>(Buf + Off); uint32_t Instr1 = *InstBuf++; uint32_t Instr2 = *InstBuf++; uint32_t Instr3 = *InstBuf++; @@ -405,7 +405,7 @@ lld::elf::Patch843419Section::Patch843419Section(InputSection *P, uint64_t Off) } uint64_t lld::elf::Patch843419Section::getLDSTAddr() const { - return Patchee->getParent()->Addr + Patchee->OutSecOff + PatcheeOffset; + return Patchee->getVA(PatcheeOffset); } void lld::elf::Patch843419Section::writeTo(uint8_t *Buf) { @@ -554,9 +554,8 @@ static void implementPatch(uint64_t AdrpAddr, uint64_t PatcheeOffset, if (RelIt != IS->Relocations.end() && RelIt->Type == R_AARCH64_JUMP26) return; - if (Config->Verbose) - message("detected cortex-a53-843419 erratum sequence starting at " + - utohexstr(AdrpAddr) + " in unpatched output."); + log("detected cortex-a53-843419 erratum sequence starting at " + + utohexstr(AdrpAddr) + " in unpatched output."); auto *PS = make<Patch843419Section>(IS, PatcheeOffset); Patches.push_back(PS); @@ -602,7 +601,7 @@ AArch64Err843419Patcher::patchInputSectionDescription( (DataSym == MapSyms.end()) ? IS->Data.size() : (*DataSym)->Value; while (Off < Limit) { - uint64_t StartAddr = IS->getParent()->Addr + IS->OutSecOff + Off; + uint64_t StartAddr = IS->getVA(Off); if (uint64_t PatcheeOffset = scanCortexA53Errata843419(IS, Off, Limit)) implementPatch(StartAddr, PatcheeOffset, IS, Patches); } diff --git a/ELF/AArch64ErrataFix.h b/ELF/AArch64ErrataFix.h index 6c100f25d8af..edd154d4cab3 100644 --- a/ELF/AArch64ErrataFix.h +++ b/ELF/AArch64ErrataFix.h @@ -11,7 +11,6 @@ #define LLD_ELF_AARCH64ERRATAFIX_H #include "lld/Common/LLVM.h" - #include <map> #include <vector> diff --git a/ELF/Arch/AArch64.cpp b/ELF/Arch/AArch64.cpp index 99e9879a6989..c7b3c0801de2 100644 --- a/ELF/Arch/AArch64.cpp +++ b/ELF/Arch/AArch64.cpp @@ -34,7 +34,7 @@ public: AArch64(); RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; + RelType getDynRel(RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, @@ -89,6 +89,11 @@ RelExpr AArch64::getRelExpr(RelType Type, const Symbol &S, return R_TLSDESC_CALL; case R_AARCH64_TLSLE_ADD_TPREL_HI12: case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: return R_TLS; case R_AARCH64_CALL26: case R_AARCH64_CONDBR19: @@ -144,8 +149,10 @@ bool AArch64::usesOnlyLowPageBits(RelType Type) const { } } -bool AArch64::isPicRel(RelType Type) const { - return Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64; +RelType AArch64::getDynRel(RelType Type) const { + if (Type == R_AARCH64_ABS32 || Type == R_AARCH64_ABS64) + return Type; + return R_AARCH64_NONE; } void AArch64::writeGotPlt(uint8_t *Buf, const Symbol &) const { @@ -240,12 +247,12 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_AARCH64_ABS16: case R_AARCH64_PREL16: - checkIntUInt<16>(Loc, Val, Type); + checkIntUInt(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_AARCH64_ABS32: case R_AARCH64_PREL32: - checkIntUInt<32>(Loc, Val, Type); + checkIntUInt(Loc, Val, 32, Type); write32le(Loc, Val); break; case R_AARCH64_ABS64: @@ -260,11 +267,11 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_AARCH64_ADR_PREL_PG_HI21: case R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21: case R_AARCH64_TLSDESC_ADR_PAGE21: - checkInt<33>(Loc, Val, Type); + checkInt(Loc, Val, 33, Type); write32AArch64Addr(Loc, Val >> 12); break; case R_AARCH64_ADR_PREL_LO21: - checkInt<21>(Loc, Val, Type); + checkInt(Loc, Val, 21, Type); write32AArch64Addr(Loc, Val); break; case R_AARCH64_JUMP26: @@ -278,38 +285,40 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { write32le(Loc, 0x14000000); LLVM_FALLTHROUGH; case R_AARCH64_CALL26: - checkInt<28>(Loc, Val, Type); + checkInt(Loc, Val, 28, Type); or32le(Loc, (Val & 0x0FFFFFFC) >> 2); break; case R_AARCH64_CONDBR19: case R_AARCH64_LD_PREL_LO19: - checkAlignment<4>(Loc, Val, Type); - checkInt<21>(Loc, Val, Type); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 21, Type); or32le(Loc, (Val & 0x1FFFFC) << 3); break; - case R_AARCH64_LD64_GOT_LO12_NC: - case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: - case R_AARCH64_TLSDESC_LD64_LO12: - checkAlignment<8>(Loc, Val, Type); - or32le(Loc, (Val & 0xFF8) << 7); - break; case R_AARCH64_LDST8_ABS_LO12_NC: + case R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC: or32AArch64Imm(Loc, getBits(Val, 0, 11)); break; case R_AARCH64_LDST16_ABS_LO12_NC: - checkAlignment<2>(Loc, Val, Type); + case R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC: + checkAlignment(Loc, Val, 2, Type); or32AArch64Imm(Loc, getBits(Val, 1, 11)); break; case R_AARCH64_LDST32_ABS_LO12_NC: - checkAlignment<4>(Loc, Val, Type); + case R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC: + checkAlignment(Loc, Val, 4, Type); or32AArch64Imm(Loc, getBits(Val, 2, 11)); break; case R_AARCH64_LDST64_ABS_LO12_NC: - checkAlignment<8>(Loc, Val, Type); + case R_AARCH64_LD64_GOT_LO12_NC: + case R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC: + case R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC: + case R_AARCH64_TLSDESC_LD64_LO12: + checkAlignment(Loc, Val, 8, Type); or32AArch64Imm(Loc, getBits(Val, 3, 11)); break; case R_AARCH64_LDST128_ABS_LO12_NC: - checkAlignment<16>(Loc, Val, Type); + case R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: + checkAlignment(Loc, Val, 16, Type); or32AArch64Imm(Loc, getBits(Val, 4, 11)); break; case R_AARCH64_MOVW_UABS_G0_NC: @@ -325,11 +334,11 @@ void AArch64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { or32le(Loc, (Val & 0xFFFF000000000000) >> 43); break; case R_AARCH64_TSTBR14: - checkInt<16>(Loc, Val, Type); + checkInt(Loc, Val, 16, Type); or32le(Loc, (Val & 0xFFFC) << 3); break; case R_AARCH64_TLSLE_ADD_TPREL_HI12: - checkInt<24>(Loc, Val, Type); + checkInt(Loc, Val, 24, Type); or32AArch64Imm(Loc, Val >> 12); break; case R_AARCH64_TLSLE_ADD_TPREL_LO12_NC: @@ -353,7 +362,7 @@ void AArch64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { // movk x0, #0x10 // nop // nop - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); switch (Type) { case R_AARCH64_TLSDESC_ADD_LO12: @@ -403,7 +412,7 @@ void AArch64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { } void AArch64::relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); if (Type == R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21) { // Generate MOVZ. diff --git a/ELF/Arch/AMDGPU.cpp b/ELF/Arch/AMDGPU.cpp index 505e0e6ad480..48b27f23510c 100644 --- a/ELF/Arch/AMDGPU.cpp +++ b/ELF/Arch/AMDGPU.cpp @@ -66,6 +66,7 @@ void AMDGPU::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { write32le(Loc, Val); break; case R_AMDGPU_ABS64: + case R_AMDGPU_REL64: write64le(Loc, Val); break; case R_AMDGPU_GOTPCREL32_HI: @@ -86,6 +87,7 @@ RelExpr AMDGPU::getRelExpr(RelType Type, const Symbol &S, case R_AMDGPU_REL32: case R_AMDGPU_REL32_LO: case R_AMDGPU_REL32_HI: + case R_AMDGPU_REL64: return R_PC; case R_AMDGPU_GOTPCREL: case R_AMDGPU_GOTPCREL32_LO: diff --git a/ELF/Arch/ARM.cpp b/ELF/Arch/ARM.cpp index b9f551e4b3be..d99be9be7c36 100644 --- a/ELF/Arch/ARM.cpp +++ b/ELF/Arch/ARM.cpp @@ -29,7 +29,6 @@ public: uint32_t calcEFlags() const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; RelType getDynRel(RelType Type) const override; int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; @@ -55,6 +54,7 @@ ARM::ARM() { TlsGotRel = R_ARM_TLS_TPOFF32; TlsModuleIndexRel = R_ARM_TLS_DTPMOD32; TlsOffsetRel = R_ARM_TLS_DTPOFF32; + GotBaseSymInGotPlt = false; GotEntrySize = 4; GotPltEntrySize = 4; PltEntrySize = 16; @@ -161,18 +161,10 @@ RelExpr ARM::getRelExpr(RelType Type, const Symbol &S, } } -bool ARM::isPicRel(RelType Type) const { - return (Type == R_ARM_TARGET1 && !Config->Target1Rel) || - (Type == R_ARM_ABS32); -} - RelType ARM::getDynRel(RelType Type) const { - if (Type == R_ARM_TARGET1 && !Config->Target1Rel) + if ((Type == R_ARM_ABS32) || (Type == R_ARM_TARGET1 && !Config->Target1Rel)) return R_ARM_ABS32; - if (Type == R_ARM_ABS32) - return Type; - // Keep it going with a dummy value so that we can find more reloc errors. - return R_ARM_ABS32; + return R_ARM_NONE; } void ARM::writeGotPlt(uint8_t *Buf, const Symbol &) const { @@ -392,7 +384,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { write32le(Loc, 1); break; case R_ARM_PREL31: - checkInt<31>(Loc, Val, Type); + checkInt(Loc, Val, 31, Type); write32le(Loc, (read32le(Loc) & 0x80000000) | (Val & ~0x80000000)); break; case R_ARM_CALL: @@ -401,7 +393,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { if (Val & 1) { // If bit 0 of Val is 1 the target is Thumb, we must select a BLX. // The BLX encoding is 0xfa:H:imm24 where Val = imm24:H:'1' - checkInt<26>(Loc, Val, Type); + checkInt(Loc, Val, 26, Type); write32le(Loc, 0xfa000000 | // opcode ((Val & 2) << 23) | // H ((Val >> 2) & 0x00ffffff)); // imm24 @@ -416,16 +408,16 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_ARM_JUMP24: case R_ARM_PC24: case R_ARM_PLT32: - checkInt<26>(Loc, Val, Type); + checkInt(Loc, Val, 26, Type); write32le(Loc, (read32le(Loc) & ~0x00ffffff) | ((Val >> 2) & 0x00ffffff)); break; case R_ARM_THM_JUMP11: - checkInt<12>(Loc, Val, Type); + checkInt(Loc, Val, 12, Type); write16le(Loc, (read32le(Loc) & 0xf800) | ((Val >> 1) & 0x07ff)); break; case R_ARM_THM_JUMP19: // Encoding T3: Val = S:J2:J1:imm6:imm11:0 - checkInt<21>(Loc, Val, Type); + checkInt(Loc, Val, 21, Type); write16le(Loc, (read16le(Loc) & 0xfbc0) | // opcode cond ((Val >> 10) & 0x0400) | // S @@ -451,7 +443,7 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_ARM_THM_JUMP24: // Encoding B T4, BL T1, BLX T2: Val = S:I1:I2:imm10:imm11:0 // FIXME: Use of I1 and I2 require v6T2ops - checkInt<25>(Loc, Val, Type); + checkInt(Loc, Val, 25, Type); write16le(Loc, 0xf000 | // opcode ((Val >> 14) & 0x0400) | // S @@ -469,14 +461,14 @@ void ARM::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { break; case R_ARM_MOVT_ABS: case R_ARM_MOVT_PREL: - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32le(Loc, (read32le(Loc) & ~0x000f0fff) | (((Val >> 16) & 0xf000) << 4) | ((Val >> 16) & 0xfff)); break; case R_ARM_THM_MOVT_ABS: case R_ARM_THM_MOVT_PREL: // Encoding T1: A = imm4:i:imm3:imm8 - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write16le(Loc, 0xf2c0 | // opcode ((Val >> 17) & 0x0400) | // i diff --git a/ELF/Arch/Hexagon.cpp b/ELF/Arch/Hexagon.cpp new file mode 100644 index 000000000000..2d5c23fd5ad6 --- /dev/null +++ b/ELF/Arch/Hexagon.cpp @@ -0,0 +1,97 @@ +//===-- Hexagon.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputFiles.h" +#include "Symbols.h" +#include "Target.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::support::endian; +using namespace llvm::ELF; +using namespace lld; +using namespace lld::elf; + +namespace { +class Hexagon final : public TargetInfo { +public: + uint32_t calcEFlags() const override; + RelExpr getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const override; + void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; +}; +} // namespace + +// Support V60 only at the moment. +uint32_t Hexagon::calcEFlags() const { return 0x60; } + +static uint32_t applyMask(uint32_t Mask, uint32_t Data) { + uint32_t Result = 0; + size_t Off = 0; + + for (size_t Bit = 0; Bit != 32; ++Bit) { + uint32_t ValBit = (Data >> Off) & 1; + uint32_t MaskBit = (Mask >> Bit) & 1; + if (MaskBit) { + Result |= (ValBit << Bit); + ++Off; + } + } + return Result; +} + +RelExpr Hexagon::getRelExpr(RelType Type, const Symbol &S, + const uint8_t *Loc) const { + switch (Type) { + case R_HEX_B15_PCREL: + case R_HEX_B15_PCREL_X: + case R_HEX_B22_PCREL: + case R_HEX_B22_PCREL_X: + case R_HEX_B32_PCREL_X: + return R_PC; + default: + return R_ABS; + } +} + +static void or32le(uint8_t *P, int32_t V) { write32le(P, read32le(P) | V); } + +void Hexagon::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { + case R_HEX_NONE: + break; + case R_HEX_B15_PCREL: + or32le(Loc, applyMask(0x00df20fe, Val >> 2)); + break; + case R_HEX_B15_PCREL_X: + or32le(Loc, applyMask(0x00df20fe, Val & 0x3f)); + break; + case R_HEX_B22_PCREL: + or32le(Loc, applyMask(0x1ff3ffe, Val >> 2)); + break; + case R_HEX_B22_PCREL_X: + or32le(Loc, applyMask(0x1ff3ffe, Val & 0x3f)); + break; + case R_HEX_B32_PCREL_X: + or32le(Loc, applyMask(0x0fff3fff, Val >> 6)); + break; + default: + error(getErrorLocation(Loc) + "unrecognized reloc " + toString(Type)); + break; + } +} + +TargetInfo *elf::getHexagonTargetInfo() { + static Hexagon Target; + return &Target; +} diff --git a/ELF/Arch/Mips.cpp b/ELF/Arch/Mips.cpp index 495e2567006f..dc70401c0b0e 100644 --- a/ELF/Arch/Mips.cpp +++ b/ELF/Arch/Mips.cpp @@ -32,7 +32,6 @@ public: RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const override; - bool isPicRel(RelType Type) const override; RelType getDynRel(RelType Type) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; @@ -50,6 +49,7 @@ template <class ELFT> MIPS<ELFT>::MIPS() { DefaultMaxPageSize = 65536; GotEntrySize = sizeof(typename ELFT::uint); GotPltEntrySize = sizeof(typename ELFT::uint); + GotBaseSymInGotPlt = false; PltEntrySize = 16; PltHeaderSize = 32; CopyRel = R_MIPS_COPY; @@ -101,8 +101,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, case R_MIPS_HIGHEST: case R_MICROMIPS_HI16: case R_MICROMIPS_LO16: - case R_MICROMIPS_HIGHER: - case R_MICROMIPS_HIGHEST: // R_MIPS_HI16/R_MIPS_LO16 relocations against _gp_disp calculate // offset between start of function and 'gp' value which by default // equal to the start of .got section. In that case we consider these @@ -124,8 +122,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, case R_MIPS_TLS_TPREL_LO16: case R_MIPS_TLS_TPREL32: case R_MIPS_TLS_TPREL64: - case R_MICROMIPS_GOT_OFST: - case R_MICROMIPS_SUB: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_TPREL_HI16: @@ -155,7 +151,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, case R_MIPS_GOT_DISP: case R_MIPS_TLS_GOTTPREL: case R_MICROMIPS_CALL16: - case R_MICROMIPS_GOT_DISP: case R_MICROMIPS_TLS_GOTTPREL: return R_MIPS_GOT_OFF; case R_MIPS_CALL_HI16: @@ -168,7 +163,6 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, case R_MICROMIPS_GOT_LO16: return R_MIPS_GOT_OFF32; case R_MIPS_GOT_PAGE: - case R_MICROMIPS_GOT_PAGE: return R_MIPS_GOT_LOCAL_PAGE; case R_MIPS_TLS_GD: case R_MICROMIPS_TLS_GD: @@ -183,12 +177,10 @@ RelExpr MIPS<ELFT>::getRelExpr(RelType Type, const Symbol &S, } } -template <class ELFT> bool MIPS<ELFT>::isPicRel(RelType Type) const { - return Type == R_MIPS_32 || Type == R_MIPS_64; -} - template <class ELFT> RelType MIPS<ELFT>::getDynRel(RelType Type) const { - return RelativeRel; + if (Type == R_MIPS_32 || Type == R_MIPS_64) + return RelativeRel; + return R_MIPS_NONE; } template <class ELFT> @@ -213,8 +205,8 @@ template <endianness E> static uint32_t readShuffle(const uint8_t *Loc) { } template <endianness E> -static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize, - uint8_t Shift) { +static void writeValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { uint32_t Instr = read32<E>(Loc); uint32_t Mask = 0xffffffff >> (32 - BitsSize); uint32_t Data = (Instr & ~Mask) | ((V >> Shift) & Mask); @@ -222,14 +214,14 @@ static void writeRelocation(uint8_t *Loc, uint64_t V, uint8_t BitsSize, } template <endianness E> -static void writeMicroRelocation32(uint8_t *Loc, uint64_t V, uint8_t BitsSize, - uint8_t Shift) { +static void writeShuffleValue(uint8_t *Loc, uint64_t V, uint8_t BitsSize, + uint8_t Shift) { // See comments in readShuffle for purpose of this code. uint16_t *Words = (uint16_t *)Loc; if (E == support::little) std::swap(Words[0], Words[1]); - writeRelocation<E>(Loc, V, BitsSize, Shift); + writeValue<E>(Loc, V, BitsSize, Shift); if (E == support::little) std::swap(Words[0], Words[1]); @@ -296,13 +288,14 @@ template <class ELFT> void MIPS<ELFT>::writePltHeader(uint8_t *Buf) const { write32<E>(Buf + 20, 0x0018c082); // srl $24, $24, 2 } - write32<E>(Buf + 24, 0x0320f809); // jalr $25 + uint32_t JalrInst = Config->ZHazardplt ? 0x0320fc09 : 0x0320f809; + write32<E>(Buf + 24, JalrInst); // jalr.hb $25 or jalr $25 write32<E>(Buf + 28, 0x2718fffe); // subu $24, $24, 2 uint64_t GotPlt = InX::GotPlt->getVA(); - writeRelocation<E>(Buf, GotPlt + 0x8000, 16, 16); - writeRelocation<E>(Buf + 4, GotPlt, 16, 0); - writeRelocation<E>(Buf + 8, GotPlt, 16, 0); + writeValue<E>(Buf, GotPlt + 0x8000, 16, 16); + writeValue<E>(Buf + 4, GotPlt, 16, 0); + writeValue<E>(Buf + 8, GotPlt, 16, 0); } template <class ELFT> @@ -330,13 +323,16 @@ void MIPS<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, return; } + uint32_t JrInst = isMipsR6() ? (Config->ZHazardplt ? 0x03200409 : 0x03200009) + : (Config->ZHazardplt ? 0x03200408 : 0x03200008); + write32<E>(Buf, 0x3c0f0000); // lui $15, %hi(.got.plt entry) write32<E>(Buf + 4, 0x8df90000); // l[wd] $25, %lo(.got.plt entry)($15) - write32<E>(Buf + 8, isMipsR6() ? 0x03200009 : 0x03200008); // jr $25 + write32<E>(Buf + 8, JrInst); // jr $25 / jr.hb $25 write32<E>(Buf + 12, 0x25f80000); // addiu $24, $15, %lo(.got.plt entry) - writeRelocation<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16); - writeRelocation<E>(Buf + 4, GotPltEntryAddr, 16, 0); - writeRelocation<E>(Buf + 12, GotPltEntryAddr, 16, 0); + writeValue<E>(Buf, GotPltEntryAddr + 0x8000, 16, 16); + writeValue<E>(Buf + 4, GotPltEntryAddr, 16, 0); + writeValue<E>(Buf + 12, GotPltEntryAddr, 16, 0); } template <class ELFT> @@ -455,9 +451,6 @@ calculateMipsRelChain(uint8_t *Loc, RelType Type, uint64_t Val) { return std::make_pair(Type2, Val); if (Type2 == R_MIPS_SUB && (Type3 == R_MIPS_HI16 || Type3 == R_MIPS_LO16)) return std::make_pair(Type3, -Val); - if (Type2 == R_MICROMIPS_SUB && - (Type3 == R_MICROMIPS_HI16 || Type3 == R_MICROMIPS_LO16)) - return std::make_pair(Type3, -Val); error(getErrorLocation(Loc) + "unsupported relocations combination " + Twine(Type)); return std::make_pair(Type & 0xff, Val); @@ -467,6 +460,9 @@ template <class ELFT> void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { const endianness E = ELFT::TargetEndianness; + if (ELFT::Is64Bits || Config->MipsN32Abi) + std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); + // Thread pointer and DRP offsets from the start of TLS data area. // https://www.linux-mips.org/wiki/NPTL if (Type == R_MIPS_TLS_DTPREL_HI16 || Type == R_MIPS_TLS_DTPREL_LO16 || @@ -481,9 +477,6 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { Val -= 0x7000; } - if (ELFT::Is64Bits || Config->MipsN32Abi) - std::tie(Type, Val) = calculateMipsRelChain(Loc, Type, Val); - switch (Type) { case R_MIPS_32: case R_MIPS_GPREL32: @@ -497,25 +490,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { write64<E>(Loc, Val); break; case R_MIPS_26: - writeRelocation<E>(Loc, Val, 26, 2); + writeValue<E>(Loc, Val, 26, 2); break; case R_MIPS_GOT16: // The R_MIPS_GOT16 relocation's value in "relocatable" linking mode // is updated addend (not a GOT index). In that case write high 16 bits // to store a correct addend value. if (Config->Relocatable) { - writeRelocation<E>(Loc, Val + 0x8000, 16, 16); + writeValue<E>(Loc, Val + 0x8000, 16, 16); } else { - checkInt<16>(Loc, Val, Type); - writeRelocation<E>(Loc, Val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeValue<E>(Loc, Val, 16, 0); } break; case R_MICROMIPS_GOT16: if (Config->Relocatable) { - writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16); + writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16); } else { - checkInt<16>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeShuffleValue<E>(Loc, Val, 16, 0); } break; case R_MIPS_CALL16: @@ -525,7 +518,7 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_MIPS_TLS_GD: case R_MIPS_TLS_GOTTPREL: case R_MIPS_TLS_LDM: - checkInt<16>(Loc, Val, Type); + checkInt(Loc, Val, 16, Type); LLVM_FALLTHROUGH; case R_MIPS_CALL_LO16: case R_MIPS_GOT_LO16: @@ -534,28 +527,25 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_MIPS_PCLO16: case R_MIPS_TLS_DTPREL_LO16: case R_MIPS_TLS_TPREL_LO16: - writeRelocation<E>(Loc, Val, 16, 0); + writeValue<E>(Loc, Val, 16, 0); break; - case R_MICROMIPS_GOT_DISP: - case R_MICROMIPS_GOT_PAGE: case R_MICROMIPS_GPREL16: case R_MICROMIPS_TLS_GD: case R_MICROMIPS_TLS_LDM: - checkInt<16>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 16, 0); + checkInt(Loc, Val, 16, Type); + writeShuffleValue<E>(Loc, Val, 16, 0); break; case R_MICROMIPS_CALL16: case R_MICROMIPS_CALL_LO16: - case R_MICROMIPS_GOT_OFST: case R_MICROMIPS_LO16: case R_MICROMIPS_TLS_DTPREL_LO16: case R_MICROMIPS_TLS_GOTTPREL: case R_MICROMIPS_TLS_TPREL_LO16: - writeMicroRelocation32<E>(Loc, Val, 16, 0); + writeShuffleValue<E>(Loc, Val, 16, 0); break; case R_MICROMIPS_GPREL7_S2: - checkInt<7>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 7, 2); + checkInt(Loc, Val, 7, Type); + writeShuffleValue<E>(Loc, Val, 7, 2); break; case R_MIPS_CALL_HI16: case R_MIPS_GOT_HI16: @@ -563,86 +553,80 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_MIPS_PCHI16: case R_MIPS_TLS_DTPREL_HI16: case R_MIPS_TLS_TPREL_HI16: - writeRelocation<E>(Loc, Val + 0x8000, 16, 16); + writeValue<E>(Loc, Val + 0x8000, 16, 16); break; case R_MICROMIPS_CALL_HI16: case R_MICROMIPS_GOT_HI16: case R_MICROMIPS_HI16: case R_MICROMIPS_TLS_DTPREL_HI16: case R_MICROMIPS_TLS_TPREL_HI16: - writeMicroRelocation32<E>(Loc, Val + 0x8000, 16, 16); + writeShuffleValue<E>(Loc, Val + 0x8000, 16, 16); break; case R_MIPS_HIGHER: - writeRelocation<E>(Loc, Val + 0x80008000, 16, 32); + writeValue<E>(Loc, Val + 0x80008000, 16, 32); break; case R_MIPS_HIGHEST: - writeRelocation<E>(Loc, Val + 0x800080008000, 16, 48); - break; - case R_MICROMIPS_HIGHER: - writeMicroRelocation32<E>(Loc, Val + 0x80008000, 16, 32); - break; - case R_MICROMIPS_HIGHEST: - writeMicroRelocation32<E>(Loc, Val + 0x800080008000, 16, 48); + writeValue<E>(Loc, Val + 0x800080008000, 16, 48); break; case R_MIPS_JALR: case R_MICROMIPS_JALR: // Ignore this optimization relocation for now break; case R_MIPS_PC16: - checkAlignment<4>(Loc, Val, Type); - checkInt<18>(Loc, Val, Type); - writeRelocation<E>(Loc, Val, 16, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 18, Type); + writeValue<E>(Loc, Val, 16, 2); break; case R_MIPS_PC19_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<21>(Loc, Val, Type); - writeRelocation<E>(Loc, Val, 19, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 21, Type); + writeValue<E>(Loc, Val, 19, 2); break; case R_MIPS_PC21_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<23>(Loc, Val, Type); - writeRelocation<E>(Loc, Val, 21, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 23, Type); + writeValue<E>(Loc, Val, 21, 2); break; case R_MIPS_PC26_S2: - checkAlignment<4>(Loc, Val, Type); - checkInt<28>(Loc, Val, Type); - writeRelocation<E>(Loc, Val, 26, 2); + checkAlignment(Loc, Val, 4, Type); + checkInt(Loc, Val, 28, Type); + writeValue<E>(Loc, Val, 26, 2); break; case R_MIPS_PC32: - writeRelocation<E>(Loc, Val, 32, 0); + writeValue<E>(Loc, Val, 32, 0); break; case R_MICROMIPS_26_S1: case R_MICROMIPS_PC26_S1: - checkInt<27>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 26, 1); + checkInt(Loc, Val, 27, Type); + writeShuffleValue<E>(Loc, Val, 26, 1); break; case R_MICROMIPS_PC7_S1: - checkInt<8>(Loc, Val, Type); + checkInt(Loc, Val, 8, Type); writeMicroRelocation16<E>(Loc, Val, 7, 1); break; case R_MICROMIPS_PC10_S1: - checkInt<11>(Loc, Val, Type); + checkInt(Loc, Val, 11, Type); writeMicroRelocation16<E>(Loc, Val, 10, 1); break; case R_MICROMIPS_PC16_S1: - checkInt<17>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 16, 1); + checkInt(Loc, Val, 17, Type); + writeShuffleValue<E>(Loc, Val, 16, 1); break; case R_MICROMIPS_PC18_S3: - checkInt<21>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 18, 3); + checkInt(Loc, Val, 21, Type); + writeShuffleValue<E>(Loc, Val, 18, 3); break; case R_MICROMIPS_PC19_S2: - checkInt<21>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 19, 2); + checkInt(Loc, Val, 21, Type); + writeShuffleValue<E>(Loc, Val, 19, 2); break; case R_MICROMIPS_PC21_S1: - checkInt<22>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 21, 1); + checkInt(Loc, Val, 22, Type); + writeShuffleValue<E>(Loc, Val, 21, 1); break; case R_MICROMIPS_PC23_S2: - checkInt<25>(Loc, Val, Type); - writeMicroRelocation32<E>(Loc, Val, 23, 2); + checkInt(Loc, Val, 25, Type); + writeShuffleValue<E>(Loc, Val, 23, 2); break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); @@ -651,19 +635,26 @@ void MIPS<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { template <class ELFT> bool MIPS<ELFT>::usesOnlyLowPageBits(RelType Type) const { return Type == R_MIPS_LO16 || Type == R_MIPS_GOT_OFST || - Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_GOT_OFST; + Type == R_MICROMIPS_LO16; } // Return true if the symbol is a PIC function. template <class ELFT> bool elf::isMipsPIC(const Defined *Sym) { - typedef typename ELFT::Ehdr Elf_Ehdr; - if (!Sym->Section || !Sym->isFunc()) + if (!Sym->isFunc()) + return false; + + if (Sym->StOther & STO_MIPS_PIC) + return true; + + if (!Sym->Section) + return false; + + ObjFile<ELFT> *File = + cast<InputSectionBase>(Sym->Section)->template getFile<ELFT>(); + if (!File) return false; - auto *Sec = cast<InputSectionBase>(Sym->Section); - const Elf_Ehdr *Hdr = Sec->template getFile<ELFT>()->getObj().getHeader(); - return (Sym->StOther & STO_MIPS_MIPS16) == STO_MIPS_PIC || - (Hdr->e_flags & EF_MIPS_PIC); + return File->getObj().getHeader()->e_flags & EF_MIPS_PIC; } template <class ELFT> TargetInfo *elf::getMipsTargetInfo() { diff --git a/ELF/Arch/MipsArchTree.cpp b/ELF/Arch/MipsArchTree.cpp index 754a47001579..98ceac3075e0 100644 --- a/ELF/Arch/MipsArchTree.cpp +++ b/ELF/Arch/MipsArchTree.cpp @@ -65,25 +65,30 @@ static StringRef getNanName(bool IsNan2008) { static StringRef getFpName(bool IsFp64) { return IsFp64 ? "64" : "32"; } static void checkFlags(ArrayRef<FileFlags> Files) { + assert(!Files.empty() && "expected non-empty file list"); + uint32_t ABI = Files[0].Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); bool Nan = Files[0].Flags & EF_MIPS_NAN2008; bool Fp = Files[0].Flags & EF_MIPS_FP64; - for (const FileFlags &F : Files.slice(1)) { + for (const FileFlags &F : Files) { + if (Config->Is64 && F.Flags & EF_MIPS_MICROMIPS) + error(toString(F.File) + ": microMIPS 64-bit is not supported"); + uint32_t ABI2 = F.Flags & (EF_MIPS_ABI | EF_MIPS_ABI2); if (ABI != ABI2) - error("target ABI '" + getAbiName(ABI) + "' is incompatible with '" + - getAbiName(ABI2) + "': " + toString(F.File)); + error(toString(F.File) + ": ABI '" + getAbiName(ABI2) + + "' is incompatible with target ABI '" + getAbiName(ABI) + "'"); bool Nan2 = F.Flags & EF_MIPS_NAN2008; if (Nan != Nan2) - error("target -mnan=" + getNanName(Nan) + " is incompatible with -mnan=" + - getNanName(Nan2) + ": " + toString(F.File)); + error(toString(F.File) + ": -mnan=" + getNanName(Nan2) + + " is incompatible with target -mnan=" + getNanName(Nan)); bool Fp2 = F.Flags & EF_MIPS_FP64; if (Fp != Fp2) - error("target -mfp" + getFpName(Fp) + " is incompatible with -mfp" + - getFpName(Fp2) + ": " + toString(F.File)); + error(toString(F.File) + ": -mfp" + getFpName(Fp2) + + " is incompatible with target -mfp" + getFpName(Fp)); } } @@ -102,11 +107,13 @@ static uint32_t getPicFlags(ArrayRef<FileFlags> Files) { for (const FileFlags &F : Files.slice(1)) { bool IsPic2 = F.Flags & (EF_MIPS_PIC | EF_MIPS_CPIC); if (IsPic && !IsPic2) - warn("linking abicalls code " + toString(Files[0].File) + - " with non-abicalls file: " + toString(F.File)); + warn(toString(F.File) + + ": linking non-abicalls code with abicalls code " + + toString(Files[0].File)); if (!IsPic && IsPic2) - warn("linking non-abicalls code " + toString(Files[0].File) + - " with abicalls file: " + toString(F.File)); + warn(toString(F.File) + + ": linking abicalls code with non-abicalls code " + + toString(Files[0].File)); } // Compute the result PIC/non-PIC flag. @@ -326,7 +333,7 @@ static StringRef getMipsFpAbiName(uint8_t FpAbi) { case Mips::Val_GNU_MIPS_ABI_FP_SOFT: return "-msoft-float"; case Mips::Val_GNU_MIPS_ABI_FP_OLD_64: - return "-mips32r2 -mfp64 (old)"; + return "-mgp32 -mfp64 (old)"; case Mips::Val_GNU_MIPS_ABI_FP_XX: return "-mfpxx"; case Mips::Val_GNU_MIPS_ABI_FP_64: @@ -343,9 +350,9 @@ uint8_t elf::getMipsFpAbiFlag(uint8_t OldFlag, uint8_t NewFlag, if (compareMipsFpAbi(NewFlag, OldFlag) >= 0) return NewFlag; if (compareMipsFpAbi(OldFlag, NewFlag) < 0) - error("target floating point ABI '" + getMipsFpAbiName(OldFlag) + - "' is incompatible with '" + getMipsFpAbiName(NewFlag) + - "': " + FileName); + error(FileName + ": floating point ABI '" + getMipsFpAbiName(NewFlag) + + "' is incompatible with target floating point ABI '" + + getMipsFpAbiName(OldFlag) + "'"); return OldFlag; } diff --git a/ELF/Arch/PPC.cpp b/ELF/Arch/PPC.cpp index 6af0df331df6..20cae0e59cf4 100644 --- a/ELF/Arch/PPC.cpp +++ b/ELF/Arch/PPC.cpp @@ -21,13 +21,18 @@ using namespace lld::elf; namespace { class PPC final : public TargetInfo { public: - PPC() { GotBaseSymOff = 0x8000; } + PPC(); void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; }; } // namespace +PPC::PPC() { + GotBaseSymOff = 0x8000; + GotBaseSymInGotPlt = false; +} + RelExpr PPC::getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const { switch (Type) { diff --git a/ELF/Arch/PPC64.cpp b/ELF/Arch/PPC64.cpp index ac4021b5918d..fa3bf6c62a0d 100644 --- a/ELF/Arch/PPC64.cpp +++ b/ELF/Arch/PPC64.cpp @@ -14,12 +14,14 @@ #include "llvm/Support/Endian.h" using namespace llvm; +using namespace llvm::object; using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; static uint64_t PPC64TocOffset = 0x8000; +static uint64_t DynamicThreadPointerOffset = 0x8000; uint64_t elf::getPPC64TocBase() { // The TOC consists of sections .got, .toc, .tocbss, .plt in that order. The @@ -39,11 +41,21 @@ namespace { class PPC64 final : public TargetInfo { public: PPC64(); + uint32_t calcEFlags() const override; RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; + void writePltHeader(uint8_t *Buf) const override; void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const override; void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void writeGotHeader(uint8_t *Buf) const override; + bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const override; + RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const override; + void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; }; } // namespace @@ -51,21 +63,35 @@ public: // #higher(value), #highera(value), #highest(value), and #highesta(value) // macros defined in section 4.5.1. Relocation Types of the PPC-elf64abi // document. -static uint16_t applyPPCLo(uint64_t V) { return V; } -static uint16_t applyPPCHi(uint64_t V) { return V >> 16; } -static uint16_t applyPPCHa(uint64_t V) { return (V + 0x8000) >> 16; } -static uint16_t applyPPCHigher(uint64_t V) { return V >> 32; } -static uint16_t applyPPCHighera(uint64_t V) { return (V + 0x8000) >> 32; } -static uint16_t applyPPCHighest(uint64_t V) { return V >> 48; } -static uint16_t applyPPCHighesta(uint64_t V) { return (V + 0x8000) >> 48; } +static uint16_t lo(uint64_t V) { return V; } +static uint16_t hi(uint64_t V) { return V >> 16; } +static uint16_t ha(uint64_t V) { return (V + 0x8000) >> 16; } +static uint16_t higher(uint64_t V) { return V >> 32; } +static uint16_t highera(uint64_t V) { return (V + 0x8000) >> 32; } +static uint16_t highest(uint64_t V) { return V >> 48; } +static uint16_t highesta(uint64_t V) { return (V + 0x8000) >> 48; } PPC64::PPC64() { - PltRel = GotRel = R_PPC64_GLOB_DAT; + GotRel = R_PPC64_GLOB_DAT; + PltRel = R_PPC64_JMP_SLOT; RelativeRel = R_PPC64_RELATIVE; + IRelativeRel = R_PPC64_IRELATIVE; GotEntrySize = 8; + PltEntrySize = 4; GotPltEntrySize = 8; - PltEntrySize = 32; - PltHeaderSize = 0; + GotBaseSymInGotPlt = false; + GotBaseSymOff = 0x8000; + GotHeaderEntriesNum = 1; + GotPltHeaderEntriesNum = 2; + PltHeaderSize = 60; + NeedsThunks = true; + TcbSize = 8; + TlsTpOffset = 0x7000; + + TlsModuleIndexRel = R_PPC64_DTPMOD64; + TlsOffsetRel = R_PPC64_DTPREL64; + + TlsGotRel = R_PPC64_TPREL64; // We need 64K pages (at least under glibc/Linux, the loader won't // set different permissions on a finer granularity than that). @@ -80,6 +106,110 @@ PPC64::PPC64() { // And because the lowest non-zero 256M boundary is 0x10000000, PPC64 linkers // use 0x10000000 as the starting address. DefaultImageBase = 0x10000000; + + TrapInstr = + (Config->IsLE == sys::IsLittleEndianHost) ? 0x7fe00008 : 0x0800e07f; +} + +static uint32_t getEFlags(InputFile *File) { + if (Config->EKind == ELF64BEKind) + return cast<ObjFile<ELF64BE>>(File)->getObj().getHeader()->e_flags; + return cast<ObjFile<ELF64LE>>(File)->getObj().getHeader()->e_flags; +} + +// This file implements v2 ABI. This function makes sure that all +// object files have v2 or an unspecified version as an ABI version. +uint32_t PPC64::calcEFlags() const { + for (InputFile *F : ObjectFiles) { + uint32_t Flag = getEFlags(F); + if (Flag == 1) + error(toString(F) + ": ABI version 1 is not supported"); + else if (Flag > 2) + error(toString(F) + ": unrecognized e_flags: " + Twine(Flag)); + } + return 2; +} + +void PPC64::relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + // Reference: 3.7.4.2 of the 64-bit ELF V2 abi supplement. + // The general dynamic code sequence for a global `x` will look like: + // Instruction Relocation Symbol + // addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x + // addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x + // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x + // R_PPC64_REL24 __tls_get_addr + // nop None None + + // Relaxing to local exec entails converting: + // addis r3, r2, x@got@tlsgd@ha into nop + // addi r3, r3, x@got@tlsgd@l into addis r3, r13, x@tprel@ha + // bl __tls_get_addr(x@tlsgd) into nop + // nop into addi r3, r3, x@tprel@l + + uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U; + + switch (Type) { + case R_PPC64_GOT_TLSGD16_HA: + write32(Loc - EndianOffset, 0x60000000); // nop + break; + case R_PPC64_GOT_TLSGD16_LO: + write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13 + relocateOne(Loc, R_PPC64_TPREL16_HA, Val); + break; + case R_PPC64_TLSGD: + write32(Loc, 0x60000000); // nop + write32(Loc + 4, 0x38630000); // addi r3, r3 + relocateOne(Loc + 4 + EndianOffset, R_PPC64_TPREL16_LO, Val); + break; + default: + llvm_unreachable("unsupported relocation for TLS GD to LE relaxation"); + } +} + + +void PPC64::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { + // Reference: 3.7.4.3 of the 64-bit ELF V2 abi supplement. + // The local dynamic code sequence for a global `x` will look like: + // Instruction Relocation Symbol + // addis r3, r2, x@got@tlsld@ha R_PPC64_GOT_TLSLD16_HA x + // addi r3, r3, x@got@tlsld@l R_PPC64_GOT_TLSLD16_LO x + // bl __tls_get_addr(x@tlsgd) R_PPC64_TLSLD x + // R_PPC64_REL24 __tls_get_addr + // nop None None + + // Relaxing to local exec entails converting: + // addis r3, r2, x@got@tlsld@ha into nop + // addi r3, r3, x@got@tlsld@l into addis r3, r13, 0 + // bl __tls_get_addr(x@tlsgd) into nop + // nop into addi r3, r3, 4096 + + uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U; + switch (Type) { + case R_PPC64_GOT_TLSLD16_HA: + write32(Loc - EndianOffset, 0x60000000); // nop + break; + case R_PPC64_GOT_TLSLD16_LO: + write32(Loc - EndianOffset, 0x3c6d0000); // addis r3, r13, 0 + break; + case R_PPC64_TLSLD: + write32(Loc, 0x60000000); // nop + write32(Loc + 4, 0x38631000); // addi r3, r3, 4096 + break; + case R_PPC64_DTPREL16: + case R_PPC64_DTPREL16_HA: + case R_PPC64_DTPREL16_HI: + case R_PPC64_DTPREL16_DS: + case R_PPC64_DTPREL16_LO: + case R_PPC64_DTPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_DS: + case R_PPC64_GOT_DTPREL16_HI: + relocateOne(Loc, Type, Val); + break; + default: + llvm_unreachable("unsupported relocation for TLS LD to LE relaxation"); + } } RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, @@ -95,48 +225,162 @@ RelExpr PPC64::getRelExpr(RelType Type, const Symbol &S, case R_PPC64_TOC: return R_PPC_TOC; case R_PPC64_REL24: - return R_PPC_PLT_OPD; + return R_PPC_CALL_PLT; + case R_PPC64_REL16_LO: + case R_PPC64_REL16_HA: + case R_PPC64_REL32: + case R_PPC64_REL64: + return R_PC; + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSGD16_LO: + return R_TLSGD_GOT; + case R_PPC64_GOT_TLSLD16: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TLSLD16_HI: + case R_PPC64_GOT_TLSLD16_LO: + return R_TLSLD_GOT; + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_TPREL16_DS: + case R_PPC64_GOT_TPREL16_HI: + return R_GOT_OFF; + case R_PPC64_GOT_DTPREL16_HA: + case R_PPC64_GOT_DTPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_DS: + case R_PPC64_GOT_DTPREL16_HI: + return R_TLSLD_GOT_OFF; + case R_PPC64_TPREL16: + case R_PPC64_TPREL16_HA: + case R_PPC64_TPREL16_LO: + case R_PPC64_TPREL16_HI: + case R_PPC64_TPREL16_DS: + case R_PPC64_TPREL16_LO_DS: + case R_PPC64_TPREL16_HIGHER: + case R_PPC64_TPREL16_HIGHERA: + case R_PPC64_TPREL16_HIGHEST: + case R_PPC64_TPREL16_HIGHESTA: + return R_TLS; + case R_PPC64_DTPREL16: + case R_PPC64_DTPREL16_DS: + case R_PPC64_DTPREL16_HA: + case R_PPC64_DTPREL16_HI: + case R_PPC64_DTPREL16_HIGHER: + case R_PPC64_DTPREL16_HIGHERA: + case R_PPC64_DTPREL16_HIGHEST: + case R_PPC64_DTPREL16_HIGHESTA: + case R_PPC64_DTPREL16_LO: + case R_PPC64_DTPREL16_LO_DS: + case R_PPC64_DTPREL64: + return R_ABS; + case R_PPC64_TLSGD: + return R_TLSDESC_CALL; + case R_PPC64_TLSLD: + return R_TLSLD_HINT; + case R_PPC64_TLS: + return R_HINT; default: return R_ABS; } } +void PPC64::writeGotHeader(uint8_t *Buf) const { + write64(Buf, getPPC64TocBase()); +} + +void PPC64::writePltHeader(uint8_t *Buf) const { + // The generic resolver stub goes first. + write32(Buf + 0, 0x7c0802a6); // mflr r0 + write32(Buf + 4, 0x429f0005); // bcl 20,4*cr7+so,8 <_glink+0x8> + write32(Buf + 8, 0x7d6802a6); // mflr r11 + write32(Buf + 12, 0x7c0803a6); // mtlr r0 + write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12 + write32(Buf + 20, 0x380cffcc); // subi r0,r12,52 + write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2 + write32(Buf + 28, 0xe98b002c); // ld r12,44(r11) + write32(Buf + 32, 0x7d6c5a14); // add r11,r12,r11 + write32(Buf + 36, 0xe98b0000); // ld r12,0(r11) + write32(Buf + 40, 0xe96b0008); // ld r11,8(r11) + write32(Buf + 44, 0x7d8903a6); // mtctr r12 + write32(Buf + 48, 0x4e800420); // bctr + + // The 'bcl' instruction will set the link register to the address of the + // following instruction ('mflr r11'). Here we store the offset from that + // instruction to the first entry in the GotPlt section. + int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8); + write64(Buf + 52, GotPltOffset); +} + void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, int32_t Index, unsigned RelOff) const { - uint64_t Off = GotPltEntryAddr - getPPC64TocBase(); - - // FIXME: What we should do, in theory, is get the offset of the function - // descriptor in the .opd section, and use that as the offset from %r2 (the - // TOC-base pointer). Instead, we have the GOT-entry offset, and that will - // be a pointer to the function descriptor in the .opd section. Using - // this scheme is simpler, but requires an extra indirection per PLT dispatch. - - write32be(Buf, 0xf8410028); // std %r2, 40(%r1) - write32be(Buf + 4, 0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X@ha - write32be(Buf + 8, 0xe98b0000 | applyPPCLo(Off)); // ld %r12, X@l(%r11) - write32be(Buf + 12, 0xe96c0000); // ld %r11,0(%r12) - write32be(Buf + 16, 0x7d6903a6); // mtctr %r11 - write32be(Buf + 20, 0xe84c0008); // ld %r2,8(%r12) - write32be(Buf + 24, 0xe96c0010); // ld %r11,16(%r12) - write32be(Buf + 28, 0x4e800420); // bctr + int32_t Offset = PltHeaderSize + Index * PltEntrySize; + // bl __glink_PLTresolve + write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc)); } static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) { - uint64_t V = Val - PPC64TocOffset; + // Relocations relative to the toc-base need to be adjusted by the Toc offset. + uint64_t TocBiasedVal = Val - PPC64TocOffset; + // Relocations relative to dtv[dtpmod] need to be adjusted by the DTP offset. + uint64_t DTPBiasedVal = Val - DynamicThreadPointerOffset; + switch (Type) { + // TOC biased relocation. + case R_PPC64_GOT_TLSGD16: + case R_PPC64_GOT_TLSLD16: case R_PPC64_TOC16: - return {R_PPC64_ADDR16, V}; + return {R_PPC64_ADDR16, TocBiasedVal}; case R_PPC64_TOC16_DS: - return {R_PPC64_ADDR16_DS, V}; + case R_PPC64_GOT_TPREL16_DS: + case R_PPC64_GOT_DTPREL16_DS: + return {R_PPC64_ADDR16_DS, TocBiasedVal}; + case R_PPC64_GOT_TLSGD16_HA: + case R_PPC64_GOT_TLSLD16_HA: + case R_PPC64_GOT_TPREL16_HA: + case R_PPC64_GOT_DTPREL16_HA: case R_PPC64_TOC16_HA: - return {R_PPC64_ADDR16_HA, V}; + return {R_PPC64_ADDR16_HA, TocBiasedVal}; + case R_PPC64_GOT_TLSGD16_HI: + case R_PPC64_GOT_TLSLD16_HI: + case R_PPC64_GOT_TPREL16_HI: + case R_PPC64_GOT_DTPREL16_HI: case R_PPC64_TOC16_HI: - return {R_PPC64_ADDR16_HI, V}; + return {R_PPC64_ADDR16_HI, TocBiasedVal}; + case R_PPC64_GOT_TLSGD16_LO: + case R_PPC64_GOT_TLSLD16_LO: case R_PPC64_TOC16_LO: - return {R_PPC64_ADDR16_LO, V}; + return {R_PPC64_ADDR16_LO, TocBiasedVal}; case R_PPC64_TOC16_LO_DS: - return {R_PPC64_ADDR16_LO_DS, V}; + case R_PPC64_GOT_TPREL16_LO_DS: + case R_PPC64_GOT_DTPREL16_LO_DS: + return {R_PPC64_ADDR16_LO_DS, TocBiasedVal}; + + // Dynamic Thread pointer biased relocation types. + case R_PPC64_DTPREL16: + return {R_PPC64_ADDR16, DTPBiasedVal}; + case R_PPC64_DTPREL16_DS: + return {R_PPC64_ADDR16_DS, DTPBiasedVal}; + case R_PPC64_DTPREL16_HA: + return {R_PPC64_ADDR16_HA, DTPBiasedVal}; + case R_PPC64_DTPREL16_HI: + return {R_PPC64_ADDR16_HI, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHER: + return {R_PPC64_ADDR16_HIGHER, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHERA: + return {R_PPC64_ADDR16_HIGHERA, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHEST: + return {R_PPC64_ADDR16_HIGHEST, DTPBiasedVal}; + case R_PPC64_DTPREL16_HIGHESTA: + return {R_PPC64_ADDR16_HIGHESTA, DTPBiasedVal}; + case R_PPC64_DTPREL16_LO: + return {R_PPC64_ADDR16_LO, DTPBiasedVal}; + case R_PPC64_DTPREL16_LO_DS: + return {R_PPC64_ADDR16_LO_DS, DTPBiasedVal}; + case R_PPC64_DTPREL64: + return {R_PPC64_ADDR64, DTPBiasedVal}; + default: return {Type, Val}; } @@ -149,68 +393,139 @@ void PPC64::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_PPC64_ADDR14: { - checkAlignment<4>(Loc, Val, Type); + checkAlignment(Loc, Val, 4, Type); // Preserve the AA/LK bits in the branch instruction uint8_t AALK = Loc[3]; - write16be(Loc + 2, (AALK & 3) | (Val & 0xfffc)); + write16(Loc + 2, (AALK & 3) | (Val & 0xfffc)); break; } case R_PPC64_ADDR16: - checkInt<16>(Loc, Val, Type); - write16be(Loc, Val); + case R_PPC64_TPREL16: + checkInt(Loc, Val, 16, Type); + write16(Loc, Val); break; case R_PPC64_ADDR16_DS: - checkInt<16>(Loc, Val, Type); - write16be(Loc, (read16be(Loc) & 3) | (Val & ~3)); + case R_PPC64_TPREL16_DS: + checkInt(Loc, Val, 16, Type); + write16(Loc, (read16(Loc) & 3) | (Val & ~3)); break; case R_PPC64_ADDR16_HA: case R_PPC64_REL16_HA: - write16be(Loc, applyPPCHa(Val)); + case R_PPC64_TPREL16_HA: + write16(Loc, ha(Val)); break; case R_PPC64_ADDR16_HI: case R_PPC64_REL16_HI: - write16be(Loc, applyPPCHi(Val)); + case R_PPC64_TPREL16_HI: + write16(Loc, hi(Val)); break; case R_PPC64_ADDR16_HIGHER: - write16be(Loc, applyPPCHigher(Val)); + case R_PPC64_TPREL16_HIGHER: + write16(Loc, higher(Val)); break; case R_PPC64_ADDR16_HIGHERA: - write16be(Loc, applyPPCHighera(Val)); + case R_PPC64_TPREL16_HIGHERA: + write16(Loc, highera(Val)); break; case R_PPC64_ADDR16_HIGHEST: - write16be(Loc, applyPPCHighest(Val)); + case R_PPC64_TPREL16_HIGHEST: + write16(Loc, highest(Val)); break; case R_PPC64_ADDR16_HIGHESTA: - write16be(Loc, applyPPCHighesta(Val)); + case R_PPC64_TPREL16_HIGHESTA: + write16(Loc, highesta(Val)); break; case R_PPC64_ADDR16_LO: - write16be(Loc, applyPPCLo(Val)); + case R_PPC64_REL16_LO: + case R_PPC64_TPREL16_LO: + write16(Loc, lo(Val)); break; case R_PPC64_ADDR16_LO_DS: - case R_PPC64_REL16_LO: - write16be(Loc, (read16be(Loc) & 3) | (applyPPCLo(Val) & ~3)); + case R_PPC64_TPREL16_LO_DS: + write16(Loc, (read16(Loc) & 3) | (lo(Val) & ~3)); break; case R_PPC64_ADDR32: case R_PPC64_REL32: - checkInt<32>(Loc, Val, Type); - write32be(Loc, Val); + checkInt(Loc, Val, 32, Type); + write32(Loc, Val); break; case R_PPC64_ADDR64: case R_PPC64_REL64: case R_PPC64_TOC: - write64be(Loc, Val); + write64(Loc, Val); break; case R_PPC64_REL24: { uint32_t Mask = 0x03FFFFFC; - checkInt<24>(Loc, Val, Type); - write32be(Loc, (read32be(Loc) & ~Mask) | (Val & Mask)); + checkInt(Loc, Val, 24, Type); + write32(Loc, (read32(Loc) & ~Mask) | (Val & Mask)); break; } + case R_PPC64_DTPREL64: + write64(Loc, Val - DynamicThreadPointerOffset); + break; default: error(getErrorLocation(Loc) + "unrecognized reloc " + Twine(Type)); } } +bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, + uint64_t BranchAddr, const Symbol &S) const { + // If a function is in the plt it needs to be called through + // a call stub. + return Type == R_PPC64_REL24 && S.isInPlt(); +} + +RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data, + RelExpr Expr) const { + if (Expr == R_RELAX_TLS_GD_TO_IE) + return R_RELAX_TLS_GD_TO_IE_GOT_OFF; + if (Expr == R_RELAX_TLS_LD_TO_LE) + return R_RELAX_TLS_LD_TO_LE_ABS; + return Expr; +} + +// Reference: 3.7.4.1 of the 64-bit ELF V2 abi supplement. +// The general dynamic code sequence for a global `x` uses 4 instructions. +// Instruction Relocation Symbol +// addis r3, r2, x@got@tlsgd@ha R_PPC64_GOT_TLSGD16_HA x +// addi r3, r3, x@got@tlsgd@l R_PPC64_GOT_TLSGD16_LO x +// bl __tls_get_addr(x@tlsgd) R_PPC64_TLSGD x +// R_PPC64_REL24 __tls_get_addr +// nop None None +// +// Relaxing to initial-exec entails: +// 1) Convert the addis/addi pair that builds the address of the tls_index +// struct for 'x' to an addis/ld pair that loads an offset from a got-entry. +// 2) Convert the call to __tls_get_addr to a nop. +// 3) Convert the nop following the call to an add of the loaded offset to the +// thread pointer. +// Since the nop must directly follow the call, the R_PPC64_TLSGD relocation is +// used as the relaxation hint for both steps 2 and 3. +void PPC64::relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const { + switch (Type) { + case R_PPC64_GOT_TLSGD16_HA: + // This is relaxed from addis rT, r2, sym@got@tlsgd@ha to + // addis rT, r2, sym@got@tprel@ha. + relocateOne(Loc, R_PPC64_GOT_TPREL16_HA, Val); + return; + case R_PPC64_GOT_TLSGD16_LO: { + // Relax from addi r3, rA, sym@got@tlsgd@l to + // ld r3, sym@got@tprel@l(rA) + uint32_t EndianOffset = Config->EKind == ELF64BEKind ? 2U : 0U; + uint32_t InputRegister = (read32(Loc - EndianOffset) & (0x1f << 16)); + write32(Loc - EndianOffset, 0xE8600000 | InputRegister); + relocateOne(Loc, R_PPC64_GOT_TPREL16_LO_DS, Val); + return; + } + case R_PPC64_TLSGD: + write32(Loc, 0x60000000); // bl __tls_get_addr(sym@tlsgd) --> nop + write32(Loc + 4, 0x7c636A14); // nop --> add r3, r3, r13 + return; + default: + llvm_unreachable("unsupported relocation for TLS GD to IE relaxation"); + } +} + TargetInfo *elf::getPPC64TargetInfo() { static PPC64 Target; return &Target; diff --git a/ELF/Arch/SPARCV9.cpp b/ELF/Arch/SPARCV9.cpp index d9d6e1390407..36f5c836930e 100644 --- a/ELF/Arch/SPARCV9.cpp +++ b/ELF/Arch/SPARCV9.cpp @@ -77,23 +77,23 @@ void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_SPARC_32: case R_SPARC_UA32: // V-word32 - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); write32be(Loc, Val); break; case R_SPARC_DISP32: // V-disp32 - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32be(Loc, Val); break; case R_SPARC_WDISP30: case R_SPARC_WPLT30: // V-disp30 - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32be(Loc, (read32be(Loc) & ~0x3fffffff) | ((Val >> 2) & 0x3fffffff)); break; case R_SPARC_22: // V-imm22 - checkUInt<22>(Loc, Val, Type); + checkUInt(Loc, Val, 22, Type); write32be(Loc, (read32be(Loc) & ~0x003fffff) | (Val & 0x003fffff)); break; case R_SPARC_GOT22: @@ -103,7 +103,7 @@ void SPARCV9::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { break; case R_SPARC_WDISP19: // V-disp19 - checkInt<21>(Loc, Val, Type); + checkInt(Loc, Val, 21, Type); write32be(Loc, (read32be(Loc) & ~0x0007ffff) | ((Val >> 2) & 0x0007ffff)); break; case R_SPARC_GOT10: @@ -137,7 +137,7 @@ void SPARCV9::writePlt(uint8_t *Buf, uint64_t GotEntryAddr, }; memcpy(Buf, PltData, sizeof(PltData)); - uint64_t Off = PltHeaderSize + Index * PltEntrySize; + uint64_t Off = getPltEntryOffset(Index); relocateOne(Buf, R_SPARC_22, Off); relocateOne(Buf + 4, R_SPARC_WDISP19, -(Off + 4 - PltEntrySize)); } diff --git a/ELF/Arch/X86.cpp b/ELF/Arch/X86.cpp index 10517bef14f3..19a0b6017f1a 100644 --- a/ELF/Arch/X86.cpp +++ b/ELF/Arch/X86.cpp @@ -21,7 +21,7 @@ using namespace lld; using namespace lld::elf; namespace { -class X86 final : public TargetInfo { +class X86 : public TargetInfo { public: X86(); RelExpr getRelExpr(RelType Type, const Symbol &S, @@ -46,7 +46,6 @@ public: } // namespace X86::X86() { - GotBaseSymOff = -1; CopyRel = R_386_COPY; GotRel = R_386_GLOB_DAT; PltRel = R_386_JUMP_SLOT; @@ -74,9 +73,9 @@ RelExpr X86::getRelExpr(RelType Type, const Symbol &S, case R_386_TLS_LDO_32: return R_ABS; case R_386_TLS_GD: - return R_TLSGD; + return R_TLSGD_GOT_FROM_END; case R_386_TLS_LDM: - return R_TLSLD; + return R_TLSLD_GOT_FROM_END; case R_386_PLT32: return R_PLT_PC; case R_386_PC8: @@ -224,7 +223,7 @@ void X86::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, } write32le(Buf + 7, RelOff); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); + write32le(Buf + 12, -getPltEntryOffset(Index) - 16); } int64_t X86::getImplicitAddend(const uint8_t *Buf, RelType Type) const { @@ -256,15 +255,15 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { // R_386_{PC,}{8,16} are not part of the i386 psABI, but they are // being used for some 16-bit programs such as boot loaders, so // we want to support them. - checkUInt<8>(Loc, Val, Type); + checkIntUInt(Loc, Val, 8, Type); *Loc = Val; break; case R_386_PC8: - checkInt<8>(Loc, Val, Type); + checkInt(Loc, Val, 8, Type); *Loc = Val; break; case R_386_16: - checkUInt<16>(Loc, Val, Type); + checkIntUInt(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_386_PC16: @@ -278,7 +277,7 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { // current location subtracted from it. // We just check that Val fits in 17 bits. This misses some cases, but // should have no false positives. - checkInt<17>(Loc, Val, Type); + checkInt(Loc, Val, 17, Type); write16le(Loc, Val); break; case R_386_32: @@ -301,7 +300,7 @@ void X86::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_386_TLS_LE_32: case R_386_TLS_TPOFF: case R_386_TLS_TPOFF32: - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32le(Loc, Val); break; default: @@ -399,7 +398,152 @@ void X86::relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const { memcpy(Loc - 2, Inst, sizeof(Inst)); } +namespace { +class RetpolinePic : public X86 { +public: + RetpolinePic(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; + +class RetpolineNoPic : public X86 { +public: + RetpolineNoPic(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; +} // namespace + +RetpolinePic::RetpolinePic() { + PltHeaderSize = 48; + PltEntrySize = 32; +} + +void RetpolinePic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 17); +} + +void RetpolinePic::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xff, 0xb3, 0, 0, 0, 0, // 0: pushl GOTPLT+4(%ebx) + 0x50, // 6: pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // 7: mov GOTPLT+8(%ebx), %eax + 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: call next + 0xf3, 0x90, // 12: loop: pause + 0x0f, 0xae, 0xe8, // 14: lfence + 0xeb, 0xf9, // 17: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 + 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) + 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx + 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) + 0x89, 0xc8, // 2b: mov %ecx, %eax + 0x59, // 2d: pop %ecx + 0xc3, // 2e: ret + 0xcc, // 2f: int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + uint32_t GotPlt = InX::GotPlt->getVA() - Ebx; + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 9, GotPlt + 8); +} + +void RetpolinePic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x50, // pushl %eax + 0x8b, 0x83, 0, 0, 0, 0, // mov foo@GOT(%ebx), %eax + 0xe8, 0, 0, 0, 0, // call plt+0x20 + 0xe9, 0, 0, 0, 0, // jmp plt+0x12 + 0x68, 0, 0, 0, 0, // pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t Ebx = InX::Got->getVA() + InX::Got->getSize(); + unsigned Off = getPltEntryOffset(Index); + write32le(Buf + 3, GotPltEntryAddr - Ebx); + write32le(Buf + 8, -Off - 12 + 32); + write32le(Buf + 13, -Off - 17 + 18); + write32le(Buf + 18, RelOff); + write32le(Buf + 23, -Off - 27); +} + +RetpolineNoPic::RetpolineNoPic() { + PltHeaderSize = 48; + PltEntrySize = 32; +} + +void RetpolineNoPic::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write32le(Buf, S.getPltVA() + 16); +} + +void RetpolineNoPic::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xff, 0x35, 0, 0, 0, 0, // 0: pushl GOTPLT+4 + 0x50, // 6: pushl %eax + 0xa1, 0, 0, 0, 0, // 7: mov GOTPLT+8, %eax + 0xe8, 0x0f, 0x00, 0x00, 0x00, // c: call next + 0xf3, 0x90, // 11: loop: pause + 0x0f, 0xae, 0xe8, // 13: lfence + 0xeb, 0xf9, // 16: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 18: int3 + 0xcc, 0xcc, 0xcc, // 1f: int3; .align 16 + 0x89, 0x0c, 0x24, // 20: next: mov %ecx, (%esp) + 0x8b, 0x4c, 0x24, 0x04, // 23: mov 0x4(%esp), %ecx + 0x89, 0x44, 0x24, 0x04, // 27: mov %eax ,0x4(%esp) + 0x89, 0xc8, // 2b: mov %ecx, %eax + 0x59, // 2d: pop %ecx + 0xc3, // 2e: ret + 0xcc, // 2f: int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint32_t GotPlt = InX::GotPlt->getVA(); + write32le(Buf + 2, GotPlt + 4); + write32le(Buf + 8, GotPlt + 8); +} + +void RetpolineNoPic::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x50, // 0: pushl %eax + 0xa1, 0, 0, 0, 0, // 1: mov foo_in_GOT, %eax + 0xe8, 0, 0, 0, 0, // 6: call plt+0x20 + 0xe9, 0, 0, 0, 0, // b: jmp plt+0x11 + 0x68, 0, 0, 0, 0, // 10: pushl $reloc_offset + 0xe9, 0, 0, 0, 0, // 15: jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding + 0xcc, // 1f: int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); + + unsigned Off = getPltEntryOffset(Index); + write32le(Buf + 2, GotPltEntryAddr); + write32le(Buf + 7, -Off - 11 + 32); + write32le(Buf + 12, -Off - 16 + 17); + write32le(Buf + 17, RelOff); + write32le(Buf + 22, -Off - 26); +} + TargetInfo *elf::getX86TargetInfo() { - static X86 Target; - return &Target; + if (Config->ZRetpolineplt) { + if (Config->Pic) { + static RetpolinePic T; + return &T; + } + static RetpolineNoPic T; + return &T; + } + + static X86 T; + return &T; } diff --git a/ELF/Arch/X86_64.cpp b/ELF/Arch/X86_64.cpp index c977d9247d92..d4bdb3730c58 100644 --- a/ELF/Arch/X86_64.cpp +++ b/ELF/Arch/X86_64.cpp @@ -23,12 +23,12 @@ using namespace lld; using namespace lld::elf; namespace { -template <class ELFT> class X86_64 final : public TargetInfo { +template <class ELFT> class X86_64 : public TargetInfo { public: X86_64(); RelExpr getRelExpr(RelType Type, const Symbol &S, const uint8_t *Loc) const override; - bool isPicRel(RelType Type) const override; + RelType getDynRel(RelType Type) const override; void writeGotPltHeader(uint8_t *Buf) const override; void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; void writePltHeader(uint8_t *Buf) const override; @@ -43,6 +43,8 @@ public: void relaxTlsGdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsIeToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; void relaxTlsLdToLe(uint8_t *Loc, RelType Type, uint64_t Val) const override; + bool adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const override; private: void relaxGotNoPic(uint8_t *Loc, uint64_t Val, uint8_t Op, @@ -51,7 +53,6 @@ private: } // namespace template <class ELFT> X86_64<ELFT>::X86_64() { - GotBaseSymOff = -1; CopyRel = R_X86_64_COPY; GotRel = R_X86_64_GLOB_DAT; PltRel = R_X86_64_JUMP_SLOT; @@ -106,6 +107,11 @@ RelExpr X86_64<ELFT>::getRelExpr(RelType Type, const Symbol &S, case R_X86_64_REX_GOTPCRELX: case R_X86_64_GOTTPOFF: return R_GOT_PC; + case R_X86_64_GOTOFF64: + return R_GOTREL_FROM_END; + case R_X86_64_GOTPC32: + case R_X86_64_GOTPC64: + return R_GOTONLY_PC_FROM_END; case R_X86_64_NONE: return R_NONE; default: @@ -124,7 +130,7 @@ template <class ELFT> void X86_64<ELFT>::writeGotPltHeader(uint8_t *Buf) const { template <class ELFT> void X86_64<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const { // See comments in X86::writeGotPlt. - write32le(Buf, S.getPltVA() + 6); + write64le(Buf, S.getPltVA() + 6); } template <class ELFT> void X86_64<ELFT>::writePltHeader(uint8_t *Buf) const { @@ -153,12 +159,14 @@ void X86_64<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, write32le(Buf + 2, GotPltEntryAddr - PltEntryAddr - 6); write32le(Buf + 7, Index); - write32le(Buf + 12, -Index * PltEntrySize - PltHeaderSize - 16); + write32le(Buf + 12, -getPltEntryOffset(Index) - 16); } -template <class ELFT> bool X86_64<ELFT>::isPicRel(RelType Type) const { - return Type != R_X86_64_PC32 && Type != R_X86_64_32 && - Type != R_X86_64_TPOFF32; +template <class ELFT> RelType X86_64<ELFT>::getDynRel(RelType Type) const { + if (Type == R_X86_64_64 || Type == R_X86_64_PC64 || Type == R_X86_64_SIZE32 || + Type == R_X86_64_SIZE64) + return Type; + return R_X86_64_NONE; } template <class ELFT> @@ -285,20 +293,21 @@ template <class ELFT> void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { switch (Type) { case R_X86_64_8: - checkUInt<8>(Loc, Val, Type); + checkUInt(Loc, Val, 8, Type); *Loc = Val; break; case R_X86_64_16: - checkUInt<16>(Loc, Val, Type); + checkUInt(Loc, Val, 16, Type); write16le(Loc, Val); break; case R_X86_64_32: - checkUInt<32>(Loc, Val, Type); + checkUInt(Loc, Val, 32, Type); write32le(Loc, Val); break; case R_X86_64_32S: case R_X86_64_TPOFF32: case R_X86_64_GOT32: + case R_X86_64_GOTPC32: case R_X86_64_GOTPCREL: case R_X86_64_GOTPCRELX: case R_X86_64_REX_GOTPCRELX: @@ -309,7 +318,7 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_X86_64_TLSLD: case R_X86_64_DTPOFF32: case R_X86_64_SIZE32: - checkInt<32>(Loc, Val, Type); + checkInt(Loc, Val, 32, Type); write32le(Loc, Val); break; case R_X86_64_64: @@ -318,6 +327,8 @@ void X86_64<ELFT>::relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const { case R_X86_64_PC64: case R_X86_64_SIZE64: case R_X86_64_GOT64: + case R_X86_64_GOTOFF64: + case R_X86_64_GOTPC64: write64le(Loc, Val); break; default: @@ -460,12 +471,180 @@ void X86_64<ELFT>::relaxGot(uint8_t *Loc, uint64_t Val) const { write32le(Loc - 1, Val + 1); } -TargetInfo *elf::getX32TargetInfo() { - static X86_64<ELF32LE> Target; - return &Target; +// This anonymous namespace works around a warning bug in +// old versions of gcc. See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 +namespace { + +// A split-stack prologue starts by checking the amount of stack remaining +// in one of two ways: +// A) Comparing of the stack pointer to a field in the tcb. +// B) Or a load of a stack pointer offset with an lea to r10 or r11. +template <> +bool X86_64<ELF64LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const { + // Replace "cmp %fs:0x70,%rsp" and subsequent branch + // with "stc, nopl 0x0(%rax,%rax,1)" + if (Loc + 8 < End && memcmp(Loc, "\x64\x48\x3b\x24\x25", 4) == 0) { + memcpy(Loc, "\xf9\x0f\x1f\x84\x00\x00\x00\x00", 8); + return true; + } + + // Adjust "lea -0x200(%rsp),%r10" to lea "-0x4200(%rsp),%r10" + if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x94\x24\x00\xfe\xff", 7) == 0) { + memcpy(Loc, "\x4c\x8d\x94\x24\x00\xbe\xff", 7); + return true; + } + + // Adjust "lea -0x200(%rsp),%r11" to lea "-0x4200(%rsp),%r11" + if (Loc + 7 < End && memcmp(Loc, "\x4c\x8d\x9c\x24\x00\xfe\xff", 7) == 0) { + memcpy(Loc, "\x4c\x8d\x9c\x24\x00\xbe\xff", 7); + return true; + } + return false; +} + +template <> +bool X86_64<ELF32LE>::adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const { + llvm_unreachable("Target doesn't support split stacks."); +} + +} // namespace + +// These nonstandard PLT entries are to migtigate Spectre v2 security +// vulnerability. In order to mitigate Spectre v2, we want to avoid indirect +// branch instructions such as `jmp *GOTPLT(%rip)`. So, in the following PLT +// entries, we use a CALL followed by MOV and RET to do the same thing as an +// indirect jump. That instruction sequence is so-called "retpoline". +// +// We have two types of retpoline PLTs as a size optimization. If `-z now` +// is specified, all dynamic symbols are resolved at load-time. Thus, when +// that option is given, we can omit code for symbol lazy resolution. +namespace { +template <class ELFT> class Retpoline : public X86_64<ELFT> { +public: + Retpoline(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override; + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; + +template <class ELFT> class RetpolineZNow : public X86_64<ELFT> { +public: + RetpolineZNow(); + void writeGotPlt(uint8_t *Buf, const Symbol &S) const override {} + void writePltHeader(uint8_t *Buf) const override; + void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr, + int32_t Index, unsigned RelOff) const override; +}; +} // namespace + +template <class ELFT> Retpoline<ELFT>::Retpoline() { + TargetInfo::PltHeaderSize = 48; + TargetInfo::PltEntrySize = 32; } -TargetInfo *elf::getX86_64TargetInfo() { - static X86_64<ELF64LE> Target; - return &Target; +template <class ELFT> +void Retpoline<ELFT>::writeGotPlt(uint8_t *Buf, const Symbol &S) const { + write64le(Buf, S.getPltVA() + 17); +} + +template <class ELFT> void Retpoline<ELFT>::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xff, 0x35, 0, 0, 0, 0, // 0: pushq GOTPLT+8(%rip) + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 6: mov GOTPLT+16(%rip), %r11 + 0xe8, 0x0e, 0x00, 0x00, 0x00, // d: callq next + 0xf3, 0x90, // 12: loop: pause + 0x0f, 0xae, 0xe8, // 14: lfence + 0xeb, 0xf9, // 17: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 19: int3; .align 16 + 0x4c, 0x89, 0x1c, 0x24, // 20: next: mov %r11, (%rsp) + 0xc3, // 24: ret + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 25: int3; padding + 0xcc, 0xcc, 0xcc, 0xcc, // 2c: int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint64_t GotPlt = InX::GotPlt->getVA(); + uint64_t Plt = InX::Plt->getVA(); + write32le(Buf + 2, GotPlt - Plt - 6 + 8); + write32le(Buf + 9, GotPlt - Plt - 13 + 16); +} + +template <class ELFT> +void Retpoline<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // 0: mov foo@GOTPLT(%rip), %r11 + 0xe8, 0, 0, 0, 0, // 7: callq plt+0x20 + 0xe9, 0, 0, 0, 0, // c: jmp plt+0x12 + 0x68, 0, 0, 0, 0, // 11: pushq <relocation index> + 0xe9, 0, 0, 0, 0, // 16: jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1b: int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); + + uint64_t Off = TargetInfo::getPltEntryOffset(Index); + + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, -Off - 12 + 32); + write32le(Buf + 13, -Off - 17 + 18); + write32le(Buf + 18, Index); + write32le(Buf + 23, -Off - 27); +} + +template <class ELFT> RetpolineZNow<ELFT>::RetpolineZNow() { + TargetInfo::PltHeaderSize = 32; + TargetInfo::PltEntrySize = 16; } + +template <class ELFT> +void RetpolineZNow<ELFT>::writePltHeader(uint8_t *Buf) const { + const uint8_t Insn[] = { + 0xe8, 0x0b, 0x00, 0x00, 0x00, // 0: call next + 0xf3, 0x90, // 5: loop: pause + 0x0f, 0xae, 0xe8, // 7: lfence + 0xeb, 0xf9, // a: jmp loop + 0xcc, 0xcc, 0xcc, 0xcc, // c: int3; .align 16 + 0x4c, 0x89, 0x1c, 0x24, // 10: next: mov %r11, (%rsp) + 0xc3, // 14: ret + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 15: int3; padding + 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, // 1a: int3; padding + 0xcc, // 1f: int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); +} + +template <class ELFT> +void RetpolineZNow<ELFT>::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, + uint64_t PltEntryAddr, int32_t Index, + unsigned RelOff) const { + const uint8_t Insn[] = { + 0x4c, 0x8b, 0x1d, 0, 0, 0, 0, // mov foo@GOTPLT(%rip), %r11 + 0xe9, 0, 0, 0, 0, // jmp plt+0 + 0xcc, 0xcc, 0xcc, 0xcc, // int3; padding + }; + memcpy(Buf, Insn, sizeof(Insn)); + + write32le(Buf + 3, GotPltEntryAddr - PltEntryAddr - 7); + write32le(Buf + 8, -TargetInfo::getPltEntryOffset(Index) - 12); +} + +template <class ELFT> static TargetInfo *getTargetInfo() { + if (Config->ZRetpolineplt) { + if (Config->ZNow) { + static RetpolineZNow<ELFT> T; + return &T; + } + static Retpoline<ELFT> T; + return &T; + } + + static X86_64<ELFT> T; + return &T; +} + +TargetInfo *elf::getX32TargetInfo() { return getTargetInfo<ELF32LE>(); } +TargetInfo *elf::getX86_64TargetInfo() { return getTargetInfo<ELF64LE>(); } diff --git a/ELF/CMakeLists.txt b/ELF/CMakeLists.txt index 7ec837841315..fb2f53a72025 100644 --- a/ELF/CMakeLists.txt +++ b/ELF/CMakeLists.txt @@ -12,6 +12,7 @@ add_lld_library(lldELF Arch/AMDGPU.cpp Arch/ARM.cpp Arch/AVR.cpp + Arch/Hexagon.cpp Arch/Mips.cpp Arch/MipsArchTree.cpp Arch/PPC.cpp @@ -19,6 +20,7 @@ add_lld_library(lldELF Arch/SPARCV9.cpp Arch/X86.cpp Arch/X86_64.cpp + CallGraphSort.cpp Driver.cpp DriverUtils.cpp EhFrame.cpp @@ -35,7 +37,6 @@ add_lld_library(lldELF Relocations.cpp ScriptLexer.cpp ScriptParser.cpp - Strings.cpp SymbolTable.cpp Symbols.cpp SyntheticSections.cpp @@ -46,6 +47,7 @@ add_lld_library(lldELF LINK_COMPONENTS ${LLVM_TARGETS_TO_BUILD} BinaryFormat + BitWriter Core DebugInfoDWARF LTO diff --git a/ELF/CallGraphSort.cpp b/ELF/CallGraphSort.cpp new file mode 100644 index 000000000000..33ac159a6e26 --- /dev/null +++ b/ELF/CallGraphSort.cpp @@ -0,0 +1,249 @@ +//===- CallGraphSort.cpp --------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// Implementation of Call-Chain Clustering from: Optimizing Function Placement +/// for Large-Scale Data-Center Applications +/// https://research.fb.com/wp-content/uploads/2017/01/cgo2017-hfsort-final1.pdf +/// +/// The goal of this algorithm is to improve runtime performance of the final +/// executable by arranging code sections such that page table and i-cache +/// misses are minimized. +/// +/// Definitions: +/// * Cluster +/// * An ordered list of input sections which are layed out as a unit. At the +/// beginning of the algorithm each input section has its own cluster and +/// the weight of the cluster is the sum of the weight of all incomming +/// edges. +/// * Call-Chain Clustering (C³) Heuristic +/// * Defines when and how clusters are combined. Pick the highest weighted +/// input section then add it to its most likely predecessor if it wouldn't +/// penalize it too much. +/// * Density +/// * The weight of the cluster divided by the size of the cluster. This is a +/// proxy for the ammount of execution time spent per byte of the cluster. +/// +/// It does so given a call graph profile by the following: +/// * Build a weighted call graph from the call graph profile +/// * Sort input sections by weight +/// * For each input section starting with the highest weight +/// * Find its most likely predecessor cluster +/// * Check if the combined cluster would be too large, or would have too low +/// a density. +/// * If not, then combine the clusters. +/// * Sort non-empty clusters by density +/// +//===----------------------------------------------------------------------===// + +#include "CallGraphSort.h" +#include "OutputSections.h" +#include "SymbolTable.h" +#include "Symbols.h" + +using namespace llvm; +using namespace lld; +using namespace lld::elf; + +namespace { +struct Edge { + int From; + uint64_t Weight; +}; + +struct Cluster { + Cluster(int Sec, size_t S) { + Sections.push_back(Sec); + Size = S; + } + + double getDensity() const { + if (Size == 0) + return 0; + return double(Weight) / double(Size); + } + + std::vector<int> Sections; + size_t Size = 0; + uint64_t Weight = 0; + uint64_t InitialWeight = 0; + std::vector<Edge> Preds; +}; + +class CallGraphSort { +public: + CallGraphSort(); + + DenseMap<const InputSectionBase *, int> run(); + +private: + std::vector<Cluster> Clusters; + std::vector<const InputSectionBase *> Sections; + + void groupClusters(); +}; + +// Maximum ammount the combined cluster density can be worse than the original +// cluster to consider merging. +constexpr int MAX_DENSITY_DEGRADATION = 8; + +// Maximum cluster size in bytes. +constexpr uint64_t MAX_CLUSTER_SIZE = 1024 * 1024; +} // end anonymous namespace + +// Take the edge list in Config->CallGraphProfile, resolve symbol names to +// Symbols, and generate a graph between InputSections with the provided +// weights. +CallGraphSort::CallGraphSort() { + llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>, + uint64_t> &Profile = Config->CallGraphProfile; + DenseMap<const InputSectionBase *, int> SecToCluster; + + auto GetOrCreateNode = [&](const InputSectionBase *IS) -> int { + auto Res = SecToCluster.insert(std::make_pair(IS, Clusters.size())); + if (Res.second) { + Sections.push_back(IS); + Clusters.emplace_back(Clusters.size(), IS->getSize()); + } + return Res.first->second; + }; + + // Create the graph. + for (const auto &C : Profile) { + const auto *FromSB = cast<InputSectionBase>(C.first.first->Repl); + const auto *ToSB = cast<InputSectionBase>(C.first.second->Repl); + uint64_t Weight = C.second; + + // Ignore edges between input sections belonging to different output + // sections. This is done because otherwise we would end up with clusters + // containing input sections that can't actually be placed adjacently in the + // output. This messes with the cluster size and density calculations. We + // would also end up moving input sections in other output sections without + // moving them closer to what calls them. + if (FromSB->getOutputSection() != ToSB->getOutputSection()) + continue; + + int From = GetOrCreateNode(FromSB); + int To = GetOrCreateNode(ToSB); + + Clusters[To].Weight += Weight; + + if (From == To) + continue; + + // Add an edge + Clusters[To].Preds.push_back({From, Weight}); + } + for (Cluster &C : Clusters) + C.InitialWeight = C.Weight; +} + +// It's bad to merge clusters which would degrade the density too much. +static bool isNewDensityBad(Cluster &A, Cluster &B) { + double NewDensity = double(A.Weight + B.Weight) / double(A.Size + B.Size); + if (NewDensity < A.getDensity() / MAX_DENSITY_DEGRADATION) + return true; + return false; +} + +static void mergeClusters(Cluster &Into, Cluster &From) { + Into.Sections.insert(Into.Sections.end(), From.Sections.begin(), + From.Sections.end()); + Into.Size += From.Size; + Into.Weight += From.Weight; + From.Sections.clear(); + From.Size = 0; + From.Weight = 0; +} + +// Group InputSections into clusters using the Call-Chain Clustering heuristic +// then sort the clusters by density. +void CallGraphSort::groupClusters() { + std::vector<int> SortedSecs(Clusters.size()); + std::vector<Cluster *> SecToCluster(Clusters.size()); + + for (int SI = 0, SE = Clusters.size(); SI != SE; ++SI) { + SortedSecs[SI] = SI; + SecToCluster[SI] = &Clusters[SI]; + } + + std::stable_sort(SortedSecs.begin(), SortedSecs.end(), [&](int A, int B) { + return Clusters[B].getDensity() < Clusters[A].getDensity(); + }); + + for (int SI : SortedSecs) { + // Clusters[SI] is the same as SecToClusters[SI] here because it has not + // been merged into another cluster yet. + Cluster &C = Clusters[SI]; + + int BestPred = -1; + uint64_t BestWeight = 0; + + for (Edge &E : C.Preds) { + if (BestPred == -1 || E.Weight > BestWeight) { + BestPred = E.From; + BestWeight = E.Weight; + } + } + + // don't consider merging if the edge is unlikely. + if (BestWeight * 10 <= C.InitialWeight) + continue; + + Cluster *PredC = SecToCluster[BestPred]; + if (PredC == &C) + continue; + + if (C.Size + PredC->Size > MAX_CLUSTER_SIZE) + continue; + + if (isNewDensityBad(*PredC, C)) + continue; + + // NOTE: Consider using a disjoint-set to track section -> cluster mapping + // if this is ever slow. + for (int SI : C.Sections) + SecToCluster[SI] = PredC; + + mergeClusters(*PredC, C); + } + + // Remove empty or dead nodes. Invalidates all cluster indices. + llvm::erase_if(Clusters, [](const Cluster &C) { + return C.Size == 0 || C.Sections.empty(); + }); + + // Sort by density. + std::stable_sort(Clusters.begin(), Clusters.end(), + [](const Cluster &A, const Cluster &B) { + return A.getDensity() > B.getDensity(); + }); +} + +DenseMap<const InputSectionBase *, int> CallGraphSort::run() { + groupClusters(); + + // Generate order. + llvm::DenseMap<const InputSectionBase *, int> OrderMap; + ssize_t CurOrder = 1; + + for (const Cluster &C : Clusters) + for (int SecIndex : C.Sections) + OrderMap[Sections[SecIndex]] = CurOrder++; + + return OrderMap; +} + +// Sort sections by the profile data provided by -callgraph-profile-file +// +// This first builds a call graph based on the profile data then merges sections +// according to the C³ huristic. All clusters are then sorted by a density +// metric to further improve locality. +DenseMap<const InputSectionBase *, int> elf::computeCallGraphProfileOrder() { + return CallGraphSort().run(); +} diff --git a/ELF/CallGraphSort.h b/ELF/CallGraphSort.h new file mode 100644 index 000000000000..3f96dc88f435 --- /dev/null +++ b/ELF/CallGraphSort.h @@ -0,0 +1,23 @@ +//===- CallGraphSort.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_CALL_GRAPH_SORT_H +#define LLD_ELF_CALL_GRAPH_SORT_H + +#include "llvm/ADT/DenseMap.h" + +namespace lld { +namespace elf { +class InputSectionBase; + +llvm::DenseMap<const InputSectionBase *, int> computeCallGraphProfileOrder(); +} // namespace elf +} // namespace lld + +#endif diff --git a/ELF/Config.h b/ELF/Config.h index 74c325cb7cb1..ec804c5296bc 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -10,6 +10,7 @@ #ifndef LLD_ELF_CONFIG_H #define LLD_ELF_CONFIG_H +#include "lld/Common/ErrorHandler.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" @@ -17,13 +18,13 @@ #include "llvm/Support/CachePruning.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Endian.h" - #include <vector> namespace lld { namespace elf { class InputFile; +class InputSectionBase; enum ELFKind { ELFNoneKind, @@ -39,6 +40,9 @@ enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid }; // For --discard-{all,locals,none}. enum class DiscardPolicy { Default, All, Locals, None }; +// For --icf={none,safe,all}. +enum class ICFLevel { None, Safe, All }; + // For --strip-{all,debug}. enum class StripPolicy { None, All, Debug }; @@ -79,21 +83,27 @@ struct Configuration { llvm::StringMap<uint64_t> SectionStartMap; llvm::StringRef Chroot; llvm::StringRef DynamicLinker; + llvm::StringRef DwoDir; llvm::StringRef Entry; llvm::StringRef Emulation; llvm::StringRef Fini; llvm::StringRef Init; llvm::StringRef LTOAAPipeline; llvm::StringRef LTONewPmPasses; + llvm::StringRef LTOObjPath; + llvm::StringRef LTOSampleProfile; llvm::StringRef MapFile; llvm::StringRef OutputFile; llvm::StringRef OptRemarksFilename; + llvm::StringRef ProgName; llvm::StringRef SoName; llvm::StringRef Sysroot; llvm::StringRef ThinLTOCacheDir; + llvm::StringRef ThinLTOIndexOnlyArg; + std::pair<llvm::StringRef, llvm::StringRef> ThinLTOObjectSuffixReplace; + std::pair<llvm::StringRef, llvm::StringRef> ThinLTOPrefixReplace; std::string Rpath; std::vector<VersionDefinition> VersionDefinitions; - std::vector<llvm::StringRef> Argv; std::vector<llvm::StringRef> AuxiliaryList; std::vector<llvm::StringRef> FilterList; std::vector<llvm::StringRef> SearchPaths; @@ -103,15 +113,20 @@ struct Configuration { std::vector<SymbolVersion> VersionScriptGlobals; std::vector<SymbolVersion> VersionScriptLocals; std::vector<uint8_t> BuildIdVector; + llvm::MapVector<std::pair<const InputSectionBase *, const InputSectionBase *>, + uint64_t> + CallGraphProfile; bool AllowMultipleDefinition; - bool AndroidPackDynRelocs = false; + bool AndroidPackDynRelocs; bool ARMHasBlx = false; bool ARMHasMovtMovw = false; bool ARMJ1J2BranchEncoding = false; bool AsNeeded = false; bool Bsymbolic; bool BsymbolicFunctions; + bool CheckSections; bool CompressDebugSections; + bool Cref; bool DefineCommon; bool Demangle = true; bool DisableVerify; @@ -123,14 +138,15 @@ struct Configuration { bool GcSections; bool GdbIndex; bool GnuHash = false; + bool GnuUnique; bool HasDynamicList = false; bool HasDynSymTab; - bool ICF; - bool ICFData; + bool IgnoreDataAddressEquality; + bool IgnoreFunctionAddressEquality; + bool LTODebugPassManager; + bool LTONewPassManager; bool MergeArmExidx; bool MipsN32Abi = false; - bool NoGnuUnique; - bool NoUndefinedVersion; bool NoinhibitExec; bool Nostdlib; bool OFormatBinary; @@ -138,7 +154,9 @@ struct Configuration { bool OptRemarksWithHotness; bool Pie; bool PrintGcSections; + bool PrintIcfSections; bool Relocatable; + bool RelrPackDynRelocs; bool SaveTemps; bool SingleRoRx; bool Shared; @@ -146,12 +164,21 @@ struct Configuration { bool SysvHash = false; bool Target1Rel; bool Trace; - bool Verbose; + bool ThinLTOEmitImportsFiles; + bool ThinLTOIndexOnly; + bool UndefinedVersion; + bool UseAndroidRelrTags = false; + bool WarnBackrefs; bool WarnCommon; bool WarnMissingEntry; + bool WarnSymbolOrdering; + bool WriteAddends; bool ZCombreloc; + bool ZCopyreloc; bool ZExecstack; - bool ZNocopyreloc; + bool ZHazardplt; + bool ZInitfirst; + bool ZKeepTextSectionPrefix; bool ZNodelete; bool ZNodlopen; bool ZNow; @@ -159,9 +186,10 @@ struct Configuration { bool ZRelro; bool ZRodynamic; bool ZText; - bool ExitEarly; + bool ZRetpolineplt; bool ZWxneeded; DiscardPolicy Discard; + ICFLevel ICF; OrphanHandlingPolicy OrphanHandling; SortSectionPolicy SortSection; StripPolicy Strip; @@ -173,6 +201,7 @@ struct Configuration { uint16_t EMachine = llvm::ELF::EM_NONE; llvm::Optional<uint64_t> ImageBase; uint64_t MaxPageSize; + uint64_t MipsGotSize; uint64_t ZStackSize; unsigned LTOPartitions; unsigned LTOO; @@ -238,6 +267,12 @@ struct Configuration { // The only instance of Configuration struct. extern Configuration *Config; +static inline void errorOrWarn(const Twine &Msg) { + if (!Config->NoinhibitExec) + error(Msg); + else + warn(Msg); +} } // namespace elf } // namespace lld diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index cc76fea2ad5e..1fc552f011b6 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -30,9 +30,9 @@ #include "InputFiles.h" #include "InputSection.h" #include "LinkerScript.h" +#include "MarkLive.h" #include "OutputSections.h" #include "ScriptParser.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" @@ -42,12 +42,16 @@ #include "lld/Common/Driver.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" +#include "lld/Common/TargetOptionsCommandFlags.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compression.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/Path.h" #include "llvm/Support/TarWriter.h" #include "llvm/Support/TargetSelect.h" @@ -66,16 +70,18 @@ using namespace lld::elf; Configuration *elf::Config; LinkerDriver *elf::Driver; -static void setConfigs(); +static void setConfigs(opt::InputArgList &Args); bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Error) { - errorHandler().LogName = Args[0]; + errorHandler().LogName = sys::path::filename(Args[0]); errorHandler().ErrorLimitExceededMsg = "too many errors emitted, stopping now (use " "-error-limit=0 to see all errors)"; errorHandler().ErrorOS = &Error; + errorHandler().ExitEarly = CanExitEarly; errorHandler().ColorDiagnostics = Error.has_colors(); + InputSections.clear(); OutputSections.clear(); Tar = nullptr; @@ -88,14 +94,14 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, Driver = make<LinkerDriver>(); Script = make<LinkerScript>(); Symtab = make<SymbolTable>(); - Config->Argv = {Args.begin(), Args.end()}; + Config->ProgName = Args[0]; - Driver->main(Args, CanExitEarly); + Driver->main(Args); // Exit immediately if we don't need to return to the caller. // This saves time because the overhead of calling destructors // for all globally-allocated objects is not negligible. - if (Config->ExitEarly) + if (CanExitEarly) exitLld(errorCount() ? 1 : 0); freeArena(); @@ -113,7 +119,8 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { std::pair<ELFKind, uint16_t> Ret = StringSwitch<std::pair<ELFKind, uint16_t>>(S) - .Cases("aarch64elf", "aarch64linux", {ELF64LEKind, EM_AARCH64}) + .Cases("aarch64elf", "aarch64linux", "aarch64_elf64_le_vec", + {ELF64LEKind, EM_AARCH64}) .Cases("armelf", "armelf_linux_eabi", {ELF32LEKind, EM_ARM}) .Case("elf32_x86_64", {ELF32LEKind, EM_X86_64}) .Cases("elf32btsmip", "elf32btsmipn32", {ELF32BEKind, EM_MIPS}) @@ -122,6 +129,7 @@ static std::tuple<ELFKind, uint16_t, uint8_t> parseEmulation(StringRef Emul) { .Case("elf64btsmip", {ELF64BEKind, EM_MIPS}) .Case("elf64ltsmip", {ELF64LEKind, EM_MIPS}) .Case("elf64ppc", {ELF64BEKind, EM_PPC64}) + .Case("elf64lppc", {ELF64LEKind, EM_PPC64}) .Cases("elf_amd64", "elf_x86_64", {ELF64LEKind, EM_X86_64}) .Case("elf_i386", {ELF32LEKind, EM_386}) .Case("elf_iamcu", {ELF32LEKind, EM_IAMCU}) @@ -228,11 +236,15 @@ void LinkerDriver::addFile(StringRef Path, bool WithLOption) { Files.push_back( createSharedFile(MBRef, WithLOption ? path::filename(Path) : Path)); return; - default: + case file_magic::bitcode: + case file_magic::elf_relocatable: if (InLib) Files.push_back(make<LazyObjFile>(MBRef, "", 0)); else Files.push_back(createObjectFile(MBRef)); + break; + default: + error(Path + ": unknown file type"); } } @@ -248,18 +260,11 @@ void LinkerDriver::addLibrary(StringRef Name) { // LTO calls LLVM functions to compile bitcode files to native code. // Technically this can be delayed until we read bitcode files, but // we don't bother to do lazily because the initialization is fast. -static void initLLVM(opt::InputArgList &Args) { +static void initLLVM() { InitializeAllTargets(); InitializeAllTargetMCs(); InitializeAllAsmPrinters(); InitializeAllAsmParsers(); - - // Parse and evaluate -mllvm options. - std::vector<const char *> V; - V.push_back("lld (LLVM option parsing)"); - for (auto *Arg : Args.filtered(OPT_mllvm)) - V.push_back(Arg->getValue()); - cl::ParseCommandLineOptions(V.size(), V.data()); } // Some command line options or some combinations of them are not allowed. @@ -290,7 +295,9 @@ static void checkOptions(opt::InputArgList &Args) { error("-r and -shared may not be used together"); if (Config->GcSections) error("-r and --gc-sections may not be used together"); - if (Config->ICF) + if (Config->GdbIndex) + error("-r and --gdb-index may not be used together"); + if (Config->ICF != ICFLevel::None) error("-r and --icf may not be used together"); if (Config->Pie) error("-r and -pie may not be used together"); @@ -310,7 +317,37 @@ static bool hasZOption(opt::InputArgList &Args, StringRef Key) { return false; } -void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { +static bool getZFlag(opt::InputArgList &Args, StringRef K1, StringRef K2, + bool Default) { + for (auto *Arg : Args.filtered_reverse(OPT_z)) { + if (K1 == Arg->getValue()) + return true; + if (K2 == Arg->getValue()) + return false; + } + return Default; +} + +static bool isKnown(StringRef S) { + return S == "combreloc" || S == "copyreloc" || S == "defs" || + S == "execstack" || S == "hazardplt" || S == "initfirst" || + S == "keep-text-section-prefix" || S == "lazy" || S == "muldefs" || + S == "nocombreloc" || S == "nocopyreloc" || S == "nodelete" || + S == "nodlopen" || S == "noexecstack" || + S == "nokeep-text-section-prefix" || S == "norelro" || S == "notext" || + S == "now" || S == "origin" || S == "relro" || S == "retpolineplt" || + S == "rodynamic" || S == "text" || S == "wxneeded" || + S.startswith("max-page-size=") || S.startswith("stack-size="); +} + +// Report an error for an unknown -z option. +static void checkZOptions(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_z)) + if (!isKnown(Arg->getValue())) + error("unknown -z value: " + StringRef(Arg->getValue())); +} + +void LinkerDriver::main(ArrayRef<const char *> ArgsArr) { ELFOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); @@ -319,7 +356,7 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { // Handle -help if (Args.hasArg(OPT_help)) { - printHelp(ArgsArr[0]); + printHelp(); return; } @@ -348,9 +385,6 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { if (Args.hasArg(OPT_version)) return; - Config->ExitEarly = CanExitEarly && !Args.hasArg(OPT_full_shutdown); - errorHandler().ExitEarly = Config->ExitEarly; - if (const char *Path = getReproduceOption(Args)) { // Note that --reproduce is a debug option so you can ignore it // if you are trying to understand the whole picture of the code. @@ -368,10 +402,14 @@ void LinkerDriver::main(ArrayRef<const char *> ArgsArr, bool CanExitEarly) { } readConfigs(Args); - initLLVM(Args); + checkZOptions(Args); + initLLVM(); createFiles(Args); + if (errorCount()) + return; + inferMachineType(); - setConfigs(); + setConfigs(Args); checkOptions(Args); if (errorCount()) return; @@ -482,6 +520,15 @@ static StringRef getDynamicLinker(opt::InputArgList &Args) { return Arg->getValue(); } +static ICFLevel getICF(opt::InputArgList &Args) { + auto *Arg = Args.getLastArg(OPT_icf_none, OPT_icf_safe, OPT_icf_all); + if (!Arg || Arg->getOption().getID() == OPT_icf_none) + return ICFLevel::None; + if (Arg->getOption().getID() == OPT_icf_safe) + return ICFLevel::Safe; + return ICFLevel::All; +} + static StripPolicy getStrip(opt::InputArgList &Args) { if (Args.hasArg(OPT_relocatable)) return StripPolicy::None; @@ -556,6 +603,8 @@ getBuildId(opt::InputArgList &Args) { return {BuildIdKind::Fast, {}}; StringRef S = Arg->getValue(); + if (S == "fast") + return {BuildIdKind::Fast, {}}; if (S == "md5") return {BuildIdKind::Md5, {}}; if (S == "sha1" || S == "tree") @@ -570,6 +619,57 @@ getBuildId(opt::InputArgList &Args) { return {BuildIdKind::None, {}}; } +static std::pair<bool, bool> getPackDynRelocs(opt::InputArgList &Args) { + StringRef S = Args.getLastArgValue(OPT_pack_dyn_relocs, "none"); + if (S == "android") + return {true, false}; + if (S == "relr") + return {false, true}; + if (S == "android+relr") + return {true, true}; + + if (S != "none") + error("unknown -pack-dyn-relocs format: " + S); + return {false, false}; +} + +static void readCallGraph(MemoryBufferRef MB) { + // Build a map from symbol name to section + DenseMap<StringRef, const Symbol *> SymbolNameToSymbol; + for (InputFile *File : ObjectFiles) + for (Symbol *Sym : File->getSymbols()) + SymbolNameToSymbol[Sym->getName()] = Sym; + + for (StringRef L : args::getLines(MB)) { + SmallVector<StringRef, 3> Fields; + L.split(Fields, ' '); + uint64_t Count; + if (Fields.size() != 3 || !to_integer(Fields[2], Count)) + fatal(MB.getBufferIdentifier() + ": parse error"); + const Symbol *FromSym = SymbolNameToSymbol.lookup(Fields[0]); + const Symbol *ToSym = SymbolNameToSymbol.lookup(Fields[1]); + if (Config->WarnSymbolOrdering) { + if (!FromSym) + warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[0]); + if (!ToSym) + warn(MB.getBufferIdentifier() + ": no such symbol: " + Fields[1]); + } + if (!FromSym || !ToSym || Count == 0) + continue; + warnUnorderableSymbol(FromSym); + warnUnorderableSymbol(ToSym); + const Defined *FromSymD = dyn_cast<Defined>(FromSym); + const Defined *ToSymD = dyn_cast<Defined>(ToSym); + if (!FromSymD || !ToSymD) + continue; + const auto *FromSB = dyn_cast_or_null<InputSectionBase>(FromSymD->Section); + const auto *ToSB = dyn_cast_or_null<InputSectionBase>(ToSymD->Section); + if (!FromSB || !ToSB) + continue; + Config->CallGraphProfile[std::make_pair(FromSB, ToSB)] += Count; + } +} + static bool getCompressDebugSections(opt::InputArgList &Args) { StringRef S = Args.getLastArgValue(OPT_compress_debug_sections, "none"); if (S == "none") @@ -581,54 +681,98 @@ static bool getCompressDebugSections(opt::InputArgList &Args) { return true; } -static int parseInt(StringRef S, opt::Arg *Arg) { - int V = 0; - if (!to_integer(S, V, 10)) - error(Arg->getSpelling() + ": number expected, but got '" + S + "'"); - return V; +static std::pair<StringRef, StringRef> getOldNewOptions(opt::InputArgList &Args, + unsigned Id) { + auto *Arg = Args.getLastArg(Id); + if (!Arg) + return {"", ""}; + + StringRef S = Arg->getValue(); + std::pair<StringRef, StringRef> Ret = S.split(';'); + if (Ret.second.empty()) + error(Arg->getSpelling() + " expects 'old;new' format, but got " + S); + return Ret; +} + +// Parse the symbol ordering file and warn for any duplicate entries. +static std::vector<StringRef> getSymbolOrderingFile(MemoryBufferRef MB) { + SetVector<StringRef> Names; + for (StringRef S : args::getLines(MB)) + if (!Names.insert(S) && Config->WarnSymbolOrdering) + warn(MB.getBufferIdentifier() + ": duplicate ordered symbol: " + S); + + return Names.takeVector(); +} + +static void parseClangOption(StringRef Opt, const Twine &Msg) { + std::string Err; + raw_string_ostream OS(Err); + + const char *Argv[] = {Config->ProgName.data(), Opt.data()}; + if (cl::ParseCommandLineOptions(2, Argv, "", &OS)) + return; + OS.flush(); + error(Msg + ": " + StringRef(Err).trim()); } // Initializes Config members by the command line options. void LinkerDriver::readConfigs(opt::InputArgList &Args) { + errorHandler().Verbose = Args.hasArg(OPT_verbose); + errorHandler().FatalWarnings = + Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); + ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + Config->AllowMultipleDefinition = - Args.hasArg(OPT_allow_multiple_definition) || hasZOption(Args, "muldefs"); + Args.hasFlag(OPT_allow_multiple_definition, + OPT_no_allow_multiple_definition, false) || + hasZOption(Args, "muldefs"); Config->AuxiliaryList = args::getStrings(Args, OPT_auxiliary); Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic); Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions); + Config->CheckSections = + Args.hasFlag(OPT_check_sections, OPT_no_check_sections, true); Config->Chroot = Args.getLastArgValue(OPT_chroot); Config->CompressDebugSections = getCompressDebugSections(Args); + Config->Cref = Args.hasFlag(OPT_cref, OPT_no_cref, false); Config->DefineCommon = Args.hasFlag(OPT_define_common, OPT_no_define_common, !Args.hasArg(OPT_relocatable)); Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); Config->DisableVerify = Args.hasArg(OPT_disable_verify); Config->Discard = getDiscard(Args); + Config->DwoDir = Args.getLastArgValue(OPT_plugin_opt_dwo_dir_eq); Config->DynamicLinker = getDynamicLinker(Args); Config->EhFrameHdr = Args.hasFlag(OPT_eh_frame_hdr, OPT_no_eh_frame_hdr, false); Config->EmitRelocs = Args.hasArg(OPT_emit_relocs); - Config->EnableNewDtags = !Args.hasArg(OPT_disable_new_dtags); + Config->EnableNewDtags = + Args.hasFlag(OPT_enable_new_dtags, OPT_disable_new_dtags, true); Config->Entry = Args.getLastArgValue(OPT_entry); Config->ExportDynamic = Args.hasFlag(OPT_export_dynamic, OPT_no_export_dynamic, false); - errorHandler().FatalWarnings = - Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); Config->FilterList = args::getStrings(Args, OPT_filter); Config->Fini = Args.getLastArgValue(OPT_fini, "_fini"); Config->FixCortexA53Errata843419 = Args.hasArg(OPT_fix_cortex_a53_843419); Config->GcSections = Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, false); + Config->GnuUnique = Args.hasFlag(OPT_gnu_unique, OPT_no_gnu_unique, true); Config->GdbIndex = Args.hasFlag(OPT_gdb_index, OPT_no_gdb_index, false); - Config->ICF = Args.hasFlag(OPT_icf_all, OPT_icf_none, false); - Config->ICFData = Args.hasArg(OPT_icf_data); + Config->ICF = getICF(Args); + Config->IgnoreDataAddressEquality = + Args.hasArg(OPT_ignore_data_address_equality); + Config->IgnoreFunctionAddressEquality = + Args.hasArg(OPT_ignore_function_address_equality); Config->Init = Args.getLastArgValue(OPT_init, "_init"); Config->LTOAAPipeline = Args.getLastArgValue(OPT_lto_aa_pipeline); + Config->LTODebugPassManager = Args.hasArg(OPT_lto_debug_pass_manager); + Config->LTONewPassManager = Args.hasArg(OPT_lto_new_pass_manager); Config->LTONewPmPasses = Args.getLastArgValue(OPT_lto_newpm_passes); Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); + Config->LTOObjPath = Args.getLastArgValue(OPT_plugin_opt_obj_path_eq); Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); + Config->LTOSampleProfile = Args.getLastArgValue(OPT_lto_sample_profile); Config->MapFile = Args.getLastArgValue(OPT_Map); - Config->NoGnuUnique = Args.hasArg(OPT_no_gnu_unique); + Config->MipsGotSize = args::getInteger(Args, OPT_mips_got_size, 0xfff0); Config->MergeArmExidx = Args.hasFlag(OPT_merge_exidx_entries, OPT_no_merge_exidx_entries, true); - Config->NoUndefinedVersion = Args.hasArg(OPT_no_undefined_version); Config->NoinhibitExec = Args.hasArg(OPT_noinhibit_exec); Config->Nostdlib = Args.hasArg(OPT_nostdlib); Config->OFormatBinary = isOutputFormatBinary(Args); @@ -638,7 +782,9 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->Optimize = args::getInteger(Args, OPT_O, 1); Config->OrphanHandling = getOrphanHandling(Args); Config->OutputFile = Args.getLastArgValue(OPT_o); - Config->Pie = Args.hasFlag(OPT_pie, OPT_nopie, false); + Config->Pie = Args.hasFlag(OPT_pie, OPT_no_pie, false); + Config->PrintIcfSections = + Args.hasFlag(OPT_print_icf_sections, OPT_no_print_icf_sections, false); Config->PrintGcSections = Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); Config->Rpath = getRpath(Args); @@ -658,46 +804,58 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { Config->ThinLTOCachePolicy = CHECK( parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), "--thinlto-cache-policy: invalid cache policy"); + Config->ThinLTOEmitImportsFiles = + Args.hasArg(OPT_plugin_opt_thinlto_emit_imports_files); + Config->ThinLTOIndexOnly = Args.hasArg(OPT_plugin_opt_thinlto_index_only) || + Args.hasArg(OPT_plugin_opt_thinlto_index_only_eq); + Config->ThinLTOIndexOnlyArg = + Args.getLastArgValue(OPT_plugin_opt_thinlto_index_only_eq); Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); - ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); + Config->ThinLTOObjectSuffixReplace = + getOldNewOptions(Args, OPT_plugin_opt_thinlto_object_suffix_replace_eq); + Config->ThinLTOPrefixReplace = + getOldNewOptions(Args, OPT_plugin_opt_thinlto_prefix_replace_eq); Config->Trace = Args.hasArg(OPT_trace); Config->Undefined = args::getStrings(Args, OPT_undefined); + Config->UndefinedVersion = + Args.hasFlag(OPT_undefined_version, OPT_no_undefined_version, true); + Config->UseAndroidRelrTags = Args.hasFlag( + OPT_use_android_relr_tags, OPT_no_use_android_relr_tags, false); Config->UnresolvedSymbols = getUnresolvedSymbolPolicy(Args); - Config->Verbose = Args.hasArg(OPT_verbose); - errorHandler().Verbose = Config->Verbose; - Config->WarnCommon = Args.hasArg(OPT_warn_common); - Config->ZCombreloc = !hasZOption(Args, "nocombreloc"); - Config->ZExecstack = hasZOption(Args, "execstack"); - Config->ZNocopyreloc = hasZOption(Args, "nocopyreloc"); + Config->WarnBackrefs = + Args.hasFlag(OPT_warn_backrefs, OPT_no_warn_backrefs, false); + Config->WarnCommon = Args.hasFlag(OPT_warn_common, OPT_no_warn_common, false); + Config->WarnSymbolOrdering = + Args.hasFlag(OPT_warn_symbol_ordering, OPT_no_warn_symbol_ordering, true); + Config->ZCombreloc = getZFlag(Args, "combreloc", "nocombreloc", true); + Config->ZCopyreloc = getZFlag(Args, "copyreloc", "nocopyreloc", true); + Config->ZExecstack = getZFlag(Args, "execstack", "noexecstack", false); + Config->ZHazardplt = hasZOption(Args, "hazardplt"); + Config->ZInitfirst = hasZOption(Args, "initfirst"); + Config->ZKeepTextSectionPrefix = getZFlag( + Args, "keep-text-section-prefix", "nokeep-text-section-prefix", false); Config->ZNodelete = hasZOption(Args, "nodelete"); Config->ZNodlopen = hasZOption(Args, "nodlopen"); - Config->ZNow = hasZOption(Args, "now"); + Config->ZNow = getZFlag(Args, "now", "lazy", false); Config->ZOrigin = hasZOption(Args, "origin"); - Config->ZRelro = !hasZOption(Args, "norelro"); + Config->ZRelro = getZFlag(Args, "relro", "norelro", true); + Config->ZRetpolineplt = hasZOption(Args, "retpolineplt"); Config->ZRodynamic = hasZOption(Args, "rodynamic"); Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", 0); - Config->ZText = !hasZOption(Args, "notext"); + Config->ZText = getZFlag(Args, "text", "notext", true); Config->ZWxneeded = hasZOption(Args, "wxneeded"); - // Parse LTO plugin-related options for compatibility with gold. - for (auto *Arg : Args.filtered(OPT_plugin_opt, OPT_plugin_opt_eq)) { - StringRef S = Arg->getValue(); - if (S == "disable-verify") - Config->DisableVerify = true; - else if (S == "save-temps") - Config->SaveTemps = true; - else if (S.startswith("O")) - Config->LTOO = parseInt(S.substr(1), Arg); - else if (S.startswith("lto-partitions=")) - Config->LTOPartitions = parseInt(S.substr(15), Arg); - else if (S.startswith("jobs=")) - Config->ThinLTOJobs = parseInt(S.substr(5), Arg); - else if (!S.startswith("/") && !S.startswith("-fresolution=") && - !S.startswith("-pass-through=") && !S.startswith("mcpu=") && - !S.startswith("thinlto") && S != "-function-sections" && - S != "-data-sections") - error(Arg->getSpelling() + ": unknown option: " + S); - } + // Parse LTO options. + if (auto *Arg = Args.getLastArg(OPT_plugin_opt_mcpu_eq)) + parseClangOption(Saver.save("-mcpu=" + StringRef(Arg->getValue())), + Arg->getSpelling()); + + for (auto *Arg : Args.filtered(OPT_plugin_opt)) + parseClangOption(Arg->getValue(), Arg->getSpelling()); + + // Parse -mllvm options. + for (auto *Arg : Args.filtered(OPT_mllvm)) + parseClangOption(Arg->getValue(), Arg->getSpelling()); if (Config->LTOO > 3) error("invalid optimization level for LTO: " + Twine(Config->LTOO)); @@ -740,17 +898,12 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { std::tie(Config->BuildId, Config->BuildIdVector) = getBuildId(Args); - if (auto *Arg = Args.getLastArg(OPT_pack_dyn_relocs_eq)) { - StringRef S = Arg->getValue(); - if (S == "android") - Config->AndroidPackDynRelocs = true; - else if (S != "none") - error("unknown -pack-dyn-relocs format: " + S); - } + std::tie(Config->AndroidPackDynRelocs, Config->RelrPackDynRelocs) = + getPackDynRelocs(Args); if (auto *Arg = Args.getLastArg(OPT_symbol_ordering_file)) if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - Config->SymbolOrderingFile = args::getLines(*Buffer); + Config->SymbolOrderingFile = getSymbolOrderingFile(*Buffer); // If --retain-symbol-file is used, we'll keep only the symbols listed in // the file and discard all others. @@ -778,32 +931,67 @@ void LinkerDriver::readConfigs(opt::InputArgList &Args) { {Arg->getValue(), /*IsExternCpp*/ false, /*HasWildcard*/ false}); } + // If --export-dynamic-symbol=foo is given and symbol foo is defined in + // an object file in an archive file, that object file should be pulled + // out and linked. (It doesn't have to behave like that from technical + // point of view, but this is needed for compatibility with GNU.) + for (auto *Arg : Args.filtered(OPT_export_dynamic_symbol)) + Config->Undefined.push_back(Arg->getValue()); + for (auto *Arg : Args.filtered(OPT_version_script)) - if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) - readVersionScript(*Buffer); + if (Optional<std::string> Path = searchScript(Arg->getValue())) { + if (Optional<MemoryBufferRef> Buffer = readFile(*Path)) + readVersionScript(*Buffer); + } else { + error(Twine("cannot find version script ") + Arg->getValue()); + } } // Some Config members do not directly correspond to any particular // command line options, but computed based on other Config values. // This function initialize such members. See Config.h for the details // of these values. -static void setConfigs() { +static void setConfigs(opt::InputArgList &Args) { ELFKind Kind = Config->EKind; uint16_t Machine = Config->EMachine; - // There is an ILP32 ABI for x86-64, although it's not very popular. - // It is called the x32 ABI. - bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64); - Config->CopyRelocs = (Config->Relocatable || Config->EmitRelocs); Config->Is64 = (Kind == ELF64LEKind || Kind == ELF64BEKind); Config->IsLE = (Kind == ELF32LEKind || Kind == ELF64LEKind); Config->Endianness = Config->IsLE ? support::endianness::little : support::endianness::big; Config->IsMips64EL = (Kind == ELF64LEKind && Machine == EM_MIPS); - Config->IsRela = Config->Is64 || IsX32 || Config->MipsN32Abi; Config->Pic = Config->Pie || Config->Shared; Config->Wordsize = Config->Is64 ? 8 : 4; + + // There is an ILP32 ABI for x86-64, although it's not very popular. + // It is called the x32 ABI. + bool IsX32 = (Kind == ELF32LEKind && Machine == EM_X86_64); + + // ELF defines two different ways to store relocation addends as shown below: + // + // Rel: Addends are stored to the location where relocations are applied. + // Rela: Addends are stored as part of relocation entry. + // + // In other words, Rela makes it easy to read addends at the price of extra + // 4 or 8 byte for each relocation entry. We don't know why ELF defined two + // different mechanisms in the first place, but this is how the spec is + // defined. + // + // You cannot choose which one, Rel or Rela, you want to use. Instead each + // ABI defines which one you need to use. The following expression expresses + // that. + Config->IsRela = + (Config->Is64 || IsX32 || Machine == EM_PPC) && Machine != EM_MIPS; + + // If the output uses REL relocations we must store the dynamic relocation + // addends to the output sections. We also store addends for RELA relocations + // if --apply-dynamic-relocs is used. + // We default to not writing the addends when using RELA relocations since + // any standard conforming tool can find it in r_addend. + Config->WriteAddends = Args.hasFlag(OPT_apply_dynamic_relocs, + OPT_no_apply_dynamic_relocs, false) || + !Config->IsRela; } // Returns a value of "-format" option. @@ -818,6 +1006,10 @@ static bool getBinaryOption(StringRef S) { } void LinkerDriver::createFiles(opt::InputArgList &Args) { + // For --{push,pop}-state. + std::vector<std::tuple<bool, bool, bool>> Stack; + + // Iterate over argv to process input files and positional arguments. for (auto *Arg : Args) { switch (Arg->getOption().getUnaliasedOption().getID()) { case OPT_library: @@ -826,8 +1018,15 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_INPUT: addFile(Arg->getValue(), /*WithLOption=*/false); break; + case OPT_defsym: { + StringRef From; + StringRef To; + std::tie(From, To) = StringRef(Arg->getValue()).split('='); + readDefsym(From, MemoryBufferRef(To, "-defsym")); + break; + } case OPT_script: - if (Optional<std::string> Path = searchLinkerScript(Arg->getValue())) { + if (Optional<std::string> Path = searchScript(Arg->getValue())) { if (Optional<MemoryBufferRef> MB = readFile(*Path)) readLinkerScript(*MB); break; @@ -855,11 +1054,48 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_no_whole_archive: InWholeArchive = false; break; + case OPT_just_symbols: + if (Optional<MemoryBufferRef> MB = readFile(Arg->getValue())) { + Files.push_back(createObjectFile(*MB)); + Files.back()->JustSymbols = true; + } + break; + case OPT_start_group: + if (InputFile::IsInGroup) + error("nested --start-group"); + InputFile::IsInGroup = true; + break; + case OPT_end_group: + if (!InputFile::IsInGroup) + error("stray --end-group"); + InputFile::IsInGroup = false; + ++InputFile::NextGroupId; + break; case OPT_start_lib: + if (InLib) + error("nested --start-lib"); + if (InputFile::IsInGroup) + error("may not nest --start-lib in --start-group"); InLib = true; + InputFile::IsInGroup = true; break; case OPT_end_lib: + if (!InLib) + error("stray --end-lib"); InLib = false; + InputFile::IsInGroup = false; + ++InputFile::NextGroupId; + break; + case OPT_push_state: + Stack.emplace_back(Config->AsNeeded, Config->Static, InWholeArchive); + break; + case OPT_pop_state: + if (Stack.empty()) { + error("unbalanced --push-state/--pop-state"); + break; + } + std::tie(Config->AsNeeded, Config->Static, InWholeArchive) = Stack.back(); + Stack.pop_back(); break; } } @@ -932,14 +1168,6 @@ static DenseSet<StringRef> getExcludeLibs(opt::InputArgList &Args) { return Ret; } -static Optional<StringRef> getArchiveName(InputFile *File) { - if (isa<ArchiveFile>(File)) - return File->getName(); - if (!File->ArchiveName.empty()) - return File->ArchiveName; - return None; -} - // Handles the -exclude-libs option. If a static library file is specified // by the -exclude-libs option, all public symbols from the archive become // private unless otherwise specified by version scripts or something. @@ -947,16 +1175,132 @@ static Optional<StringRef> getArchiveName(InputFile *File) { // // This is not a popular option, but some programs such as bionic libc use it. template <class ELFT> -static void excludeLibs(opt::InputArgList &Args, ArrayRef<InputFile *> Files) { +static void excludeLibs(opt::InputArgList &Args) { DenseSet<StringRef> Libs = getExcludeLibs(Args); bool All = Libs.count("ALL"); - for (InputFile *File : Files) - if (Optional<StringRef> Archive = getArchiveName(File)) - if (All || Libs.count(path::filename(*Archive))) + auto Visit = [&](InputFile *File) { + if (!File->ArchiveName.empty()) + if (All || Libs.count(path::filename(File->ArchiveName))) for (Symbol *Sym : File->getSymbols()) - if (!Sym->isLocal()) + if (!Sym->isLocal() && Sym->File == File) Sym->VersionId = VER_NDX_LOCAL; + }; + + for (InputFile *File : ObjectFiles) + Visit(File); + + for (BitcodeFile *File : BitcodeFiles) + Visit(File); +} + +// Force Sym to be entered in the output. Used for -u or equivalent. +template <class ELFT> static void handleUndefined(StringRef Name) { + Symbol *Sym = Symtab->find(Name); + if (!Sym) + return; + + // Since symbol S may not be used inside the program, LTO may + // eliminate it. Mark the symbol as "used" to prevent it. + Sym->IsUsedInRegularObj = true; + + if (Sym->isLazy()) + Symtab->fetchLazy<ELFT>(Sym); +} + +template <class ELFT> static bool shouldDemote(Symbol &Sym) { + // If all references to a DSO happen to be weak, the DSO is not added to + // DT_NEEDED. If that happens, we need to eliminate shared symbols created + // from the DSO. Otherwise, they become dangling references that point to a + // non-existent DSO. + if (auto *S = dyn_cast<SharedSymbol>(&Sym)) + return !S->getFile<ELFT>().IsNeeded; + + // We are done processing archives, so lazy symbols that were used but not + // found can be converted to undefined. We could also just delete the other + // lazy symbols, but that seems to be more work than it is worth. + return Sym.isLazy() && Sym.IsUsedInRegularObj; +} + +// Some files, such as .so or files between -{start,end}-lib may be removed +// after their symbols are added to the symbol table. If that happens, we +// need to remove symbols that refer files that no longer exist, so that +// they won't appear in the symbol table of the output file. +// +// We remove symbols by demoting them to undefined symbol. +template <class ELFT> static void demoteSymbols() { + for (Symbol *Sym : Symtab->getSymbols()) { + if (shouldDemote<ELFT>(*Sym)) { + bool Used = Sym->Used; + replaceSymbol<Undefined>(Sym, nullptr, Sym->getName(), Sym->Binding, + Sym->StOther, Sym->Type); + Sym->Used = Used; + } + } +} + +// The section referred to by S is considered address-significant. Set the +// KeepUnique flag on the section if appropriate. +static void markAddrsig(Symbol *S) { + if (auto *D = dyn_cast_or_null<Defined>(S)) + if (D->Section) + // We don't need to keep text sections unique under --icf=all even if they + // are address-significant. + if (Config->ICF == ICFLevel::Safe || !(D->Section->Flags & SHF_EXECINSTR)) + D->Section->KeepUnique = true; +} + +// Record sections that define symbols mentioned in --keep-unique <symbol> +// and symbols referred to by address-significance tables. These sections are +// ineligible for ICF. +template <class ELFT> +static void findKeepUniqueSections(opt::InputArgList &Args) { + for (auto *Arg : Args.filtered(OPT_keep_unique)) { + StringRef Name = Arg->getValue(); + auto *D = dyn_cast_or_null<Defined>(Symtab->find(Name)); + if (!D || !D->Section) { + warn("could not find symbol " + Name + " to keep unique"); + continue; + } + D->Section->KeepUnique = true; + } + + // --icf=all --ignore-data-address-equality means that we can ignore + // the dynsym and address-significance tables entirely. + if (Config->ICF == ICFLevel::All && Config->IgnoreDataAddressEquality) + return; + + // Symbols in the dynsym could be address-significant in other executables + // or DSOs, so we conservatively mark them as address-significant. + for (Symbol *S : Symtab->getSymbols()) + if (S->includeInDynsym()) + markAddrsig(S); + + // Visit the address-significance table in each object file and mark each + // referenced symbol as address-significant. + for (InputFile *F : ObjectFiles) { + auto *Obj = cast<ObjFile<ELFT>>(F); + ArrayRef<Symbol *> Syms = Obj->getSymbols(); + if (Obj->AddrsigSec) { + ArrayRef<uint8_t> Contents = + check(Obj->getObj().getSectionContents(Obj->AddrsigSec)); + const uint8_t *Cur = Contents.begin(); + while (Cur != Contents.end()) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + fatal(toString(F) + ": could not decode addrsig section: " + Err); + markAddrsig(Syms[SymIndex]); + Cur += Size; + } + } else { + // If an object file does not have an address-significance table, + // conservatively mark all of its symbols as address-significant. + for (Symbol *S : Syms) + markAddrsig(S); + } + } } // Do actual linking. Note that when this function is called, @@ -1007,14 +1351,6 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { for (InputFile *F : Files) Symtab->addFile<ELFT>(F); - // Process -defsym option. - for (auto *Arg : Args.filtered(OPT_defsym)) { - StringRef From; - StringRef To; - std::tie(From, To) = StringRef(Arg->getValue()).split('='); - readDefsym(From, MemoryBufferRef(To, "-defsym")); - } - // Now that we have every file, we can decide if we will need a // dynamic symbol table. // We need one if we were asked to export dynamic symbols or if we are @@ -1031,23 +1367,29 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // Handle the `--undefined <sym>` options. for (StringRef S : Config->Undefined) - Symtab->fetchIfLazy<ELFT>(S); + handleUndefined<ELFT>(S); // If an entry symbol is in a static archive, pull out that file now // to complete the symbol table. After this, no new names except a // few linker-synthesized ones will be added to the symbol table. - Symtab->fetchIfLazy<ELFT>(Config->Entry); + handleUndefined<ELFT>(Config->Entry); // Return if there were name resolution errors. if (errorCount()) return; - // Handle undefined symbols in DSOs. - Symtab->scanShlibUndefined<ELFT>(); + // Now when we read all script files, we want to finalize order of linker + // script commands, which can be not yet final because of INSERT commands. + Script->processInsertCommands(); + + // We want to declare linker script's symbols early, + // so that we can version them. + // They also might be exported if referenced by DSOs. + Script->declareSymbols(); // Handle the -exclude-libs option. if (Args.hasArg(OPT_exclude_libs)) - excludeLibs<ELFT>(Args, Files); + excludeLibs<ELFT>(Args); // Create ElfHeader early. We need a dummy section in // addReservedSymbols to mark the created symbols as not absolute. @@ -1059,16 +1401,29 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { addReservedSymbols(); // Apply version scripts. - Symtab->scanVersionScript(); + // + // For a relocatable output, version scripts don't make sense, and + // parsing a symbol version string (e.g. dropping "@ver1" from a symbol + // name "foo@ver1") rather do harm, so we don't call this if -r is given. + if (!Config->Relocatable) + Symtab->scanVersionScript(); // Create wrapped symbols for -wrap option. for (auto *Arg : Args.filtered(OPT_wrap)) Symtab->addSymbolWrap<ELFT>(Arg->getValue()); + // Do link-time optimization if given files are LLVM bitcode files. + // This compiles bitcode files into real object files. Symtab->addCombinedLTOObject<ELFT>(); if (errorCount()) return; + // If -thinlto-index-only is given, we should create only "index + // files" and not object files. Index file creation is already done + // in addCombinedLTOObject, so we are done if that's the case. + if (Config->ThinLTOIndexOnly) + return; + // Apply symbol renames for -wrap. Symtab->applySymbolWrap(); @@ -1115,11 +1470,20 @@ template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) { // Do size optimizations: garbage collection, merging of SHF_MERGE sections // and identical code folding. - markLive<ELFT>(); decompressSections(); + splitSections<ELFT>(); + markLive<ELFT>(); + demoteSymbols<ELFT>(); mergeSections(); - if (Config->ICF) + if (Config->ICF != ICFLevel::None) { + findKeepUniqueSections<ELFT>(Args); doIcf<ELFT>(); + } + + // Read the callgraph now that we know what was gced or icfed + if (auto *Arg = Args.getLastArg(OPT_call_graph_ordering_file)) + if (Optional<MemoryBufferRef> Buffer = readFile(Arg->getValue())) + readCallGraph(*Buffer); // Write the result to the file. writeResult<ELFT>(); diff --git a/ELF/Driver.h b/ELF/Driver.h index 351d7926de71..99e194d9b66c 100644 --- a/ELF/Driver.h +++ b/ELF/Driver.h @@ -26,7 +26,7 @@ extern class LinkerDriver *Driver; class LinkerDriver { public: - void main(ArrayRef<const char *> Args, bool CanExitEarly); + void main(ArrayRef<const char *> Args); void addFile(StringRef Path, bool WithLOption); void addLibrary(StringRef Name); @@ -63,11 +63,11 @@ enum { #undef OPTION }; -void printHelp(const char *Argv0); +void printHelp(); std::string createResponseFile(const llvm::opt::InputArgList &Args); llvm::Optional<std::string> findFromSearchPaths(StringRef Path); -llvm::Optional<std::string> searchLinkerScript(StringRef Path); +llvm::Optional<std::string> searchScript(StringRef Path); llvm::Optional<std::string> searchLibrary(StringRef Path); } // namespace elf diff --git a/ELF/DriverUtils.cpp b/ELF/DriverUtils.cpp index 2f7c9228851a..698e06edfe63 100644 --- a/ELF/DriverUtils.cpp +++ b/ELF/DriverUtils.cpp @@ -29,6 +29,7 @@ using namespace llvm; using namespace llvm::sys; +using namespace llvm::opt; using namespace lld; using namespace lld::elf; @@ -58,18 +59,18 @@ static void handleColorDiagnostics(opt::InputArgList &Args) { OPT_no_color_diagnostics); if (!Arg) return; - else if (Arg->getOption().getID() == OPT_color_diagnostics) + if (Arg->getOption().getID() == OPT_color_diagnostics) { errorHandler().ColorDiagnostics = true; - else if (Arg->getOption().getID() == OPT_no_color_diagnostics) + } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { errorHandler().ColorDiagnostics = false; - else { + } else { StringRef S = Arg->getValue(); if (S == "always") errorHandler().ColorDiagnostics = true; else if (S == "never") errorHandler().ColorDiagnostics = false; else if (S != "auto") - error("unknown option: -color-diagnostics=" + S); + error("unknown option: --color-diagnostics=" + S); } } @@ -87,6 +88,29 @@ static cl::TokenizerCallback getQuotingStyle(opt::InputArgList &Args) { return cl::TokenizeGNUCommandLine; } +// Gold LTO plugin takes a `--plugin-opt foo=bar` option as an alias for +// `--plugin-opt=foo=bar`. We want to handle `--plugin-opt=foo=` as an +// option name and `bar` as a value. Unfortunately, OptParser cannot +// handle an option with a space in it. +// +// In this function, we concatenate command line arguments so that +// `--plugin-opt <foo>` is converted to `--plugin-opt=<foo>`. This is a +// bit hacky, but looks like it is still better than handling --plugin-opt +// options by hand. +static void concatLTOPluginOptions(SmallVectorImpl<const char *> &Args) { + SmallVector<const char *, 256> V; + for (size_t I = 0, E = Args.size(); I != E; ++I) { + StringRef S = Args[I]; + if ((S == "-plugin-opt" || S == "--plugin-opt") && I + 1 != E) { + V.push_back(Saver.save(S + "=" + Args[I + 1]).data()); + ++I; + } else { + V.push_back(Args[I]); + } + } + Args = std::move(V); +} + // Parses a given list of options. opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { // Make InputArgList from string vectors. @@ -102,6 +126,7 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { // Expand response files (arguments in the form of @<filename>) // and then parse the argument again. cl::ExpandResponseFiles(Saver, getQuotingStyle(Args), Vec); + concatLTOPluginOptions(Vec); Args = this->ParseArgs(Vec, MissingIndex, MissingCount); handleColorDiagnostics(Args); @@ -113,9 +138,9 @@ opt::InputArgList ELFOptTable::parse(ArrayRef<const char *> Argv) { return Args; } -void elf::printHelp(const char *Argv0) { - ELFOptTable().PrintHelp(outs(), Argv0, "lld", false /*ShowHidden*/, - true /*ShowAllAliases*/); +void elf::printHelp() { + ELFOptTable().PrintHelp(outs(), Config->ProgName.data(), "lld", + false /*ShowHidden*/, true /*ShowAllAliases*/); outs() << "\n"; // Scripts generated by Libtool versions up to at least 2.4.6 (the most @@ -123,13 +148,7 @@ void elf::printHelp(const char *Argv0) { // in a message for the -help option. If it doesn't match, the scripts // assume that the linker doesn't support very basic features such as // shared libraries. Therefore, we need to print out at least "elf". - // Here, we print out all the targets that we support. - outs() << Argv0 << ": supported targets: " - << "elf32-i386 elf32-iamcu elf32-littlearm elf32-ntradbigmips " - << "elf32-ntradlittlemips elf32-powerpc elf32-tradbigmips " - << "elf32-tradlittlemips elf32-x86-64 " - << "elf64-amdgpu elf64-littleaarch64 elf64-powerpc elf64-tradbigmips " - << "elf64-tradlittlemips elf64-x86-64\n"; + outs() << Config->ProgName << ": supported targets: elf\n"; } // Reconstructs command line arguments so that so that you can re-run @@ -208,10 +227,10 @@ Optional<std::string> elf::searchLibrary(StringRef Name) { return None; } -// If a linker script doesn't exist in the current directory, we also look for -// the script in the '-L' search paths. This matches the behaviour of both '-T' -// and linker script INPUT() directives in ld.bfd. -Optional<std::string> elf::searchLinkerScript(StringRef Name) { +// If a linker/version script doesn't exist in the current directory, we also +// look for the script in the '-L' search paths. This matches the behaviour of +// '-T', --version-script=, and linker script INPUT() command in ld.bfd. +Optional<std::string> elf::searchScript(StringRef Name) { if (fs::exists(Name)) return Name.str(); return findFromSearchPaths(Name); diff --git a/ELF/EhFrame.cpp b/ELF/EhFrame.cpp index 62abc3973e7e..20b32c0a96e6 100644 --- a/ELF/EhFrame.cpp +++ b/ELF/EhFrame.cpp @@ -20,18 +20,16 @@ #include "Config.h" #include "InputSection.h" #include "Relocations.h" -#include "Strings.h" - +#include "Target.h" #include "lld/Common/ErrorHandler.h" +#include "lld/Common/Strings.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/Endian.h" using namespace llvm; using namespace llvm::ELF; using namespace llvm::dwarf; using namespace llvm::object; -using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; @@ -73,7 +71,7 @@ size_t EhReader::readEhRecordSize() { // First 4 bytes of CIE/FDE is the size of the record. // If it is 0xFFFFFFFF, the next 8 bytes contain the size instead, // but we do not support that format yet. - uint64_t V = read32(D.data(), Config->Endianness); + uint64_t V = read32(D.data()); if (V == UINT32_MAX) failOn(D.data(), "CIE/FDE too large"); uint64_t Size = V + 4; diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp index 8d0b5d8a2f1c..5cf240eeca56 100644 --- a/ELF/Filesystem.cpp +++ b/ELF/Filesystem.cpp @@ -44,7 +44,7 @@ using namespace lld::elf; // The calling thread returns almost immediately. void elf::unlinkAsync(StringRef Path) { // Removing a file is async on windows. -#if defined(LLVM_ON_WIN32) +#if defined(_WIN32) sys::fs::remove(Path); #else if (!ThreadsEnabled || !sys::fs::exists(Path) || diff --git a/ELF/GdbIndex.cpp b/ELF/GdbIndex.cpp index d27b57f95938..85449a200647 100644 --- a/ELF/GdbIndex.cpp +++ b/ELF/GdbIndex.cpp @@ -34,7 +34,7 @@ template <class ELFT> LLDDwarfObj<ELFT>::LLDDwarfObj(ObjFile<ELFT> *Obj) { .Case(".debug_ranges", &RangeSection) .Case(".debug_line", &LineSection) .Default(nullptr)) { - Sec->maybeUncompress(); + Sec->maybeDecompress(); M->Data = toStringRef(Sec->Data); M->Sec = Sec; continue; diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index 41ae9d793c11..eba1ba22f879 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -49,7 +49,6 @@ public: return LineSection; } StringRef getFileName() const override { return ""; } - StringRef getCUIndexSection() const override { return ""; } StringRef getAbbrevSection() const override { return AbbrevSection; } StringRef getStringSection() const override { return StrSection; } StringRef getGnuPubNamesSection() const override { diff --git a/ELF/ICF.cpp b/ELF/ICF.cpp index b1e12e0590d5..ba413b132658 100644 --- a/ELF/ICF.cpp +++ b/ELF/ICF.cpp @@ -77,6 +77,8 @@ #include "Config.h" #include "SymbolTable.h" #include "Symbols.h" +#include "SyntheticSections.h" +#include "Writer.h" #include "lld/Common/Threads.h" #include "llvm/ADT/Hashing.h" #include "llvm/BinaryFormat/ELF.h" @@ -112,9 +114,9 @@ private: size_t findBoundary(size_t Begin, size_t End); void forEachClassRange(size_t Begin, size_t End, - std::function<void(size_t, size_t)> Fn); + llvm::function_ref<void(size_t, size_t)> Fn); - void forEachClass(std::function<void(size_t, size_t)> Fn); + void forEachClass(llvm::function_ref<void(size_t, size_t)> Fn); std::vector<InputSection *> Sections; @@ -161,15 +163,38 @@ template <class ELFT> static uint32_t getHash(InputSection *S) { // Returns true if section S is subject of ICF. static bool isEligible(InputSection *S) { - // Don't merge read only data sections unless --icf-data was passed. - if (!(S->Flags & SHF_EXECINSTR) && !Config->ICFData) + if (!S->Live || S->KeepUnique || !(S->Flags & SHF_ALLOC)) return false; - // .init and .fini contains instructions that must be executed to - // initialize and finalize the process. They cannot and should not - // be merged. - return S->Live && (S->Flags & SHF_ALLOC) && !(S->Flags & SHF_WRITE) && - S->Name != ".init" && S->Name != ".fini"; + // Don't merge writable sections. .data.rel.ro sections are marked as writable + // but are semantically read-only. + if ((S->Flags & SHF_WRITE) && S->Name != ".data.rel.ro" && + !S->Name.startswith(".data.rel.ro.")) + return false; + + // SHF_LINK_ORDER sections are ICF'd as a unit with their dependent sections, + // so we don't consider them for ICF individually. + if (S->Flags & SHF_LINK_ORDER) + return false; + + // Don't merge synthetic sections as their Data member is not valid and empty. + // The Data member needs to be valid for ICF as it is used by ICF to determine + // the equality of section contents. + if (isa<SyntheticSection>(S)) + return false; + + // .init and .fini contains instructions that must be executed to initialize + // and finalize the process. They cannot and should not be merged. + if (S->Name == ".init" || S->Name == ".fini") + return false; + + // A user program may enumerate sections named with a C identifier using + // __start_* and __stop_* symbols. We cannot ICF any such sections because + // that could change program semantics. + if (isValidCIdentifier(S->Name)) + return false; + + return true; } // Split an equivalence class into smaller classes. @@ -214,9 +239,6 @@ template <class ELFT> template <class RelTy> bool ICF<ELFT>::constantEq(const InputSection *SecA, ArrayRef<RelTy> RA, const InputSection *SecB, ArrayRef<RelTy> RB) { - if (RA.size() != RB.size()) - return false; - for (size_t I = 0; I < RA.size(); ++I) { if (RA[I].r_offset != RB[I].r_offset || RA[I].getType(Config->IsMips64EL) != RB[I].getType(Config->IsMips64EL)) @@ -284,6 +306,13 @@ bool ICF<ELFT>::equalsConstant(const InputSection *A, const InputSection *B) { A->getSize() != B->getSize() || A->Data != B->Data) return false; + // If two sections have different output sections, we cannot merge them. + // FIXME: This doesn't do the right thing in the case where there is a linker + // script. We probably need to move output section assignment before ICF to + // get the correct behaviour here. + if (getOutputSectionName(A) != getOutputSectionName(B)) + return false; + if (A->AreRelocsRela) return constantEq(A, A->template relas<ELFT>(), B, B->template relas<ELFT>()); @@ -350,17 +379,12 @@ template <class ELFT> size_t ICF<ELFT>::findBoundary(size_t Begin, size_t End) { // vector. Therefore, Sections vector can be considered as contiguous // groups of sections, grouped by the class. // -// This function calls Fn on every group that starts within [Begin, End). -// Note that a group must start in that range but doesn't necessarily -// have to end before End. +// This function calls Fn on every group within [Begin, End). template <class ELFT> void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End, - std::function<void(size_t, size_t)> Fn) { - if (Begin > 0) - Begin = findBoundary(Begin - 1, End); - + llvm::function_ref<void(size_t, size_t)> Fn) { while (Begin < End) { - size_t Mid = findBoundary(Begin, Sections.size()); + size_t Mid = findBoundary(Begin, End); Fn(Begin, Mid); Begin = Mid; } @@ -368,7 +392,7 @@ void ICF<ELFT>::forEachClassRange(size_t Begin, size_t End, // Call Fn on each equivalence class. template <class ELFT> -void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) { +void ICF<ELFT>::forEachClass(llvm::function_ref<void(size_t, size_t)> Fn) { // If threading is disabled or the number of sections are // too small to use threading, call Fn sequentially. if (!ThreadsEnabled || Sections.size() < 1024) { @@ -380,16 +404,32 @@ void ICF<ELFT>::forEachClass(std::function<void(size_t, size_t)> Fn) { Current = Cnt % 2; Next = (Cnt + 1) % 2; - // Split sections into 256 shards and call Fn in parallel. - size_t NumShards = 256; + // Shard into non-overlapping intervals, and call Fn in parallel. + // The sharding must be completed before any calls to Fn are made + // so that Fn can modify the Chunks in its shard without causing data + // races. + const size_t NumShards = 256; size_t Step = Sections.size() / NumShards; - parallelForEachN(0, NumShards, [&](size_t I) { - size_t End = (I == NumShards - 1) ? Sections.size() : (I + 1) * Step; - forEachClassRange(I * Step, End, Fn); + size_t Boundaries[NumShards + 1]; + Boundaries[0] = 0; + Boundaries[NumShards] = Sections.size(); + + parallelForEachN(1, NumShards, [&](size_t I) { + Boundaries[I] = findBoundary((I - 1) * Step, Sections.size()); + }); + + parallelForEachN(1, NumShards + 1, [&](size_t I) { + if (Boundaries[I - 1] < Boundaries[I]) + forEachClassRange(Boundaries[I - 1], Boundaries[I], Fn); }); ++Cnt; } +static void print(const Twine &S) { + if (Config->PrintIcfSections) + message(S); +} + // The main function of ICF. template <class ELFT> void ICF<ELFT>::run() { // Collect sections to merge. @@ -401,7 +441,7 @@ template <class ELFT> void ICF<ELFT>::run() { // Initially, we use hash values to partition sections. parallelForEach(Sections, [&](InputSection *S) { // Set MSB to 1 to avoid collisions with non-hash IDs. - S->Class[0] = getHash<ELFT>(S) | (1 << 31); + S->Class[0] = getHash<ELFT>(S) | (1U << 31); }); // From now on, sections in Sections vector are ordered so that sections @@ -424,25 +464,21 @@ template <class ELFT> void ICF<ELFT>::run() { log("ICF needed " + Twine(Cnt) + " iterations"); // Merge sections by the equivalence class. - forEachClass([&](size_t Begin, size_t End) { + forEachClassRange(0, Sections.size(), [&](size_t Begin, size_t End) { if (End - Begin == 1) return; - - log("selected " + Sections[Begin]->Name); + print("selected section " + toString(Sections[Begin])); for (size_t I = Begin + 1; I < End; ++I) { - log(" removed " + Sections[I]->Name); + print(" removing identical section " + toString(Sections[I])); Sections[Begin]->replace(Sections[I]); + + // At this point we know sections merged are fully identical and hence + // we want to remove duplicate implicit dependencies such as link order + // and relocation sections. + for (InputSection *IS : Sections[I]->DependentSections) + IS->Live = false; } }); - - // Mark ARM Exception Index table sections that refer to folded code - // sections as not live. These sections have an implict dependency - // via the link order dependency. - if (Config->EMachine == EM_ARM) - for (InputSectionBase *Sec : InputSections) - if (auto *S = dyn_cast<InputSection>(Sec)) - if (S->Flags & SHF_LINK_ORDER) - S->Live = S->getLinkOrderDep()->Live; } // ICF entry point function. diff --git a/ELF/ICF.h b/ELF/ICF.h index 24219855fc17..a6c8636ead6d 100644 --- a/ELF/ICF.h +++ b/ELF/ICF.h @@ -12,8 +12,10 @@ namespace lld { namespace elf { + template <class ELFT> void doIcf(); -} + +} // namespace elf } // namespace lld #endif diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index f514870ca84a..6da722f6f30e 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -38,14 +38,23 @@ using namespace llvm::sys::fs; using namespace lld; using namespace lld::elf; +bool InputFile::IsInGroup; +uint32_t InputFile::NextGroupId; std::vector<BinaryFile *> elf::BinaryFiles; std::vector<BitcodeFile *> elf::BitcodeFiles; +std::vector<LazyObjFile *> elf::LazyObjFiles; std::vector<InputFile *> elf::ObjectFiles; std::vector<InputFile *> elf::SharedFiles; TarWriter *elf::Tar; -InputFile::InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} +InputFile::InputFile(Kind K, MemoryBufferRef M) + : MB(M), GroupId(NextGroupId), FileKind(K) { + // All files within the same --{start,end}-group get the same group ID. + // Otherwise, a new file will get a new group ID. + if (!IsInGroup) + ++NextGroupId; +} Optional<MemoryBufferRef> elf::readFile(StringRef Path) { // The --chroot option changes our virtual root directory. @@ -55,7 +64,7 @@ Optional<MemoryBufferRef> elf::readFile(StringRef Path) { log(Path); - auto MBOrErr = MemoryBuffer::getFile(Path); + auto MBOrErr = MemoryBuffer::getFile(Path, -1, false); if (auto EC = MBOrErr.getError()) { error("cannot open " + Path + ": " + EC.message()); return None; @@ -115,51 +124,60 @@ std::string InputFile::getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, } template <class ELFT> void ObjFile<ELFT>::initializeDwarf() { - DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(this)); - const DWARFObject &Obj = Dwarf.getDWARFObj(); - DwarfLine.reset(new DWARFDebugLine); + Dwarf = llvm::make_unique<DWARFContext>(make_unique<LLDDwarfObj<ELFT>>(this)); + const DWARFObject &Obj = Dwarf->getDWARFObj(); DWARFDataExtractor LineData(Obj, Obj.getLineSection(), Config->IsLE, Config->Wordsize); - // The second parameter is offset in .debug_line section - // for compilation unit (CU) of interest. We have only one - // CU (object file), so offset is always 0. - // FIXME: Provide the associated DWARFUnit if there is one. DWARF v5 - // needs it in order to find indirect strings. - const DWARFDebugLine::LineTable *LT = - DwarfLine->getOrParseLineTable(LineData, 0, nullptr); - - // Return if there is no debug information about CU available. - if (!Dwarf.getNumCompileUnits()) - return; - - // Loop over variable records and insert them to VariableLoc. - DWARFCompileUnit *CU = Dwarf.getCompileUnitAtIndex(0); - for (const auto &Entry : CU->dies()) { - DWARFDie Die(CU, &Entry); - // Skip all tags that are not variables. - if (Die.getTag() != dwarf::DW_TAG_variable) + for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf->compile_units()) { + auto Report = [](Error Err) { + handleAllErrors(std::move(Err), + [](ErrorInfoBase &Info) { warn(Info.message()); }); + }; + Expected<const DWARFDebugLine::LineTable *> ExpectedLT = + Dwarf->getLineTableForUnit(CU.get(), Report); + const DWARFDebugLine::LineTable *LT = nullptr; + if (ExpectedLT) + LT = *ExpectedLT; + else + Report(ExpectedLT.takeError()); + if (!LT) continue; + LineTables.push_back(LT); - // Skip if a local variable because we don't need them for generating error - // messages. In general, only non-local symbols can fail to be linked. - if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) - continue; + // Loop over variable records and insert them to VariableLoc. + for (const auto &Entry : CU->dies()) { + DWARFDie Die(CU.get(), &Entry); + // Skip all tags that are not variables. + if (Die.getTag() != dwarf::DW_TAG_variable) + continue; - // Get the source filename index for the variable. - unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); - if (!LT->hasFileAtIndex(File)) - continue; + // Skip if a local variable because we don't need them for generating + // error messages. In general, only non-local symbols can fail to be + // linked. + if (!dwarf::toUnsigned(Die.find(dwarf::DW_AT_external), 0)) + continue; - // Get the line number on which the variable is declared. - unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); + // Get the source filename index for the variable. + unsigned File = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_file), 0); + if (!LT->hasFileAtIndex(File)) + continue; - // Get the name of the variable and add the collected information to - // VariableLoc. Usually Name is non-empty, but it can be empty if the input - // object file lacks some debug info. - StringRef Name = dwarf::toString(Die.find(dwarf::DW_AT_name), ""); - if (!Name.empty()) - VariableLoc.insert({Name, {File, Line}}); + // Get the line number on which the variable is declared. + unsigned Line = dwarf::toUnsigned(Die.find(dwarf::DW_AT_decl_line), 0); + + // Here we want to take the variable name to add it into VariableLoc. + // Variable can have regular and linkage name associated. At first, we try + // to get linkage name as it can be different, for example when we have + // two variables in different namespaces of the same object. Use common + // name otherwise, but handle the case when it also absent in case if the + // input object file lacks some debug info. + StringRef Name = + dwarf::toString(Die.find(dwarf::DW_AT_linkage_name), + dwarf::toString(Die.find(dwarf::DW_AT_name), "")); + if (!Name.empty()) + VariableLoc.insert({Name, {LT, File, Line}}); + } } } @@ -170,11 +188,6 @@ Optional<std::pair<std::string, unsigned>> ObjFile<ELFT>::getVariableLoc(StringRef Name) { llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); - // There is always only one CU so it's offset is 0. - const DWARFDebugLine::LineTable *LT = DwarfLine->getLineTable(0); - if (!LT) - return None; - // Return if we have no debug information about data object. auto It = VariableLoc.find(Name); if (It == VariableLoc.end()) @@ -182,12 +195,12 @@ ObjFile<ELFT>::getVariableLoc(StringRef Name) { // Take file name string from line table. std::string FileName; - if (!LT->getFileNameByIndex( - It->second.first /* File */, nullptr, + if (!It->second.LT->getFileNameByIndex( + It->second.File, nullptr, DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FileName)) return None; - return std::make_pair(FileName, It->second.second /*Line*/); + return std::make_pair(FileName, It->second.Line); } // Returns source line information for a given offset @@ -197,29 +210,15 @@ Optional<DILineInfo> ObjFile<ELFT>::getDILineInfo(InputSectionBase *S, uint64_t Offset) { llvm::call_once(InitDwarfLine, [this]() { initializeDwarf(); }); - // The offset to CU is 0. - const DWARFDebugLine::LineTable *Tbl = DwarfLine->getLineTable(0); - if (!Tbl) - return None; - // Use fake address calcuated by adding section file offset and offset in // section. See comments for ObjectInfo class. DILineInfo Info; - Tbl->getFileLineInfoForAddress( - S->getOffsetInFile() + Offset, nullptr, - DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info); - if (Info.Line == 0) - return None; - return Info; -} - -// Returns source line information for a given offset -// using DWARF debug info. -template <class ELFT> -std::string ObjFile<ELFT>::getLineInfo(InputSectionBase *S, uint64_t Offset) { - if (Optional<DILineInfo> Info = getDILineInfo(S, Offset)) - return Info->FileName + ":" + std::to_string(Info->Line); - return ""; + for (const llvm::DWARFDebugLine::LineTable *LT : LineTables) + if (LT->getFileLineInfoForAddress( + S->getOffsetInFile() + Offset, nullptr, + DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, Info)) + return Info; + return None; } // Returns "<internal>", "foo.a(bar.o)" or "baz.o". @@ -249,7 +248,7 @@ ELFFileBase<ELFT>::ELFFileBase(Kind K, MemoryBufferRef MB) : InputFile(K, MB) { template <class ELFT> typename ELFT::SymRange ELFFileBase<ELFT>::getGlobalELFSyms() { - return makeArrayRef(ELFSyms.begin() + FirstNonLocal, ELFSyms.end()); + return makeArrayRef(ELFSyms.begin() + FirstGlobal, ELFSyms.end()); } template <class ELFT> @@ -260,9 +259,9 @@ uint32_t ELFFileBase<ELFT>::getSectionIndex(const Elf_Sym &Sym) const { template <class ELFT> void ELFFileBase<ELFT>::initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab) { - FirstNonLocal = Symtab->sh_info; + FirstGlobal = Symtab->sh_info; ELFSyms = CHECK(getObj().symbols(Symtab), this); - if (FirstNonLocal == 0 || FirstNonLocal > ELFSyms.size()) + if (FirstGlobal == 0 || FirstGlobal > ELFSyms.size()) fatal(toString(this) + ": invalid sh_info in symbol table"); StringTable = @@ -278,13 +277,22 @@ ObjFile<ELFT>::ObjFile(MemoryBufferRef M, StringRef ArchiveName) template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getLocalSymbols() { if (this->Symbols.empty()) return {}; - return makeArrayRef(this->Symbols).slice(1, this->FirstNonLocal - 1); + return makeArrayRef(this->Symbols).slice(1, this->FirstGlobal - 1); +} + +template <class ELFT> ArrayRef<Symbol *> ObjFile<ELFT>::getGlobalSymbols() { + return makeArrayRef(this->Symbols).slice(this->FirstGlobal); } template <class ELFT> void ObjFile<ELFT>::parse(DenseSet<CachedHashStringRef> &ComdatGroups) { - // Read section and symbol tables. - initializeSections(ComdatGroups); + // Read a section table. JustSymbols is usually false. + if (this->JustSymbols) + initializeJustSymbols(); + else + initializeSections(ComdatGroups); + + // Read a symbol table. initializeSymbols(); } @@ -308,7 +316,7 @@ StringRef ObjFile<ELFT>::getShtGroupSignature(ArrayRef<Elf_Shdr> Sections, // we use a section name as a signature. // // Such SHT_GROUP sections are invalid from the perspective of the ELF - // standard, but GNU gold 1.14 (the neweset version as of July 2017) or + // standard, but GNU gold 1.14 (the newest version as of July 2017) or // older produce such sections as outputs for the -r option, so we need // a bug-compatibility. if (Signature.empty() && Sym->getType() == STT_SECTION) @@ -328,9 +336,19 @@ ObjFile<ELFT>::getShtGroupEntries(const Elf_Shdr &Sec) { } template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { - // We don't merge sections if -O0 (default is -O1). This makes sometimes - // the linker significantly faster, although the output will be bigger. - if (Config->Optimize == 0) + // On a regular link we don't merge sections if -O0 (default is -O1). This + // sometimes makes the linker significantly faster, although the output will + // be bigger. + // + // Doing the same for -r would create a problem as it would combine sections + // with different sh_entsize. One option would be to just copy every SHF_MERGE + // section as is to the output. While this would produce a valid ELF file with + // usable SHF_MERGE sections, tools like (llvm-)?dwarfdump get confused when + // they see two .debug_str. We could have separate logic for combining + // SHF_MERGE sections based both on their name and sh_entsize, but that seems + // to be more trouble than it is worth. Instead, we just use the regular (-O1) + // logic for -r. + if (Config->Optimize == 0 && !Config->Relocatable) return false; // A mergeable section with size 0 is useless because they don't have @@ -361,12 +379,33 @@ template <class ELFT> bool ObjFile<ELFT>::shouldMerge(const Elf_Shdr &Sec) { return true; } +// This is for --just-symbols. +// +// --just-symbols is a very minor feature that allows you to link your +// output against other existing program, so that if you load both your +// program and the other program into memory, your output can refer the +// other program's symbols. +// +// When the option is given, we link "just symbols". The section table is +// initialized with null pointers. +template <class ELFT> void ObjFile<ELFT>::initializeJustSymbols() { + ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this); + this->Sections.resize(ObjSections.size()); + + for (const Elf_Shdr &Sec : ObjSections) { + if (Sec.sh_type != SHT_SYMTAB) + continue; + this->initSymtab(ObjSections, &Sec); + return; + } +} + template <class ELFT> void ObjFile<ELFT>::initializeSections( DenseSet<CachedHashStringRef> &ComdatGroups) { const ELFFile<ELFT> &Obj = this->getObj(); - ArrayRef<Elf_Shdr> ObjSections = CHECK(this->getObj().sections(), this); + ArrayRef<Elf_Shdr> ObjSections = CHECK(Obj.sections(), this); uint64_t Size = ObjSections.size(); this->Sections.resize(Size); this->SectionStringTable = @@ -381,6 +420,17 @@ void ObjFile<ELFT>::initializeSections( // if -r is given, we'll let the final link discard such sections. // This is compatible with GNU. if ((Sec.sh_flags & SHF_EXCLUDE) && !Config->Relocatable) { + if (Sec.sh_type == SHT_LLVM_ADDRSIG) { + // We ignore the address-significance table if we know that the object + // file was created by objcopy or ld -r. This is because these tools + // will reorder the symbols in the symbol table, invalidating the data + // in the address-significance table, which refers to symbols by index. + if (Sec.sh_link != 0) + this->AddrsigSec = &Sec; + else if (Config->ICF == ICFLevel::Safe) + warn(toString(this) + ": --icf=safe is incompatible with object " + "files created using objcopy or ld -r"); + } this->Sections[I] = &InputSection::Discarded; continue; } @@ -431,8 +481,15 @@ void ObjFile<ELFT>::initializeSections( if (Sec.sh_link >= this->Sections.size()) fatal(toString(this) + ": invalid sh_link index: " + Twine(Sec.sh_link)); - this->Sections[Sec.sh_link]->DependentSections.push_back( - cast<InputSection>(this->Sections[I])); + + InputSectionBase *LinkSec = this->Sections[Sec.sh_link]; + InputSection *IS = cast<InputSection>(this->Sections[I]); + LinkSec->DependentSections.push_back(IS); + if (!isa<InputSection>(LinkSec)) + error("a section " + IS->Name + + " with SHF_LINK_ORDER should not refer a non-regular " + "section: " + + toString(LinkSec)); } } } @@ -527,10 +584,11 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { } case SHT_RELA: case SHT_REL: { - // Find the relocation target section and associate this - // section with it. Target can be discarded, for example - // if it is a duplicated member of SHT_GROUP section, we - // do not create or proccess relocatable sections then. + // Find a relocation target section and associate this section with that. + // Target may have been discarded if it is in a different section group + // and the group is discarded, even though it's a violation of the + // spec. We handle that situation gracefully by discarding dangling + // relocation sections. InputSectionBase *Target = getRelocTarget(Sec); if (!Target) return nullptr; @@ -545,32 +603,28 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { fatal(toString(this) + ": multiple relocation sections to one section are not supported"); - // Mergeable sections with relocations are tricky because relocations - // need to be taken into account when comparing section contents for - // merging. It's not worth supporting such mergeable sections because - // they are rare and it'd complicates the internal design (we usually - // have to determine if two sections are mergeable early in the link - // process much before applying relocations). We simply handle mergeable - // sections with relocations as non-mergeable. + // ELF spec allows mergeable sections with relocations, but they are + // rare, and it is in practice hard to merge such sections by contents, + // because applying relocations at end of linking changes section + // contents. So, we simply handle such sections as non-mergeable ones. + // Degrading like this is acceptable because section merging is optional. if (auto *MS = dyn_cast<MergeInputSection>(Target)) { Target = toRegularSection(MS); this->Sections[Sec.sh_info] = Target; } - size_t NumRelocations; if (Sec.sh_type == SHT_RELA) { ArrayRef<Elf_Rela> Rels = CHECK(this->getObj().relas(&Sec), this); Target->FirstRelocation = Rels.begin(); - NumRelocations = Rels.size(); + Target->NumRelocations = Rels.size(); Target->AreRelocsRela = true; } else { ArrayRef<Elf_Rel> Rels = CHECK(this->getObj().rels(&Sec), this); Target->FirstRelocation = Rels.begin(); - NumRelocations = Rels.size(); + Target->NumRelocations = Rels.size(); Target->AreRelocsRela = false; } - assert(isUInt<31>(NumRelocations)); - Target->NumRelocations = NumRelocations; + assert(isUInt<31>(Target->NumRelocations)); // Relocation sections processed by the linker are usually removed // from the output, so returning `nullptr` for the normal case. @@ -602,13 +656,24 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { if (Name == ".note.GNU-stack") return &InputSection::Discarded; - // Split stacks is a feature to support a discontiguous stack. At least - // as of 2017, it seems that the feature is not being used widely. - // Only GNU gold supports that. We don't. For the details about that, - // see https://gcc.gnu.org/wiki/SplitStacks + // Split stacks is a feature to support a discontiguous stack, + // commonly used in the programming language Go. For the details, + // see https://gcc.gnu.org/wiki/SplitStacks. An object file compiled + // for split stack will include a .note.GNU-split-stack section. if (Name == ".note.GNU-split-stack") { - error(toString(this) + - ": object file compiled with -fsplit-stack is not supported"); + if (Config->Relocatable) { + error("Cannot mix split-stack and non-split-stack in a relocatable link"); + return &InputSection::Discarded; + } + this->SplitStack = true; + return &InputSection::Discarded; + } + + // An object file cmpiled for split stack, but where some of the + // functions were compiled with the no_split_stack_attribute will + // include a .note.GNU-no-split-stack section. + if (Name == ".note.GNU-no-split-stack") { + this->SomeNoSplitStack = true; return &InputSection::Discarded; } @@ -620,6 +685,14 @@ InputSectionBase *ObjFile<ELFT>::createInputSection(const Elf_Shdr &Sec) { if (Name.startswith(".gnu.linkonce.")) return &InputSection::Discarded; + // If we are creating a new .build-id section, strip existing .build-id + // sections so that the output won't have more than one .build-id. + // This is not usually a problem because input object files normally don't + // have .build-id sections, but you can create such files by + // "ld.{bfd,gold,lld} -r --build-id", and we want to guard against it. + if (Name == ".note.gnu.build-id" && Config->BuildId != BuildIdKind::None) + return &InputSection::Discarded; + // The linker merges EH (exception handling) frames and creates a // .eh_frame_hdr section for runtime. So we handle them with a special // class. For relocatable outputs, they are just passed through. @@ -701,33 +774,33 @@ ArchiveFile::ArchiveFile(std::unique_ptr<Archive> &&File) File(std::move(File)) {} template <class ELFT> void ArchiveFile::parse() { - Symbols.reserve(File->getNumberOfSymbols()); for (const Archive::Symbol &Sym : File->symbols()) - Symbols.push_back(Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym)); + Symtab->addLazyArchive<ELFT>(Sym.getName(), *this, Sym); } // Returns a buffer pointing to a member file containing a given symbol. -std::pair<MemoryBufferRef, uint64_t> -ArchiveFile::getMember(const Archive::Symbol *Sym) { +InputFile *ArchiveFile::fetch(const Archive::Symbol &Sym) { Archive::Child C = - CHECK(Sym->getMember(), toString(this) + - ": could not get the member for symbol " + - Sym->getName()); + CHECK(Sym.getMember(), toString(this) + + ": could not get the member for symbol " + + Sym.getName()); if (!Seen.insert(C.getChildOffset()).second) - return {MemoryBufferRef(), 0}; + return nullptr; - MemoryBufferRef Ret = + MemoryBufferRef MB = CHECK(C.getMemoryBufferRef(), toString(this) + ": could not get the buffer for the member defining symbol " + - Sym->getName()); + Sym.getName()); + + if (Tar && C.getParent()->isThin()) + Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), MB.getBuffer()); - if (C.getParent()->isThin() && Tar) - Tar->append(relativeToRoot(CHECK(C.getFullName(), this)), Ret.getBuffer()); - if (C.getParent()->isThin()) - return {Ret, 0}; - return {Ret, C.getChildOffset()}; + InputFile *File = createObjectFile( + MB, getName(), C.getParent()->isThin() ? 0 : C.getChildOffset()); + File->GroupId = GroupId; + return File; } template <class ELFT> @@ -784,34 +857,42 @@ template <class ELFT> void SharedFile<ELFT>::parseSoName() { } } +// Parses ".gnu.version" section which is a parallel array for the symbol table. +// If a given file doesn't have ".gnu.version" section, returns VER_NDX_GLOBAL. +template <class ELFT> std::vector<uint32_t> SharedFile<ELFT>::parseVersyms() { + size_t Size = this->ELFSyms.size() - this->FirstGlobal; + if (!VersymSec) + return std::vector<uint32_t>(Size, VER_NDX_GLOBAL); + + const char *Base = this->MB.getBuffer().data(); + const Elf_Versym *Versym = + reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) + + this->FirstGlobal; + + std::vector<uint32_t> Ret(Size); + for (size_t I = 0; I < Size; ++I) + Ret[I] = Versym[I].vs_index; + return Ret; +} + // Parse the version definitions in the object file if present. Returns a vector // whose nth element contains a pointer to the Elf_Verdef for version identifier -// n. Version identifiers that are not definitions map to nullptr. The array -// always has at least length 1. +// n. Version identifiers that are not definitions map to nullptr. template <class ELFT> -std::vector<const typename ELFT::Verdef *> -SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) { - std::vector<const Elf_Verdef *> Verdefs(1); - // We only need to process symbol versions for this DSO if it has both a - // versym and a verdef section, which indicates that the DSO contains symbol - // version definitions. - if (!VersymSec || !VerdefSec) - return Verdefs; - - // The location of the first global versym entry. - const char *Base = this->MB.getBuffer().data(); - Versym = reinterpret_cast<const Elf_Versym *>(Base + VersymSec->sh_offset) + - this->FirstNonLocal; +std::vector<const typename ELFT::Verdef *> SharedFile<ELFT>::parseVerdefs() { + if (!VerdefSec) + return {}; // We cannot determine the largest verdef identifier without inspecting // every Elf_Verdef, but both bfd and gold assign verdef identifiers // sequentially starting from 1, so we predict that the largest identifier // will be VerdefCount. unsigned VerdefCount = VerdefSec->sh_info; - Verdefs.resize(VerdefCount + 1); + std::vector<const Elf_Verdef *> Verdefs(VerdefCount + 1); // Build the Verdefs array by following the chain of Elf_Verdef objects // from the start of the .gnu.version_d section. + const char *Base = this->MB.getBuffer().data(); const char *Verdef = Base + VerdefSec->sh_offset; for (unsigned I = 0; I != VerdefCount; ++I) { auto *CurVerdef = reinterpret_cast<const Elf_Verdef *>(Verdef); @@ -825,74 +906,99 @@ SharedFile<ELFT>::parseVerdefs(const Elf_Versym *&Versym) { return Verdefs; } +// We do not usually care about alignments of data in shared object +// files because the loader takes care of it. However, if we promote a +// DSO symbol to point to .bss due to copy relocation, we need to keep +// the original alignment requirements. We infer it in this function. +template <class ELFT> +uint32_t SharedFile<ELFT>::getAlignment(ArrayRef<Elf_Shdr> Sections, + const Elf_Sym &Sym) { + uint64_t Ret = UINT64_MAX; + if (Sym.st_value) + Ret = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); + if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) + Ret = std::min<uint64_t>(Ret, Sections[Sym.st_shndx].sh_addralign); + return (Ret > UINT32_MAX) ? 0 : Ret; +} + // Fully parse the shared object file. This must be called after parseSoName(). +// +// This function parses symbol versions. If a DSO has version information, +// the file has a ".gnu.version_d" section which contains symbol version +// definitions. Each symbol is associated to one version through a table in +// ".gnu.version" section. That table is a parallel array for the symbol +// table, and each table entry contains an index in ".gnu.version_d". +// +// The special index 0 is reserved for VERF_NDX_LOCAL and 1 is for +// VER_NDX_GLOBAL. There's no table entry for these special versions in +// ".gnu.version_d". +// +// The file format for symbol versioning is perhaps a bit more complicated +// than necessary, but you can easily understand the code if you wrap your +// head around the data structure described above. template <class ELFT> void SharedFile<ELFT>::parseRest() { - // Create mapping from version identifiers to Elf_Verdef entries. - const Elf_Versym *Versym = nullptr; - Verdefs = parseVerdefs(Versym); - + Verdefs = parseVerdefs(); // parse .gnu.version_d + std::vector<uint32_t> Versyms = parseVersyms(); // parse .gnu.version ArrayRef<Elf_Shdr> Sections = CHECK(this->getObj().sections(), this); + // System libraries can have a lot of symbols with versions. Using a + // fixed buffer for computing the versions name (foo@ver) can save a + // lot of allocations. + SmallString<0> VersionedNameBuffer; + // Add symbols to the symbol table. - Elf_Sym_Range Syms = this->getGlobalELFSyms(); - for (const Elf_Sym &Sym : Syms) { - unsigned VersymIndex = VER_NDX_GLOBAL; - if (Versym) { - VersymIndex = Versym->vs_index; - ++Versym; - } - bool Hidden = VersymIndex & VERSYM_HIDDEN; - VersymIndex = VersymIndex & ~VERSYM_HIDDEN; + ArrayRef<Elf_Sym> Syms = this->getGlobalELFSyms(); + for (size_t I = 0; I < Syms.size(); ++I) { + const Elf_Sym &Sym = Syms[I]; StringRef Name = CHECK(Sym.getName(this->StringTable), this); if (Sym.isUndefined()) { - Undefs.push_back(Name); + Symbol *S = Symtab->addUndefined<ELFT>(Name, Sym.getBinding(), + Sym.st_other, Sym.getType(), + /*CanOmitFromDynSym=*/false, this); + S->ExportDynamic = true; continue; } + // ELF spec requires that all local symbols precede weak or global + // symbols in each symbol table, and the index of first non-local symbol + // is stored to sh_info. If a local symbol appears after some non-local + // symbol, that's a violation of the spec. if (Sym.getBinding() == STB_LOCAL) { warn("found local symbol '" + Name + "' in global part of symbol table in file " + toString(this)); continue; } - const Elf_Verdef *Ver = nullptr; - if (VersymIndex != VER_NDX_GLOBAL) { - if (VersymIndex >= Verdefs.size() || VersymIndex == VER_NDX_LOCAL) { - error("corrupt input file: version definition index " + - Twine(VersymIndex) + " for symbol " + Name + - " is out of bounds\n>>> defined in " + toString(this)); - continue; - } - Ver = Verdefs[VersymIndex]; - } else { - VersymIndex = 0; - } - - // We do not usually care about alignments of data in shared object - // files because the loader takes care of it. However, if we promote a - // DSO symbol to point to .bss due to copy relocation, we need to keep - // the original alignment requirements. We infer it here. - uint64_t Alignment = 1; - if (Sym.st_value) - Alignment = 1ULL << countTrailingZeros((uint64_t)Sym.st_value); - if (0 < Sym.st_shndx && Sym.st_shndx < Sections.size()) { - uint64_t SecAlign = Sections[Sym.st_shndx].sh_addralign; - Alignment = std::min(Alignment, SecAlign); - } - if (Alignment > UINT32_MAX) - error(toString(this) + ": alignment too large: " + Name); + // MIPS BFD linker puts _gp_disp symbol into DSO files and incorrectly + // assigns VER_NDX_LOCAL to this section global symbol. Here is a + // workaround for this bug. + uint32_t Idx = Versyms[I] & ~VERSYM_HIDDEN; + if (Config->EMachine == EM_MIPS && Idx == VER_NDX_LOCAL && + Name == "_gp_disp") + continue; - if (!Hidden) - Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); + uint64_t Alignment = getAlignment(Sections, Sym); + if (!(Versyms[I] & VERSYM_HIDDEN)) + Symtab->addShared(Name, *this, Sym, Alignment, Idx); // Also add the symbol with the versioned name to handle undefined symbols // with explicit versions. - if (Ver) { - StringRef VerName = this->StringTable.data() + Ver->getAux()->vda_name; - Name = Saver.save(Name + "@" + VerName); - Symtab->addShared(Name, *this, Sym, Alignment, VersymIndex); + if (Idx == VER_NDX_GLOBAL) + continue; + + if (Idx >= Verdefs.size() || Idx == VER_NDX_LOCAL) { + error("corrupt input file: version definition index " + Twine(Idx) + + " for symbol " + Name + " is out of bounds\n>>> defined in " + + toString(this)); + continue; } + + StringRef VerName = + this->StringTable.data() + Verdefs[Idx]->getAux()->vda_name; + VersionedNameBuffer.clear(); + Name = (Name + "@" + VerName).toStringRef(VersionedNameBuffer); + Symtab->addShared(Saver.save(Name), *this, Sym, Alignment, Idx); } } @@ -925,8 +1031,9 @@ static uint8_t getBitcodeMachineKind(StringRef Path, const Triple &T) { case Triple::x86_64: return EM_X86_64; default: - fatal(Path + ": could not infer e_machine from bitcode target triple " + + error(Path + ": could not infer e_machine from bitcode target triple " + T.str()); + return EM_NONE; } } @@ -935,17 +1042,21 @@ BitcodeFile::BitcodeFile(MemoryBufferRef MB, StringRef ArchiveName, : InputFile(BitcodeKind, MB) { this->ArchiveName = ArchiveName; - // Here we pass a new MemoryBufferRef which is identified by ArchiveName - // (the fully resolved path of the archive) + member name + offset of the - // member in the archive. - // ThinLTO uses the MemoryBufferRef identifier to access its internal - // data structures and if two archives define two members with the same name, - // this causes a collision which result in only one of the objects being - // taken into consideration at LTO time (which very likely causes undefined - // symbols later in the link stage). - MemoryBufferRef MBRef(MB.getBuffer(), - Saver.save(ArchiveName + MB.getBufferIdentifier() + - utostr(OffsetInArchive))); + std::string Path = MB.getBufferIdentifier().str(); + if (Config->ThinLTOIndexOnly) + Path = replaceThinLTOSuffix(MB.getBufferIdentifier()); + + // ThinLTO assumes that all MemoryBufferRefs given to it have a unique + // name. If two archives define two members with the same name, this + // causes a collision which result in only one of the objects being taken + // into consideration at LTO time (which very likely causes undefined + // symbols later in the link stage). So we append file offset to make + // filename unique. + MemoryBufferRef MBRef( + MB.getBuffer(), + Saver.save(ArchiveName + Path + + (ArchiveName.empty() ? "" : utostr(OffsetInArchive)))); + Obj = CHECK(lto::InputFile::create(MBRef), this); Triple T(Obj->getTargetTriple()); @@ -969,7 +1080,7 @@ template <class ELFT> static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, const lto::InputFile::Symbol &ObjSym, BitcodeFile &F) { - StringRef NameRef = Saver.save(ObjSym.getName()); + StringRef Name = Saver.save(ObjSym.getName()); uint32_t Binding = ObjSym.isWeak() ? STB_WEAK : STB_GLOBAL; uint8_t Type = ObjSym.isTLS() ? STT_TLS : STT_NOTYPE; @@ -978,20 +1089,20 @@ static Symbol *createBitcodeSymbol(const std::vector<bool> &KeptComdats, int C = ObjSym.getComdatIndex(); if (C != -1 && !KeptComdats[C]) - return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, + return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type, CanOmitFromDynSym, &F); if (ObjSym.isUndefined()) - return Symtab->addUndefined<ELFT>(NameRef, Binding, Visibility, Type, + return Symtab->addUndefined<ELFT>(Name, Binding, Visibility, Type, CanOmitFromDynSym, &F); if (ObjSym.isCommon()) - return Symtab->addCommon(NameRef, ObjSym.getCommonSize(), + return Symtab->addCommon(Name, ObjSym.getCommonSize(), ObjSym.getCommonAlignment(), Binding, Visibility, STT_OBJECT, F); - return Symtab->addBitcode(NameRef, Binding, Visibility, Type, - CanOmitFromDynSym, F); + return Symtab->addBitcode(Name, Binding, Visibility, Type, CanOmitFromDynSym, + F); } template <class ELFT> @@ -1026,8 +1137,8 @@ static ELFKind getELFKind(MemoryBufferRef MB) { void BinaryFile::parse() { ArrayRef<uint8_t> Data = toArrayRef(MB.getBuffer()); - auto *Section = make<InputSection>(nullptr, SHF_ALLOC | SHF_WRITE, - SHT_PROGBITS, 8, Data, ".data"); + auto *Section = make<InputSection>(this, SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, + 8, Data, ".data"); Sections.push_back(Section); // For each input file foo that is embedded to a result as a binary @@ -1047,11 +1158,6 @@ void BinaryFile::parse() { Data.size(), 0, STB_GLOBAL, nullptr, nullptr); } -static bool isBitcode(MemoryBufferRef MB) { - using namespace sys::fs; - return identify_magic(MB.getBuffer()) == file_magic::bitcode; -} - InputFile *elf::createObjectFile(MemoryBufferRef MB, StringRef ArchiveName, uint64_t OffsetInArchive) { if (isBitcode(MB)) @@ -1087,9 +1193,9 @@ InputFile *elf::createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName) { } MemoryBufferRef LazyObjFile::getBuffer() { - if (Seen) + if (AddedToLink) return MemoryBufferRef(); - Seen = true; + AddedToLink = true; return MB; } @@ -1097,66 +1203,72 @@ InputFile *LazyObjFile::fetch() { MemoryBufferRef MBRef = getBuffer(); if (MBRef.getBuffer().empty()) return nullptr; - return createObjectFile(MBRef, ArchiveName, OffsetInArchive); + + InputFile *File = createObjectFile(MBRef, ArchiveName, OffsetInArchive); + File->GroupId = GroupId; + return File; } template <class ELFT> void LazyObjFile::parse() { - for (StringRef Sym : getSymbolNames()) - Symtab->addLazyObject<ELFT>(Sym, *this); + // A lazy object file wraps either a bitcode file or an ELF file. + if (isBitcode(this->MB)) { + std::unique_ptr<lto::InputFile> Obj = + CHECK(lto::InputFile::create(this->MB), this); + for (const lto::InputFile::Symbol &Sym : Obj->symbols()) + if (!Sym.isUndefined()) + Symtab->addLazyObject<ELFT>(Saver.save(Sym.getName()), *this); + return; + } + + switch (getELFKind(this->MB)) { + case ELF32LEKind: + addElfSymbols<ELF32LE>(); + return; + case ELF32BEKind: + addElfSymbols<ELF32BE>(); + return; + case ELF64LEKind: + addElfSymbols<ELF64LE>(); + return; + case ELF64BEKind: + addElfSymbols<ELF64BE>(); + return; + default: + llvm_unreachable("getELFKind"); + } } -template <class ELFT> std::vector<StringRef> LazyObjFile::getElfSymbols() { - typedef typename ELFT::Shdr Elf_Shdr; - typedef typename ELFT::Sym Elf_Sym; - typedef typename ELFT::SymRange Elf_Sym_Range; +template <class ELFT> void LazyObjFile::addElfSymbols() { + ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(MB.getBuffer())); + ArrayRef<typename ELFT::Shdr> Sections = CHECK(Obj.sections(), this); - ELFFile<ELFT> Obj = check(ELFFile<ELFT>::create(this->MB.getBuffer())); - ArrayRef<Elf_Shdr> Sections = CHECK(Obj.sections(), this); - for (const Elf_Shdr &Sec : Sections) { + for (const typename ELFT::Shdr &Sec : Sections) { if (Sec.sh_type != SHT_SYMTAB) continue; - Elf_Sym_Range Syms = CHECK(Obj.symbols(&Sec), this); - uint32_t FirstNonLocal = Sec.sh_info; + typename ELFT::SymRange Syms = CHECK(Obj.symbols(&Sec), this); + uint32_t FirstGlobal = Sec.sh_info; StringRef StringTable = CHECK(Obj.getStringTableForSymtab(Sec, Sections), this); - std::vector<StringRef> V; - for (const Elf_Sym &Sym : Syms.slice(FirstNonLocal)) + for (const typename ELFT::Sym &Sym : Syms.slice(FirstGlobal)) if (Sym.st_shndx != SHN_UNDEF) - V.push_back(CHECK(Sym.getName(StringTable), this)); - return V; + Symtab->addLazyObject<ELFT>(CHECK(Sym.getName(StringTable), this), + *this); + return; } - return {}; } -std::vector<StringRef> LazyObjFile::getBitcodeSymbols() { - std::unique_ptr<lto::InputFile> Obj = - CHECK(lto::InputFile::create(this->MB), this); - std::vector<StringRef> V; - for (const lto::InputFile::Symbol &Sym : Obj->symbols()) - if (!Sym.isUndefined()) - V.push_back(Saver.save(Sym.getName())); - return V; -} +std::string elf::replaceThinLTOSuffix(StringRef Path) { + StringRef Suffix = Config->ThinLTOObjectSuffixReplace.first; + StringRef Repl = Config->ThinLTOObjectSuffixReplace.second; -// Returns a vector of globally-visible defined symbol names. -std::vector<StringRef> LazyObjFile::getSymbolNames() { - if (isBitcode(this->MB)) - return getBitcodeSymbols(); - - switch (getELFKind(this->MB)) { - case ELF32LEKind: - return getElfSymbols<ELF32LE>(); - case ELF32BEKind: - return getElfSymbols<ELF32BE>(); - case ELF64LEKind: - return getElfSymbols<ELF64LE>(); - case ELF64BEKind: - return getElfSymbols<ELF64BE>(); - default: - llvm_unreachable("getELFKind"); + if (!Path.endswith(Suffix)) { + error("-thinlto-object-suffix-replace=" + Suffix + ";" + Repl + + " was given, but " + Path + " does not end with the suffix"); + return ""; } + return (Path.drop_back(Suffix.size()) + Repl).str(); } template void ArchiveFile::parse<ELF32LE>(); diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h index dda1de81570c..0db3203b0ba2 100644 --- a/ELF/InputFiles.h +++ b/ELF/InputFiles.h @@ -12,22 +12,20 @@ #include "Config.h" #include "lld/Common/ErrorHandler.h" - #include "lld/Common/LLVM.h" #include "lld/Common/Reproduce.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h" #include "llvm/IR/Comdat.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Support/Threading.h" - #include <map> namespace llvm { -class DWARFDebugLine; class TarWriter; struct DILineInfo; namespace lto { @@ -48,7 +46,6 @@ namespace elf { using llvm::object::Archive; -class Lazy; class Symbol; // If -reproduce option is given, all input files are written @@ -90,15 +87,15 @@ public: // Returns object file symbols. It is a runtime error to call this // function on files of other types. ArrayRef<Symbol *> getSymbols() { - assert(FileKind == ObjKind || FileKind == BitcodeKind || - FileKind == ArchiveKind); + assert(FileKind == BinaryKind || FileKind == ObjKind || + FileKind == BitcodeKind); return Symbols; } // Filename of .a which contained this file. If this file was // not in an archive file, it is the empty string. We use this // string for creating error messages. - StringRef ArchiveName; + std::string ArchiveName; // If this is an architecture-specific file, the following members // have ELF type (i.e. ELF{32,64}{LE,BE}) and target machine type. @@ -112,6 +109,20 @@ public: std::string getSrcMsg(const Symbol &Sym, InputSectionBase &Sec, uint64_t Offset); + // True if this is an argument for --just-symbols. Usually false. + bool JustSymbols = false; + + // GroupId is used for --warn-backrefs which is an optional error + // checking feature. All files within the same --{start,end}-group or + // --{start,end}-lib get the same group ID. Otherwise, each file gets a new + // group ID. For more info, see checkDependency() in SymbolTable.cpp. + uint32_t GroupId; + static bool IsInGroup; + static uint32_t NextGroupId; + + // Index of MIPS GOT built for this file. + llvm::Optional<size_t> MipsGotIndex; + protected: InputFile(Kind K, MemoryBufferRef M); std::vector<InputSectionBase *> Sections; @@ -144,7 +155,7 @@ public: protected: ArrayRef<Elf_Sym> ELFSyms; - uint32_t FirstNonLocal = 0; + uint32_t FirstGlobal = 0; ArrayRef<Elf_Word> SymtabSHNDX; StringRef StringTable; void initSymtab(ArrayRef<Elf_Shdr> Sections, const Elf_Shdr *Symtab); @@ -167,6 +178,7 @@ public: static bool classof(const InputFile *F) { return F->kind() == Base::ObjKind; } ArrayRef<Symbol *> getLocalSymbols(); + ArrayRef<Symbol *> getGlobalSymbols(); ObjFile(MemoryBufferRef M, StringRef ArchiveName); void parse(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); @@ -182,9 +194,6 @@ public: return getSymbol(SymIndex); } - // Returns source line information for a given offset. - // If no information is available, returns "". - std::string getLineInfo(InputSectionBase *S, uint64_t Offset); llvm::Optional<llvm::DILineInfo> getDILineInfo(InputSectionBase *, uint64_t); llvm::Optional<std::pair<std::string, unsigned>> getVariableLoc(StringRef Name); @@ -198,10 +207,22 @@ public: // symbol table. StringRef SourceFile; + // True if the file defines functions compiled with + // -fsplit-stack. Usually false. + bool SplitStack = false; + + // True if the file defines functions compiled with -fsplit-stack, + // but had one or more functions with the no_split_stack attribute. + bool SomeNoSplitStack = false; + + // Pointer to this input file's .llvm_addrsig section, if it has one. + const Elf_Shdr *AddrsigSec = nullptr; + private: void initializeSections(llvm::DenseSet<llvm::CachedHashStringRef> &ComdatGroups); void initializeSymbols(); + void initializeJustSymbols(); void initializeDwarf(); InputSectionBase *getRelocTarget(const Elf_Shdr &Sec); InputSectionBase *createInputSection(const Elf_Shdr &Sec); @@ -217,8 +238,14 @@ private: // reporting. Linker may find reasonable number of errors in a // single object file, so we cache debugging information in order to // parse it only once for each object file we link. - std::unique_ptr<llvm::DWARFDebugLine> DwarfLine; - llvm::DenseMap<StringRef, std::pair<unsigned, unsigned>> VariableLoc; + std::unique_ptr<llvm::DWARFContext> Dwarf; + std::vector<const llvm::DWARFDebugLine::LineTable *> LineTables; + struct VarLoc { + const llvm::DWARFDebugLine::LineTable *LT; + unsigned File; + unsigned Line; + }; + llvm::DenseMap<StringRef, VarLoc> VariableLoc; llvm::once_flag InitDwarfLine; }; @@ -242,13 +269,11 @@ public: template <class ELFT> void parse(); MemoryBufferRef getBuffer(); InputFile *fetch(); + bool AddedToLink = false; private: - std::vector<StringRef> getSymbolNames(); - template <class ELFT> std::vector<StringRef> getElfSymbols(); - std::vector<StringRef> getBitcodeSymbols(); + template <class ELFT> void addElfSymbols(); - bool Seen = false; uint64_t OffsetInArchive; }; @@ -259,11 +284,11 @@ public: static bool classof(const InputFile *F) { return F->kind() == ArchiveKind; } template <class ELFT> void parse(); - // Returns a memory buffer for a given symbol and the offset in the archive - // for the member. An empty memory buffer and an offset of zero - // is returned if we have already returned the same memory buffer. - // (So that we don't instantiate same members more than once.) - std::pair<MemoryBufferRef, uint64_t> getMember(const Archive::Symbol *Sym); + // Pulls out an object file that contains a definition for Sym and + // returns it. If the same file was instantiated before, this + // function returns a nullptr (so we don't instantiate the same file + // more than once.) + InputFile *fetch(const Archive::Symbol &Sym); private: std::unique_ptr<Archive> File; @@ -290,7 +315,6 @@ template <class ELFT> class SharedFile : public ELFFileBase<ELFT> { typedef typename ELFT::Verdef Elf_Verdef; typedef typename ELFT::Versym Elf_Versym; - std::vector<StringRef> Undefs; const Elf_Shdr *VersymSec = nullptr; const Elf_Shdr *VerdefSec = nullptr; @@ -298,8 +322,6 @@ public: std::vector<const Elf_Verdef *> Verdefs; std::string SoName; - llvm::ArrayRef<StringRef> getUndefinedSymbols() { return Undefs; } - static bool classof(const InputFile *F) { return F->kind() == Base::SharedKind; } @@ -308,7 +330,9 @@ public: void parseSoName(); void parseRest(); - std::vector<const Elf_Verdef *> parseVerdefs(const Elf_Versym *&Versym); + uint32_t getAlignment(ArrayRef<Elf_Shdr> Sections, const Elf_Sym &Sym); + std::vector<const Elf_Verdef *> parseVerdefs(); + std::vector<uint32_t> parseVersyms(); struct NeededVer { // The string table offset of the version name in the output file. @@ -337,8 +361,15 @@ InputFile *createObjectFile(MemoryBufferRef MB, StringRef ArchiveName = "", uint64_t OffsetInArchive = 0); InputFile *createSharedFile(MemoryBufferRef MB, StringRef DefaultSoName); +inline bool isBitcode(MemoryBufferRef MB) { + return identify_magic(MB.getBuffer()) == llvm::file_magic::bitcode; +} + +std::string replaceThinLTOSuffix(StringRef Path); + extern std::vector<BinaryFile *> BinaryFiles; extern std::vector<BitcodeFile *> BitcodeFiles; +extern std::vector<LazyObjFile *> LazyObjFiles; extern std::vector<InputFile *> ObjectFiles; extern std::vector<InputFile *> SharedFiles; diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index 93baefadce6e..d6e9a19051e0 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -14,6 +14,7 @@ #include "LinkerScript.h" #include "OutputSections.h" #include "Relocations.h" +#include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" @@ -26,7 +27,10 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/Threading.h" #include "llvm/Support/xxhash.h" +#include <algorithm> #include <mutex> +#include <set> +#include <vector> using namespace llvm; using namespace llvm::ELF; @@ -45,32 +49,6 @@ std::string lld::toString(const InputSectionBase *Sec) { return (toString(Sec->File) + ":(" + Sec->Name + ")").str(); } -DenseMap<SectionBase *, int> elf::buildSectionOrder() { - DenseMap<SectionBase *, int> SectionOrder; - if (Config->SymbolOrderingFile.empty()) - return SectionOrder; - - // Build a map from symbols to their priorities. Symbols that didn't - // appear in the symbol ordering file have the lowest priority 0. - // All explicitly mentioned symbols have negative (higher) priorities. - DenseMap<StringRef, int> SymbolOrder; - int Priority = -Config->SymbolOrderingFile.size(); - for (StringRef S : Config->SymbolOrderingFile) - SymbolOrder.insert({S, Priority++}); - - // Build a map from sections to their priorities. - for (InputFile *File : ObjectFiles) { - for (Symbol *Sym : File->getSymbols()) { - auto *D = dyn_cast<Defined>(Sym); - if (!D || !D->Section) - continue; - int &Priority = SectionOrder[D->Section]; - Priority = std::min(Priority, SymbolOrder.lookup(D->getName())); - } - } - return SectionOrder; -} - template <class ELFT> static ArrayRef<uint8_t> getSectionContents(ObjFile<ELFT> &File, const typename ELFT::Shdr &Hdr) { @@ -168,12 +146,8 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const { return Offset == uint64_t(-1) ? OS->Size : Offset; } case Regular: - return cast<InputSection>(this)->OutSecOff + Offset; - case Synthetic: { - auto *IS = cast<InputSection>(this); - // For synthetic sections we treat offset -1 as the end of the section. - return IS->OutSecOff + (Offset == uint64_t(-1) ? IS->getSize() : Offset); - } + case Synthetic: + return cast<InputSection>(this)->getOffset(Offset); case EHFrame: // The file crtbeginT.o has relocations pointing to the start of an empty // .eh_frame that is known to be the first in the link. It does that to @@ -182,16 +156,21 @@ uint64_t SectionBase::getOffset(uint64_t Offset) const { case Merge: const MergeInputSection *MS = cast<MergeInputSection>(this); if (InputSection *IS = MS->getParent()) - return IS->OutSecOff + MS->getOffset(Offset); - return MS->getOffset(Offset); + return IS->getOffset(MS->getParentOffset(Offset)); + return MS->getParentOffset(Offset); } llvm_unreachable("invalid section kind"); } +uint64_t SectionBase::getVA(uint64_t Offset) const { + const OutputSection *Out = getOutputSection(); + return (Out ? Out->Addr : 0) + getOffset(Offset); +} + OutputSection *SectionBase::getOutputSection() { InputSection *Sec; if (auto *IS = dyn_cast<InputSection>(this)) - return IS->getParent(); + Sec = IS; else if (auto *MS = dyn_cast<MergeInputSection>(this)) Sec = MS->getParent(); else if (auto *EH = dyn_cast<EhInputSection>(this)) @@ -201,34 +180,50 @@ OutputSection *SectionBase::getOutputSection() { return Sec ? Sec->getParent() : nullptr; } -// Uncompress section contents if required. Note that this function +// Decompress section contents if required. Note that this function // is called from parallelForEach, so it must be thread-safe. -void InputSectionBase::maybeUncompress() { - if (UncompressBuf || !Decompressor::isCompressedELFSection(Flags, Name)) +void InputSectionBase::maybeDecompress() { + if (DecompressBuf) + return; + if (!(Flags & SHF_COMPRESSED) && !Name.startswith(".zdebug")) return; + // Decompress a section. Decompressor Dec = check(Decompressor::create(Name, toStringRef(Data), Config->IsLE, Config->Is64)); size_t Size = Dec.getDecompressedSize(); - UncompressBuf.reset(new char[Size]()); - if (Error E = Dec.decompress({UncompressBuf.get(), Size})) + DecompressBuf.reset(new char[Size + Name.size()]()); + if (Error E = Dec.decompress({DecompressBuf.get(), Size})) fatal(toString(this) + ": decompress failed: " + llvm::toString(std::move(E))); - Data = makeArrayRef((uint8_t *)UncompressBuf.get(), Size); + Data = makeArrayRef((uint8_t *)DecompressBuf.get(), Size); Flags &= ~(uint64_t)SHF_COMPRESSED; + + // A section name may have been altered if compressed. If that's + // the case, restore the original name. (i.e. ".zdebug_" -> ".debug_") + if (Name.startswith(".zdebug")) { + DecompressBuf[Size] = '.'; + memcpy(&DecompressBuf[Size + 1], Name.data() + 2, Name.size() - 2); + Name = StringRef(&DecompressBuf[Size], Name.size() - 1); + } } InputSection *InputSectionBase::getLinkOrderDep() const { - if ((Flags & SHF_LINK_ORDER) && Link != 0) { - InputSectionBase *L = File->getSections()[Link]; - if (auto *IS = dyn_cast<InputSection>(L)) - return IS; - error("a section with SHF_LINK_ORDER should not refer a non-regular " - "section: " + - toString(L)); - } + assert(Link); + assert(Flags & SHF_LINK_ORDER); + return cast<InputSection>(File->getSections()[Link]); +} + +// Find a function symbol that encloses a given location. +template <class ELFT> +Defined *InputSectionBase::getEnclosingFunction(uint64_t Offset) { + for (Symbol *B : File->getSymbols()) + if (Defined *D = dyn_cast<Defined>(B)) + if (D->Section == this && D->Type == STT_FUNC && + D->Value <= Offset && Offset < D->Value + D->Size) + return D; return nullptr; } @@ -241,9 +236,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) { .str(); // First check if we can get desired values from debugging information. - std::string LineInfo = getFile<ELFT>()->getLineInfo(this, Offset); - if (!LineInfo.empty()) - return LineInfo; + if (Optional<DILineInfo> Info = getFile<ELFT>()->getDILineInfo(this, Offset)) + return Info->FileName + ":" + std::to_string(Info->Line); // File->SourceFile contains STT_FILE symbol that contains a // source file name. If it's missing, we use an object file name. @@ -251,12 +245,8 @@ std::string InputSectionBase::getLocation(uint64_t Offset) { if (SrcFile.empty()) SrcFile = toString(File); - // Find a function symbol that encloses a given location. - for (Symbol *B : File->getSymbols()) - if (auto *D = dyn_cast<Defined>(B)) - if (D->Section == this && D->Type == STT_FUNC) - if (D->Value <= Offset && Offset < D->Value + D->Size) - return SrcFile + ":(function " + toString(*D) + ")"; + if (Defined *D = getEnclosingFunction<ELFT>(Offset)) + return SrcFile + ":(function " + toString(*D) + ")"; // If there's no symbol, print out the offset in the section. return (SrcFile + ":(" + Name + "+0x" + utohexstr(Offset) + ")").str(); @@ -292,7 +282,7 @@ std::string InputSectionBase::getObjMsg(uint64_t Off) { std::string Archive; if (!File->ArchiveName.empty()) - Archive = (" in archive " + File->ArchiveName).str(); + Archive = " in archive " + File->ArchiveName; // Find a symbol that encloses a given location. for (Symbol *B : File->getSymbols()) @@ -345,8 +335,9 @@ template <class ELFT> void InputSection::copyShtGroup(uint8_t *Buf) { *To++ = Sections[Idx]->getOutputSection()->SectionIndex; } -InputSectionBase *InputSection::getRelocatedSection() { - assert(Type == SHT_RELA || Type == SHT_REL); +InputSectionBase *InputSection::getRelocatedSection() const { + if (!File || (Type != SHT_RELA && Type != SHT_REL)) + return nullptr; ArrayRef<InputSectionBase *> Sections = File->getSections(); return Sections[Info]; } @@ -365,12 +356,12 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); Buf += sizeof(RelTy); - if (Config->IsRela) + if (RelTy::IsRela) P->r_addend = getAddend<ELFT>(Rel); // Output section VA is zero for -r, so r_offset is an offset within the // section, but for --emit-relocs it is an virtual address. - P->r_offset = Sec->getOutputSection()->Addr + Sec->getOffset(Rel.r_offset); + P->r_offset = Sec->getVA(Rel.r_offset); P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Sym), Type, Config->IsMips64EL); @@ -395,17 +386,32 @@ void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { continue; } - if (Config->IsRela) { - P->r_addend = - Sym.getVA(getAddend<ELFT>(Rel)) - Section->getOutputSection()->Addr; - } else if (Config->Relocatable) { - const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset; - Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, - Target->getImplicitAddend(BufLoc, Type), - &Sym}); + int64_t Addend = getAddend<ELFT>(Rel); + const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset; + if (!RelTy::IsRela) + Addend = Target->getImplicitAddend(BufLoc, Type); + + if (Config->EMachine == EM_MIPS && Config->Relocatable && + Target->getRelExpr(Type, Sym, BufLoc) == R_MIPS_GOTREL) { + // Some MIPS relocations depend on "gp" value. By default, + // this value has 0x7ff0 offset from a .got section. But + // relocatable files produced by a complier or a linker + // might redefine this default value and we must use it + // for a calculation of the relocation result. When we + // generate EXE or DSO it's trivial. Generating a relocatable + // output is more difficult case because the linker does + // not calculate relocations in this mode and loses + // individual "gp" values used by each input object file. + // As a workaround we add the "gp" value to the relocation + // addend and save it back to the file. + Addend += Sec->getFile<ELFT>()->MipsGp0; } - } + if (RelTy::IsRela) + P->r_addend = Sym.getVA(Addend) - Section->getOutputSection()->Addr; + else if (Config->Relocatable) + Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Addend, &Sym}); + } } } @@ -481,14 +487,17 @@ static uint64_t getARMStaticBase(const Symbol &Sym) { return OS->PtLoad->FirstSec->Addr; } -static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, - const Symbol &Sym, RelExpr Expr) { +static uint64_t getRelocTargetVA(const InputFile *File, RelType Type, int64_t A, + uint64_t P, const Symbol &Sym, RelExpr Expr) { switch (Expr) { case R_INVALID: return 0; case R_ABS: + case R_RELAX_TLS_LD_TO_LE_ABS: case R_RELAX_GOT_PC_NOPIC: return Sym.getVA(A); + case R_ADDEND: + return A; case R_ARM_SBREL: return Sym.getVA(A) - getARMStaticBase(Sym); case R_GOT: @@ -505,7 +514,9 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, case R_GOT_FROM_END: case R_RELAX_TLS_GD_TO_IE_END: return Sym.getGotOffset() + A - InX::Got->getSize(); + case R_TLSLD_GOT_OFF: case R_GOT_OFF: + case R_RELAX_TLS_GD_TO_IE_GOT_OFF: return Sym.getGotOffset() + A; case R_GOT_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: @@ -516,11 +527,12 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, case R_HINT: case R_NONE: case R_TLSDESC_CALL: + case R_TLSLD_HINT: llvm_unreachable("cannot relocate hint relocs"); case R_MIPS_GOTREL: - return Sym.getVA(A) - InX::MipsGot->getGp(); + return Sym.getVA(A) - InX::MipsGot->getGp(File); case R_MIPS_GOT_GP: - return InX::MipsGot->getGp() + A; + return InX::MipsGot->getGp(File) + A; case R_MIPS_GOT_GP_PC: { // R_MIPS_LO16 expression has R_MIPS_GOT_GP_PC type iif the target // is _gp_disp symbol. In that case we should use the following @@ -529,7 +541,7 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, // microMIPS variants of these relocations use slightly different // expressions: AHL + GP - P + 3 for %lo() and AHL + GP - P - 1 for %hi() // to correctly handle less-sugnificant bit of the microMIPS symbol. - uint64_t V = InX::MipsGot->getGp() + A - P; + uint64_t V = InX::MipsGot->getGp(File) + A - P; if (Type == R_MIPS_LO16 || Type == R_MICROMIPS_LO16) V += 4; if (Type == R_MICROMIPS_LO16 || Type == R_MICROMIPS_HI16) @@ -540,21 +552,23 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, // If relocation against MIPS local symbol requires GOT entry, this entry // should be initialized by 'page address'. This address is high 16-bits // of sum the symbol's value and the addend. - return InX::MipsGot->getVA() + InX::MipsGot->getPageEntryOffset(Sym, A) - - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getPageEntryOffset(File, Sym, A) - + InX::MipsGot->getGp(File); case R_MIPS_GOT_OFF: case R_MIPS_GOT_OFF32: // In case of MIPS if a GOT relocation has non-zero addend this addend // should be applied to the GOT entry content not to the GOT entry offset. // That is why we use separate expression type. - return InX::MipsGot->getVA() + InX::MipsGot->getSymEntryOffset(Sym, A) - - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + + InX::MipsGot->getSymEntryOffset(File, Sym, A) - + InX::MipsGot->getGp(File); case R_MIPS_TLSGD: - return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + - InX::MipsGot->getGlobalDynOffset(Sym) - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + InX::MipsGot->getGlobalDynOffset(File, Sym) - + InX::MipsGot->getGp(File); case R_MIPS_TLSLD: - return InX::MipsGot->getVA() + InX::MipsGot->getTlsOffset() + - InX::MipsGot->getTlsIndexOff() - InX::MipsGot->getGp(); + return InX::MipsGot->getVA() + InX::MipsGot->getTlsIndexOffset(File) - + InX::MipsGot->getGp(File); case R_PAGE_PC: case R_PLT_PAGE_PC: { uint64_t Dest; @@ -583,25 +597,27 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, case R_PLT: return Sym.getPltVA() + A; case R_PLT_PC: - case R_PPC_PLT_OPD: + case R_PPC_CALL_PLT: return Sym.getPltVA() + A - P; - case R_PPC_OPD: { + case R_PPC_CALL: { uint64_t SymVA = Sym.getVA(A); // If we have an undefined weak symbol, we might get here with a symbol // address of zero. That could overflow, but the code must be unreachable, // so don't bother doing anything at all. if (!SymVA) return 0; - if (Out::Opd) { - // If this is a local call, and we currently have the address of a - // function-descriptor, get the underlying code address instead. - uint64_t OpdStart = Out::Opd->Addr; - uint64_t OpdEnd = OpdStart + Out::Opd->Size; - bool InOpd = OpdStart <= SymVA && SymVA < OpdEnd; - if (InOpd) - SymVA = read64be(&Out::OpdBuf[SymVA - OpdStart]); - } - return SymVA - P; + + // PPC64 V2 ABI describes two entry points to a function. The global entry + // point sets up the TOC base pointer. When calling a local function, the + // call should branch to the local entry point rather than the global entry + // point. Section 3.4.1 describes using the 3 most significant bits of the + // st_other field to find out how many instructions there are between the + // local and global entry point. + uint8_t StOther = (Sym.StOther >> 5) & 7; + if (StOther == 0 || StOther == 1) + return SymVA - P; + + return SymVA - P + (1LL << StOther); } case R_PPC_TOC: return getPPC64TocBase() + A; @@ -618,25 +634,44 @@ static uint64_t getRelocTargetVA(RelType Type, int64_t A, uint64_t P, // statically to zero. if (Sym.isTls() && Sym.isUndefWeak()) return 0; - if (Target->TcbSize) + + // For TLS variant 1 the TCB is a fixed size, whereas for TLS variant 2 the + // TCB is on unspecified size and content. Targets that implement variant 1 + // should set TcbSize. + if (Target->TcbSize) { + // PPC64 V2 ABI has the thread pointer offset into the middle of the TLS + // storage area by TlsTpOffset for efficient addressing TCB and up to + // 4KB – 8 B of other thread library information (placed before the TCB). + // Subtracting this offset will get the address of the first TLS block. + if (Target->TlsTpOffset) + return Sym.getVA(A) - Target->TlsTpOffset; + + // If thread pointer is not offset into the middle, the first thing in the + // TLS storage area is the TCB. Add the TcbSize to get the address of the + // first TLS block. return Sym.getVA(A) + alignTo(Target->TcbSize, Out::TlsPhdr->p_align); + } return Sym.getVA(A) - Out::TlsPhdr->p_memsz; case R_RELAX_TLS_GD_TO_LE_NEG: case R_NEG_TLS: return Out::TlsPhdr->p_memsz - Sym.getVA(A); case R_SIZE: - return A; // Sym.getSize was already folded into the addend. + return Sym.getSize() + A; case R_TLSDESC: return InX::Got->getGlobalDynAddr(Sym) + A; case R_TLSDESC_PAGE: return getAArch64Page(InX::Got->getGlobalDynAddr(Sym) + A) - getAArch64Page(P); - case R_TLSGD: + case R_TLSGD_GOT: + return InX::Got->getGlobalDynOffset(Sym) + A; + case R_TLSGD_GOT_FROM_END: return InX::Got->getGlobalDynOffset(Sym) + A - InX::Got->getSize(); case R_TLSGD_PC: return InX::Got->getGlobalDynAddr(Sym) + A - P; - case R_TLSLD: + case R_TLSLD_GOT_FROM_END: return InX::Got->getTlsIndexOff() + A - InX::Got->getSize(); + case R_TLSLD_GOT: + return InX::Got->getTlsIndexOff() + A; case R_TLSLD_PC: return InX::Got->getTlsIndexVA() + A - P; } @@ -656,6 +691,14 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { for (const RelTy &Rel : Rels) { RelType Type = Rel.getType(Config->IsMips64EL); + + // GCC 8.0 or earlier have a bug that they emit R_386_GOTPC relocations + // against _GLOBAL_OFFSET_TABLE_ for .debug_info. The bug has been fixed + // in 2017 (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630), but we + // need to keep this bug-compatible code for a while. + if (Config->EMachine == EM_386 && Type == R_386_GOTPC) + continue; + uint64_t Offset = getOffset(Rel.r_offset); uint8_t *BufLoc = Buf + Offset; int64_t Addend = getAddend<ELFT>(Rel); @@ -666,17 +709,27 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { RelExpr Expr = Target->getRelExpr(Type, Sym, BufLoc); if (Expr == R_NONE) continue; + if (Expr != R_ABS) { - // GCC 8.0 or earlier have a bug that it emits R_386_GOTPC relocations - // against _GLOBAL_OFFSET_TABLE for .debug_info. The bug seems to have - // been fixed in 2017: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82630, - // but we need to keep this bug-compatible code for a while. - if (Config->EMachine == EM_386 && Type == R_386_GOTPC) - continue; + std::string Msg = getLocation<ELFT>(Offset) + + ": has non-ABS relocation " + toString(Type) + + " against symbol '" + toString(Sym) + "'"; + if (Expr != R_PC) { + error(Msg); + return; + } - error(getLocation<ELFT>(Offset) + ": has non-ABS relocation " + - toString(Type) + " against symbol '" + toString(Sym) + "'"); - return; + // If the control reaches here, we found a PC-relative relocation in a + // non-ALLOC section. Since non-ALLOC section is not loaded into memory + // at runtime, the notion of PC-relative doesn't make sense here. So, + // this is a usage error. However, GNU linkers historically accept such + // relocations without any errors and relocate them as if they were at + // address 0. For bug-compatibilty, we accept them with warnings. We + // know Steel Bank Common Lisp as of 2018 have this bug. + warn(Msg); + Target->relocateOne(BufLoc, Type, + SignExtend64<Bits>(Sym.getVA(Addend - Offset))); + continue; } if (Sym.isTls() && !Out::TlsPhdr) @@ -686,15 +739,37 @@ void InputSection::relocateNonAlloc(uint8_t *Buf, ArrayRef<RelTy> Rels) { } } +// This is used when '-r' is given. +// For REL targets, InputSection::copyRelocations() may store artificial +// relocations aimed to update addends. They are handled in relocateAlloc() +// for allocatable sections, and this function does the same for +// non-allocatable sections, such as sections with debug information. +static void relocateNonAllocForRelocatable(InputSection *Sec, uint8_t *Buf) { + const unsigned Bits = Config->Is64 ? 64 : 32; + + for (const Relocation &Rel : Sec->Relocations) { + // InputSection::copyRelocations() adds only R_ABS relocations. + assert(Rel.Expr == R_ABS); + uint8_t *BufLoc = Buf + Rel.Offset + Sec->OutSecOff; + uint64_t TargetVA = SignExtend64(Rel.Sym->getVA(Rel.Addend), Bits); + Target->relocateOne(BufLoc, Rel.Type, TargetVA); + } +} + template <class ELFT> void InputSectionBase::relocate(uint8_t *Buf, uint8_t *BufEnd) { + if (Flags & SHF_EXECINSTR) + adjustSplitStackFunctionPrologues<ELFT>(Buf, BufEnd); + if (Flags & SHF_ALLOC) { relocateAlloc(Buf, BufEnd); return; } auto *Sec = cast<InputSection>(this); - if (Sec->AreRelocsRela) + if (Config->Relocatable) + relocateNonAllocForRelocatable(Sec, Buf); + else if (Sec->AreRelocsRela) Sec->relocateNonAlloc<ELFT>(Buf, Sec->template relas<ELFT>()); else Sec->relocateNonAlloc<ELFT>(Buf, Sec->template rels<ELFT>()); @@ -705,14 +780,17 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { const unsigned Bits = Config->Wordsize * 8; for (const Relocation &Rel : Relocations) { - uint64_t Offset = getOffset(Rel.Offset); + uint64_t Offset = Rel.Offset; + if (auto *Sec = dyn_cast<InputSection>(this)) + Offset += Sec->OutSecOff; uint8_t *BufLoc = Buf + Offset; RelType Type = Rel.Type; uint64_t AddrLoc = getOutputSection()->Addr + Offset; RelExpr Expr = Rel.Expr; uint64_t TargetVA = SignExtend64( - getRelocTargetVA(Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), Bits); + getRelocTargetVA(File, Type, Rel.Addend, AddrLoc, *Rel.Sym, Expr), + Bits); switch (Expr) { case R_RELAX_GOT_PC: @@ -723,6 +801,7 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { Target->relaxTlsIeToLe(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_LD_TO_LE: + case R_RELAX_TLS_LD_TO_LE_ABS: Target->relaxTlsLdToLe(BufLoc, Type, TargetVA); break; case R_RELAX_TLS_GD_TO_LE: @@ -731,15 +810,28 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { break; case R_RELAX_TLS_GD_TO_IE: case R_RELAX_TLS_GD_TO_IE_ABS: + case R_RELAX_TLS_GD_TO_IE_GOT_OFF: case R_RELAX_TLS_GD_TO_IE_PAGE_PC: case R_RELAX_TLS_GD_TO_IE_END: Target->relaxTlsGdToIe(BufLoc, Type, TargetVA); break; - case R_PPC_PLT_OPD: + case R_PPC_CALL: + // If this is a call to __tls_get_addr, it may be part of a TLS + // sequence that has been relaxed and turned into a nop. In this + // case, we don't want to handle it as a call. + if (read32(BufLoc) == 0x60000000) // nop + break; + // Patch a nop (0x60000000) to a ld. - if (BufLoc + 8 <= BufEnd && read32be(BufLoc + 4) == 0x60000000) - write32be(BufLoc + 4, 0xe8410028); // ld %r2, 40(%r1) - LLVM_FALLTHROUGH; + if (Rel.Sym->NeedsTocRestore) { + if (BufLoc + 8 > BufEnd || read32(BufLoc + 4) != 0x60000000) { + error(getErrorLocation(BufLoc) + "call lacks nop, can't restore toc"); + break; + } + write32(BufLoc + 4, 0xe8410018); // ld %r2, 24(%r1) + } + Target->relocateOne(BufLoc, Type, TargetVA); + break; default: Target->relocateOne(BufLoc, Type, TargetVA); break; @@ -747,6 +839,103 @@ void InputSectionBase::relocateAlloc(uint8_t *Buf, uint8_t *BufEnd) { } } +// For each function-defining prologue, find any calls to __morestack, +// and replace them with calls to __morestack_non_split. +static void switchMorestackCallsToMorestackNonSplit( + llvm::DenseSet<Defined *>& Prologues, + std::vector<Relocation *>& MorestackCalls) { + + // If the target adjusted a function's prologue, all calls to + // __morestack inside that function should be switched to + // __morestack_non_split. + Symbol *MoreStackNonSplit = Symtab->find("__morestack_non_split"); + + // Sort both collections to compare addresses efficiently. + llvm::sort(MorestackCalls.begin(), MorestackCalls.end(), + [](const Relocation *L, const Relocation *R) { + return L->Offset < R->Offset; + }); + std::vector<Defined *> Functions(Prologues.begin(), Prologues.end()); + llvm::sort( + Functions.begin(), Functions.end(), + [](const Defined *L, const Defined *R) { return L->Value < R->Value; }); + + auto It = MorestackCalls.begin(); + for (Defined *F : Functions) { + // Find the first call to __morestack within the function. + while (It != MorestackCalls.end() && (*It)->Offset < F->Value) + ++It; + // Adjust all calls inside the function. + while (It != MorestackCalls.end() && (*It)->Offset < F->Value + F->Size) { + (*It)->Sym = MoreStackNonSplit; + ++It; + } + } +} + +static bool +enclosingPrologueAdjusted(uint64_t Offset, + const llvm::DenseSet<Defined *> &Prologues) { + for (Defined *F : Prologues) + if (F->Value <= Offset && Offset < F->Value + F->Size) + return true; + return false; +} + +// If a function compiled for split stack calls a function not +// compiled for split stack, then the caller needs its prologue +// adjusted to ensure that the called function will have enough stack +// available. Find those functions, and adjust their prologues. +template <class ELFT> +void InputSectionBase::adjustSplitStackFunctionPrologues(uint8_t *Buf, + uint8_t *End) { + if (!getFile<ELFT>()->SplitStack) + return; + llvm::DenseSet<Defined *> AdjustedPrologues; + std::vector<Relocation *> MorestackCalls; + + for (Relocation &Rel : Relocations) { + // Local symbols can't possibly be cross-calls, and should have been + // resolved long before this line. + if (Rel.Sym->isLocal()) + continue; + + Defined *D = dyn_cast<Defined>(Rel.Sym); + // A reference to an undefined symbol was an error, and should not + // have gotten to this point. + if (!D) + continue; + + // Ignore calls into the split-stack api. + if (D->getName().startswith("__morestack")) { + if (D->getName().equals("__morestack")) + MorestackCalls.push_back(&Rel); + continue; + } + + // A relocation to non-function isn't relevant. Sometimes + // __morestack is not marked as a function, so this check comes + // after the name check. + if (D->Type != STT_FUNC) + continue; + + if (enclosingPrologueAdjusted(Rel.Offset, AdjustedPrologues)) + continue; + + if (Defined *F = getEnclosingFunction<ELFT>(Rel.Offset)) { + if (Target->adjustPrologueForCrossSplitStack(Buf + F->Value, End)) { + AdjustedPrologues.insert(F); + continue; + } + } + if (!getFile<ELFT>()->SomeNoSplitStack) + error("function call at " + getErrorLocation(Buf + Rel.Offset) + + "crosses a split-stack boundary, but unable " + + "to adjust the enclosing function's prologue"); + } + switchMorestackCallsToMorestackNonSplit(AdjustedPrologues, MorestackCalls); +} + template <class ELFT> void InputSection::writeTo(uint8_t *Buf) { if (Type == SHT_NOBITS) return; @@ -818,10 +1007,6 @@ static unsigned getReloc(IntTy Begin, IntTy Size, const ArrayRef<RelTy> &Rels, // .eh_frame is a sequence of CIE or FDE records. // This function splits an input section into records and returns them. template <class ELFT> void EhInputSection::split() { - // Early exit if already split. - if (!Pieces.empty()) - return; - if (AreRelocsRela) split<ELFT>(relas<ELFT>()); else @@ -916,15 +1101,9 @@ void MergeInputSection::splitIntoPieces() { else splitNonStrings(Data, Entsize); - if (Config->GcSections && (Flags & SHF_ALLOC)) - for (uint64_t Off : LiveOffsets) - getSectionPiece(Off)->Live = true; -} - -// Do binary search to get a section piece at a given input offset. -SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) { - auto *This = static_cast<const MergeInputSection *>(this); - return const_cast<SectionPiece *>(This->getSectionPiece(Offset)); + OffsetMap.reserve(Pieces.size()); + for (size_t I = 0, E = Pieces.size(); I != E; ++I) + OffsetMap[Pieces[I].InputOff] = I; } template <class It, class T, class Compare> @@ -940,32 +1119,34 @@ static It fastUpperBound(It First, It Last, const T &Value, Compare Comp) { return Comp(Value, *First) ? First : First + 1; } -const SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) const { - if (Data.size() <= Offset) - fatal(toString(this) + ": entry is past the end of the section"); +// Do binary search to get a section piece at a given input offset. +static SectionPiece *findSectionPiece(MergeInputSection *Sec, uint64_t Offset) { + if (Sec->Data.size() <= Offset) + fatal(toString(Sec) + ": entry is past the end of the section"); // Find the element this offset points to. auto I = fastUpperBound( - Pieces.begin(), Pieces.end(), Offset, + Sec->Pieces.begin(), Sec->Pieces.end(), Offset, [](const uint64_t &A, const SectionPiece &B) { return A < B.InputOff; }); --I; return &*I; } +SectionPiece *MergeInputSection::getSectionPiece(uint64_t Offset) { + // Find a piece starting at a given offset. + auto It = OffsetMap.find(Offset); + if (It != OffsetMap.end()) + return &Pieces[It->second]; + + // If Offset is not at beginning of a section piece, it is not in the map. + // In that case we need to search from the original section piece vector. + return findSectionPiece(this, Offset); +} + // Returns the offset in an output section for a given input offset. // Because contents of a mergeable section is not contiguous in output, // it is not just an addition to a base output offset. -uint64_t MergeInputSection::getOffset(uint64_t Offset) const { - if (!Live) - return 0; - - // Initialize OffsetMap lazily. - llvm::call_once(InitOffsetMap, [&] { - OffsetMap.reserve(Pieces.size()); - for (size_t I = 0; I < Pieces.size(); ++I) - OffsetMap[Pieces[I].InputOff] = I; - }); - +uint64_t MergeInputSection::getParentOffset(uint64_t Offset) const { // Find a string starting at a given offset. auto It = OffsetMap.find(Offset); if (It != OffsetMap.end()) @@ -973,10 +1154,8 @@ uint64_t MergeInputSection::getOffset(uint64_t Offset) const { // If Offset is not at beginning of a section piece, it is not in the map. // In that case we need to search from the original section piece vector. - const SectionPiece &Piece = *getSectionPiece(Offset); - if (!Piece.Live) - return 0; - + const SectionPiece &Piece = + *findSectionPiece(const_cast<MergeInputSection *>(this), Offset); uint64_t Addend = Offset - Piece.InputOff; return Piece.OutputOff + Addend; } diff --git a/ELF/InputSection.h b/ELF/InputSection.h index 8c114ae71948..4db01e035e32 100644 --- a/ELF/InputSection.h +++ b/ELF/InputSection.h @@ -18,8 +18,6 @@ #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/Object/ELF.h" -#include "llvm/Support/Threading.h" -#include <mutex> namespace lld { namespace elf { @@ -63,6 +61,9 @@ public: unsigned Bss : 1; + // Set for sections that should not be folded by ICF. + unsigned KeepUnique : 1; + // These corresponds to the fields in Elf_Shdr. uint32_t Alignment; uint64_t Flags; @@ -80,13 +81,15 @@ public: // section. uint64_t getOffset(uint64_t Offset) const; + uint64_t getVA(uint64_t Offset = 0) const; + protected: SectionBase(Kind SectionKind, StringRef Name, uint64_t Flags, uint64_t Entsize, uint64_t Alignment, uint32_t Type, uint32_t Info, uint32_t Link) : Name(Name), Repl(this), SectionKind(SectionKind), Live(false), - Bss(false), Alignment(Alignment), Flags(Flags), Entsize(Entsize), - Type(Type), Link(Link), Info(Info) {} + Bss(false), KeepUnique(false), Alignment(Alignment), Flags(Flags), + Entsize(Entsize), Type(Type), Link(Link), Info(Info) {} }; // This corresponds to a section of an input file. @@ -103,7 +106,7 @@ public: static bool classof(const SectionBase *S) { return S->kind() != Output; } - // The file which contains this section. It's dynamic type is always + // The file which contains this section. Its dynamic type is always // ObjFile<ELFT>, but in order to avoid ELFT, we use InputFile as // its static type. InputFile *File; @@ -161,10 +164,15 @@ public: InputSection *getLinkOrderDep() const; + // Get the function symbol that encloses this offset from within the + // section. + template <class ELFT> + Defined *getEnclosingFunction(uint64_t Offset); + // Compilers emit zlib-compressed debug sections if the -gz option // is given. This function checks if this section is compressed, and // if so, decompress in memory. - void maybeUncompress(); + void maybeDecompress(); // Returns a source location string. Used to construct an error message. template <class ELFT> std::string getLocation(uint64_t Offset); @@ -182,6 +190,15 @@ public: // This vector contains such "cooked" relocations. std::vector<Relocation> Relocations; + // A function compiled with -fsplit-stack calling a function + // compiled without -fsplit-stack needs its prologue adjusted. Find + // such functions and adjust their prologues. This is very similar + // to relocation. See https://gcc.gnu.org/wiki/SplitStacks for more + // information. + template <typename ELFT> + void adjustSplitStackFunctionPrologues(uint8_t *Buf, uint8_t *End); + + template <typename T> llvm::ArrayRef<T> getDataAs() const { size_t S = Data.size(); assert(S % sizeof(T) == 0); @@ -189,9 +206,9 @@ public: } private: - // A pointer that owns uncompressed data if a section is compressed by zlib. + // A pointer that owns decompressed data if a section is compressed by zlib. // Since the feature is not used often, this is usually a nullptr. - std::unique_ptr<char[]> UncompressBuf; + std::unique_ptr<char[]> DecompressBuf; }; // SectionPiece represents a piece of splittable section contents. @@ -200,7 +217,7 @@ private: // be found by looking at the next one). struct SectionPiece { SectionPiece(size_t Off, uint32_t Hash, bool Live) - : InputOff(Off), Hash(Hash), OutputOff(-1), + : InputOff(Off), Hash(Hash), OutputOff(0), Live(Live || !Config->GcSections) {} uint32_t InputOff; @@ -223,19 +240,14 @@ public: static bool classof(const SectionBase *S) { return S->kind() == Merge; } void splitIntoPieces(); - // Mark the piece at a given offset live. Used by GC. - void markLiveAt(uint64_t Offset) { - if (this->Flags & llvm::ELF::SHF_ALLOC) - LiveOffsets.insert(Offset); - } - - // Translate an offset in the input section to an offset - // in the output section. - uint64_t getOffset(uint64_t Offset) const; + // Translate an offset in the input section to an offset in the parent + // MergeSyntheticSection. + uint64_t getParentOffset(uint64_t Offset) const; // Splittable sections are handled as a sequence of data // rather than a single large blob of data. std::vector<SectionPiece> Pieces; + llvm::DenseMap<uint32_t, uint32_t> OffsetMap; // Returns I'th piece's data. This function is very hot when // string merging is enabled, so we want to inline. @@ -249,18 +261,15 @@ public: // Returns the SectionPiece at a given input section offset. SectionPiece *getSectionPiece(uint64_t Offset); - const SectionPiece *getSectionPiece(uint64_t Offset) const; + const SectionPiece *getSectionPiece(uint64_t Offset) const { + return const_cast<MergeInputSection *>(this)->getSectionPiece(Offset); + } SyntheticSection *getParent() const; private: void splitStrings(ArrayRef<uint8_t> A, size_t Size); void splitNonStrings(ArrayRef<uint8_t> A, size_t Size); - - mutable llvm::DenseMap<uint32_t, uint32_t> OffsetMap; - mutable llvm::once_flag InitOffsetMap; - - llvm::DenseSet<uint64_t> LiveOffsets; }; struct EhSectionPiece { @@ -310,6 +319,8 @@ public: // beginning of the output section. template <class ELFT> void writeTo(uint8_t *Buf); + uint64_t getOffset(uint64_t Offset) const { return OutSecOff + Offset; } + OutputSection *getParent() const; // This variable has two usages. Initially, it represents an index in the @@ -320,7 +331,7 @@ public: static bool classof(const SectionBase *S); - InputSectionBase *getRelocatedSection(); + InputSectionBase *getRelocatedSection() const; template <class ELFT, class RelTy> void relocateNonAlloc(uint8_t *Buf, llvm::ArrayRef<RelTy> Rels); @@ -342,10 +353,6 @@ private: // The list of all input sections. extern std::vector<InputSectionBase *> InputSections; - -// Builds section order for handling --symbol-ordering-file. -llvm::DenseMap<SectionBase *, int> buildSectionOrder(); - } // namespace elf std::string toString(const elf::InputSectionBase *); diff --git a/ELF/LTO.cpp b/ELF/LTO.cpp index bfd85288d186..ef58932e86cc 100644 --- a/ELF/LTO.cpp +++ b/ELF/LTO.cpp @@ -20,6 +20,8 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/LTO/Caching.h" #include "llvm/LTO/Config.h" @@ -29,7 +31,6 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" #include <algorithm> #include <cstddef> #include <memory> @@ -44,70 +45,92 @@ using namespace llvm::ELF; using namespace lld; using namespace lld::elf; -// This is for use when debugging LTO. -static void saveBuffer(StringRef Buffer, const Twine &Path) { +// Creates an empty file to store a list of object files for final +// linking of distributed ThinLTO. +static std::unique_ptr<raw_fd_ostream> openFile(StringRef File) { std::error_code EC; - raw_fd_ostream OS(Path.str(), EC, sys::fs::OpenFlags::F_None); - if (EC) - error("cannot create " + Path + ": " + EC.message()); - OS << Buffer; -} - -static void diagnosticHandler(const DiagnosticInfo &DI) { - SmallString<128> ErrStorage; - raw_svector_ostream OS(ErrStorage); - DiagnosticPrinterRawOStream DP(OS); - DI.print(DP); - warn(ErrStorage); + auto Ret = + llvm::make_unique<raw_fd_ostream>(File, EC, sys::fs::OpenFlags::F_None); + if (EC) { + error("cannot open " + File + ": " + EC.message()); + return nullptr; + } + return Ret; } -static void checkError(Error E) { - handleAllErrors(std::move(E), - [&](ErrorInfoBase &EIB) { error(EIB.message()); }); +static std::string getThinLTOOutputFile(StringRef ModulePath) { + return lto::getThinLTOOutputFile(ModulePath, + Config->ThinLTOPrefixReplace.first, + Config->ThinLTOPrefixReplace.second); } -static std::unique_ptr<lto::LTO> createLTO() { - lto::Config Conf; +static lto::Config createConfig() { + lto::Config C; // LLD supports the new relocations. - Conf.Options = InitTargetOptionsFromCodeGenFlags(); - Conf.Options.RelaxELFRelocations = true; + C.Options = InitTargetOptionsFromCodeGenFlags(); + C.Options.RelaxELFRelocations = true; // Always emit a section per function/datum with LTO. - Conf.Options.FunctionSections = true; - Conf.Options.DataSections = true; + C.Options.FunctionSections = true; + C.Options.DataSections = true; if (Config->Relocatable) - Conf.RelocModel = None; + C.RelocModel = None; else if (Config->Pic) - Conf.RelocModel = Reloc::PIC_; + C.RelocModel = Reloc::PIC_; else - Conf.RelocModel = Reloc::Static; - Conf.CodeModel = GetCodeModelFromCMModel(); - Conf.DisableVerify = Config->DisableVerify; - Conf.DiagHandler = diagnosticHandler; - Conf.OptLevel = Config->LTOO; + C.RelocModel = Reloc::Static; + + C.CodeModel = GetCodeModelFromCMModel(); + C.DisableVerify = Config->DisableVerify; + C.DiagHandler = diagnosticHandler; + C.OptLevel = Config->LTOO; + C.CPU = GetCPUStr(); // Set up a custom pipeline if we've been asked to. - Conf.OptPipeline = Config->LTONewPmPasses; - Conf.AAPipeline = Config->LTOAAPipeline; + C.OptPipeline = Config->LTONewPmPasses; + C.AAPipeline = Config->LTOAAPipeline; // Set up optimization remarks if we've been asked to. - Conf.RemarksFilename = Config->OptRemarksFilename; - Conf.RemarksWithHotness = Config->OptRemarksWithHotness; + C.RemarksFilename = Config->OptRemarksFilename; + C.RemarksWithHotness = Config->OptRemarksWithHotness; + + C.SampleProfile = Config->LTOSampleProfile; + C.UseNewPM = Config->LTONewPassManager; + C.DebugPassManager = Config->LTODebugPassManager; + C.DwoDir = Config->DwoDir; if (Config->SaveTemps) - checkError(Conf.addSaveTemps(std::string(Config->OutputFile) + ".", - /*UseInputModulePath*/ true)); + checkError(C.addSaveTemps(Config->OutputFile.str() + ".", + /*UseInputModulePath*/ true)); + return C; +} +BitcodeCompiler::BitcodeCompiler() { + // Initialize LTOObj. lto::ThinBackend Backend; - if (Config->ThinLTOJobs != -1u) + + if (Config->ThinLTOIndexOnly) { + StringRef Path = Config->ThinLTOIndexOnlyArg; + if (!Path.empty()) + IndexFile = openFile(Path); + + auto OnIndexWrite = [&](const std::string &Identifier) { + ObjectToIndexFileState[Identifier] = true; + }; + + Backend = lto::createWriteIndexesThinBackend( + Config->ThinLTOPrefixReplace.first, Config->ThinLTOPrefixReplace.second, + Config->ThinLTOEmitImportsFiles, IndexFile.get(), OnIndexWrite); + } else if (Config->ThinLTOJobs != -1U) { Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); - return llvm::make_unique<lto::LTO>(std::move(Conf), Backend, - Config->LTOPartitions); -} + } -BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) { + LTOObj = llvm::make_unique<lto::LTO>(createConfig(), Backend, + Config->LTOPartitions); + + // Initialize UsedStartStop. for (Symbol *Sym : Symtab->getSymbols()) { StringRef Name = Sym->getName(); for (StringRef Prefix : {"__start_", "__stop_"}) @@ -125,20 +148,20 @@ static void undefine(Symbol *S) { void BitcodeCompiler::add(BitcodeFile &F) { lto::InputFile &Obj = *F.Obj; - unsigned SymNum = 0; - std::vector<Symbol *> Syms = F.getSymbols(); - std::vector<lto::SymbolResolution> Resols(Syms.size()); + bool IsExec = !Config->Shared && !Config->Relocatable; - DenseSet<StringRef> ScriptSymbols; - for (BaseCommand *Base : Script->SectionCommands) - if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) - ScriptSymbols.insert(Cmd->Name); + if (Config->ThinLTOIndexOnly) + ObjectToIndexFileState.insert({Obj.getName(), false}); + + ArrayRef<Symbol *> Syms = F.getSymbols(); + ArrayRef<lto::InputFile::Symbol> ObjSyms = Obj.symbols(); + std::vector<lto::SymbolResolution> Resols(Syms.size()); // Provide a resolution to the LTO API for each symbol. - for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { - Symbol *Sym = Syms[SymNum]; - lto::SymbolResolution &R = Resols[SymNum]; - ++SymNum; + for (size_t I = 0, E = Syms.size(); I != E; ++I) { + Symbol *Sym = Syms[I]; + const lto::InputFile::Symbol &ObjSym = ObjSyms[I]; + lto::SymbolResolution &R = Resols[I]; // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile // reports two symbols for module ASM defined. Without this check, lld @@ -156,25 +179,46 @@ void BitcodeCompiler::add(BitcodeFile &F) { R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj || (R.Prevailing && Sym->includeInDynsym()) || UsedStartStop.count(ObjSym.getSectionName()); + const auto *DR = dyn_cast<Defined>(Sym); + R.FinalDefinitionInLinkageUnit = + (IsExec || Sym->Visibility != STV_DEFAULT) && DR && + // Skip absolute symbols from ELF objects, otherwise PC-rel relocations + // will be generated by for them, triggering linker errors. + // Symbol section is always null for bitcode symbols, hence the check + // for isElf(). Skip linker script defined symbols as well: they have + // no File defined. + !(DR->Section == nullptr && (!Sym->File || Sym->File->isElf())); + if (R.Prevailing) undefine(Sym); - // We tell LTO to not apply interprocedural optimization for following - // symbols because otherwise LTO would inline them while their values are - // still not final: - // 1) Aliased (with --defsym) or wrapped (with --wrap) symbols. - // 2) Symbols redefined in linker script. - R.LinkerRedefined = !Sym->CanInline || ScriptSymbols.count(Sym->getName()); + // We tell LTO to not apply interprocedural optimization for wrapped + // (with --wrap) symbols because otherwise LTO would inline them while + // their values are still not final. + R.LinkerRedefined = !Sym->CanInline; } checkError(LTOObj->add(std::move(F.Obj), Resols)); } +static void createEmptyIndex(StringRef ModulePath) { + std::string Path = replaceThinLTOSuffix(getThinLTOOutputFile(ModulePath)); + std::unique_ptr<raw_fd_ostream> OS = openFile(Path + ".thinlto.bc"); + if (!OS) + return; + + ModuleSummaryIndex M(/*HaveGVs*/ false); + M.setSkipModuleByDistributedBackend(); + WriteIndexToFile(M, *OS); + + if (Config->ThinLTOEmitImportsFiles) + openFile(Path + ".imports"); +} + // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile(s). std::vector<InputFile *> BitcodeCompiler::compile() { - std::vector<InputFile *> Ret; unsigned MaxTasks = LTOObj->getMaxTasks(); - Buff.resize(MaxTasks); + Buf.resize(MaxTasks); Files.resize(MaxTasks); // The --thinlto-cache-dir option specifies the path to a directory in which @@ -184,35 +228,67 @@ std::vector<InputFile *> BitcodeCompiler::compile() { if (!Config->ThinLTOCacheDir.empty()) Cache = check( lto::localCache(Config->ThinLTOCacheDir, - [&](size_t Task, std::unique_ptr<MemoryBuffer> MB, - StringRef Path) { Files[Task] = std::move(MB); })); + [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { + Files[Task] = std::move(MB); + })); checkError(LTOObj->run( [&](size_t Task) { return llvm::make_unique<lto::NativeObjectStream>( - llvm::make_unique<raw_svector_ostream>(Buff[Task])); + llvm::make_unique<raw_svector_ostream>(Buf[Task])); }, Cache)); + // Emit empty index files for non-indexed files + if (Config->ThinLTOIndexOnly) { + for (auto &Identifier : ObjectToIndexFileState) + if (!Identifier.getValue()) { + std::string Path = getThinLTOOutputFile(Identifier.getKey()); + openFile(Path + ".thinlto.bc"); + + if (Config->ThinLTOEmitImportsFiles) + openFile(Path + ".imports"); + } + } + + // If LazyObjFile has not been added to link, emit empty index files. + // This is needed because this is what GNU gold plugin does and we have a + // distributed build system that depends on that behavior. + if (Config->ThinLTOIndexOnly) { + for (LazyObjFile *F : LazyObjFiles) + if (!F->AddedToLink && isBitcode(F->MB)) + createEmptyIndex(F->getName()); + + if (!Config->LTOObjPath.empty()) + saveBuffer(Buf[0], Config->LTOObjPath); + + // ThinLTO with index only option is required to generate only the index + // files. After that, we exit from linker and ThinLTO backend runs in a + // distributed environment. + if (IndexFile) + IndexFile->close(); + return {}; + } + if (!Config->ThinLTOCacheDir.empty()) pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); + std::vector<InputFile *> Ret; for (unsigned I = 0; I != MaxTasks; ++I) { - if (Buff[I].empty()) + if (Buf[I].empty()) continue; if (Config->SaveTemps) { if (I == 0) - saveBuffer(Buff[I], Config->OutputFile + ".lto.o"); + saveBuffer(Buf[I], Config->OutputFile + ".lto.o"); else - saveBuffer(Buff[I], Config->OutputFile + Twine(I) + ".lto.o"); + saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o"); } - InputFile *Obj = createObjectFile(MemoryBufferRef(Buff[I], "lto.tmp")); + InputFile *Obj = createObjectFile(MemoryBufferRef(Buf[I], "lto.tmp")); Ret.push_back(Obj); } for (std::unique_ptr<MemoryBuffer> &File : Files) if (File) Ret.push_back(createObjectFile(*File)); - return Ret; } diff --git a/ELF/LTO.h b/ELF/LTO.h index 223af507a97d..8803078eb1df 100644 --- a/ELF/LTO.h +++ b/ELF/LTO.h @@ -24,6 +24,7 @@ #include "lld/Common/LLVM.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" #include <memory> #include <vector> @@ -38,6 +39,7 @@ namespace elf { class BitcodeFile; class InputFile; +class LazyObjFile; class BitcodeCompiler { public: @@ -49,9 +51,11 @@ public: private: std::unique_ptr<llvm::lto::LTO> LTOObj; - std::vector<SmallString<0>> Buff; + std::vector<SmallString<0>> Buf; std::vector<std::unique_ptr<MemoryBuffer>> Files; llvm::DenseSet<StringRef> UsedStartStop; + std::unique_ptr<llvm::raw_fd_ostream> IndexFile; + llvm::StringMap<bool> ObjectToIndexFileState; }; } // namespace elf } // namespace lld diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index 8f50a977fd75..abdd899da487 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -15,13 +15,13 @@ #include "Config.h" #include "InputSection.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" @@ -74,7 +74,7 @@ uint64_t ExprValue::getSectionOffset() const { // If the alignment is trivial, we don't have to compute the full // value to know the offset. This allows this function to succeed in // cases where the output section is not yet known. - if (Alignment == 1) + if (Alignment == 1 && (!Sec || !Sec->getOutputSection())) return Val; return getValue() - getSecAddr(); } @@ -102,28 +102,67 @@ OutputSection *LinkerScript::getOrCreateOutputSection(StringRef Name) { return CmdRef; } +// Expands the memory region by the specified size. +static void expandMemoryRegion(MemoryRegion *MemRegion, uint64_t Size, + StringRef RegionName, StringRef SecName) { + MemRegion->CurPos += Size; + uint64_t NewSize = MemRegion->CurPos - MemRegion->Origin; + if (NewSize > MemRegion->Length) + error("section '" + SecName + "' will not fit in region '" + RegionName + + "': overflowed by " + Twine(NewSize - MemRegion->Length) + " bytes"); +} + +void LinkerScript::expandMemoryRegions(uint64_t Size) { + if (Ctx->MemRegion) + expandMemoryRegion(Ctx->MemRegion, Size, Ctx->MemRegion->Name, + Ctx->OutSec->Name); + if (Ctx->LMARegion) + expandMemoryRegion(Ctx->LMARegion, Size, Ctx->LMARegion->Name, + Ctx->OutSec->Name); +} + +void LinkerScript::expandOutputSection(uint64_t Size) { + Ctx->OutSec->Size += Size; + expandMemoryRegions(Size); +} + void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); if (Val < Dot && InSec) error(Loc + ": unable to move location counter backward for: " + Ctx->OutSec->Name); - Dot = Val; // Update to location counter means update to section size. if (InSec) - Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; + expandOutputSection(Val - Dot); + else + expandMemoryRegions(Val - Dot); + + Dot = Val; } -// This function is called from processSectionCommands, -// while we are fixing the output section layout. -void LinkerScript::addSymbol(SymbolAssignment *Cmd) { +// Used for handling linker symbol assignments, for both finalizing +// their values and doing early declarations. Returns true if symbol +// should be defined from linker script. +static bool shouldDefineSym(SymbolAssignment *Cmd) { if (Cmd->Name == ".") - return; + return false; - // If a symbol was in PROVIDE(), we need to define it only when - // it is a referenced undefined symbol. + if (!Cmd->Provide) + return true; + + // If a symbol was in PROVIDE(), we need to define it only + // when it is a referenced undefined symbol. Symbol *B = Symtab->find(Cmd->Name); - if (Cmd->Provide && (!B || B->isDefined())) + if (B && !B->isDefined()) + return true; + return false; +} + +// This function is called from processSectionCommands, +// while we are fixing the output section layout. +void LinkerScript::addSymbol(SymbolAssignment *Cmd) { + if (!shouldDefineSym(Cmd)) return; // Define a symbol. @@ -153,6 +192,76 @@ void LinkerScript::addSymbol(SymbolAssignment *Cmd) { Cmd->Sym = cast<Defined>(Sym); } +// This function is called from LinkerScript::declareSymbols. +// It creates a placeholder symbol if needed. +static void declareSymbol(SymbolAssignment *Cmd) { + if (!shouldDefineSym(Cmd)) + return; + + // We can't calculate final value right now. + Symbol *Sym; + uint8_t Visibility = Cmd->Hidden ? STV_HIDDEN : STV_DEFAULT; + std::tie(Sym, std::ignore) = Symtab->insert(Cmd->Name, /*Type*/ 0, Visibility, + /*CanOmitFromDynSym*/ false, + /*File*/ nullptr); + replaceSymbol<Defined>(Sym, nullptr, Cmd->Name, STB_GLOBAL, Visibility, + STT_NOTYPE, 0, 0, nullptr); + Cmd->Sym = cast<Defined>(Sym); + Cmd->Provide = false; +} + +// This method is used to handle INSERT AFTER statement. Here we rebuild +// the list of script commands to mix sections inserted into. +void LinkerScript::processInsertCommands() { + std::vector<BaseCommand *> V; + auto Insert = [&](std::vector<BaseCommand *> &From) { + V.insert(V.end(), From.begin(), From.end()); + From.clear(); + }; + + for (BaseCommand *Base : SectionCommands) { + if (auto *OS = dyn_cast<OutputSection>(Base)) { + Insert(InsertBeforeCommands[OS->Name]); + V.push_back(Base); + Insert(InsertAfterCommands[OS->Name]); + continue; + } + V.push_back(Base); + } + + for (auto &Cmds : {InsertBeforeCommands, InsertAfterCommands}) + for (const std::pair<StringRef, std::vector<BaseCommand *>> &P : Cmds) + if (!P.second.empty()) + error("unable to INSERT AFTER/BEFORE " + P.first + + ": section not defined"); + + SectionCommands = std::move(V); +} + +// Symbols defined in script should not be inlined by LTO. At the same time +// we don't know their final values until late stages of link. Here we scan +// over symbol assignment commands and create placeholder symbols if needed. +void LinkerScript::declareSymbols() { + assert(!Ctx); + for (BaseCommand *Base : SectionCommands) { + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + declareSymbol(Cmd); + continue; + } + + // If the output section directive has constraints, + // we can't say for sure if it is going to be included or not. + // Skip such sections for now. Improve the checks if we ever + // need symbols from that sections to be declared early. + auto *Sec = cast<OutputSection>(Base); + if (Sec->Constraint != ConstraintKind::NoConstraint) + continue; + for (BaseCommand *Base2 : Sec->SectionCommands) + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base2)) + declareSymbol(Cmd); + } +} + // This function is called from assignAddresses, while we are // fixing the output section addresses. This function is supposed // to set the final value for a given symbol assignment. @@ -249,23 +358,11 @@ static void sortSections(MutableArrayRef<InputSection *> Vec, // --sort-section is handled as an inner SORT command. // 3. If one SORT command is given, and if it is SORT_NONE, don't sort. // 4. If no SORT command is given, sort according to --sort-section. -// 5. If no SORT commands are given and --sort-section is not specified, -// apply sorting provided by --symbol-ordering-file if any exist. -static void sortInputSections( - MutableArrayRef<InputSection *> Vec, const SectionPattern &Pat, - const DenseMap<SectionBase *, int> &Order) { +static void sortInputSections(MutableArrayRef<InputSection *> Vec, + const SectionPattern &Pat) { if (Pat.SortOuter == SortSectionPolicy::None) return; - if (Pat.SortOuter == SortSectionPolicy::Default && - Config->SortSection == SortSectionPolicy::Default) { - // If -symbol-ordering-file was given, sort accordingly. - // Usually, Order is empty. - if (!Order.empty()) - sortByOrder(Vec, [&](InputSectionBase *S) { return Order.lookup(S); }); - return; - } - if (Pat.SortInner == SortSectionPolicy::Default) sortSections(Vec, Config->SortSection); else @@ -275,8 +372,7 @@ static void sortInputSections( // Compute and remember which sections the InputSectionDescription matches. std::vector<InputSection *> -LinkerScript::computeInputSections(const InputSectionDescription *Cmd, - const DenseMap<SectionBase *, int> &Order) { +LinkerScript::computeInputSections(const InputSectionDescription *Cmd) { std::vector<InputSection *> Ret; // Collects all sections that satisfy constraints of Cmd. @@ -290,8 +386,11 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd, // For -emit-relocs we have to ignore entries like // .rela.dyn : { *(.rela.data) } // which are common because they are in the default bfd script. - if (Sec->Type == SHT_REL || Sec->Type == SHT_RELA) - continue; + // We do not ignore SHT_REL[A] linker-synthesized sections here because + // want to support scripts that do custom layout for them. + if (auto *IS = dyn_cast<InputSection>(Sec)) + if (IS->getRelocatedSection()) + continue; std::string Filename = getFilename(Sec->File); if (!Cmd->FilePat.match(Filename) || @@ -307,7 +406,7 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd, } sortInputSections(MutableArrayRef<InputSection *>(Ret).slice(SizeBefore), - Pat, Order); + Pat); } return Ret; } @@ -315,22 +414,31 @@ LinkerScript::computeInputSections(const InputSectionDescription *Cmd, void LinkerScript::discard(ArrayRef<InputSection *> V) { for (InputSection *S : V) { if (S == InX::ShStrTab || S == InX::Dynamic || S == InX::DynSymTab || - S == InX::DynStrTab) + S == InX::DynStrTab || S == InX::RelaPlt || S == InX::RelaDyn || + S == InX::RelrDyn) error("discarding " + S->Name + " section is not allowed"); + // You can discard .hash and .gnu.hash sections by linker scripts. Since + // they are synthesized sections, we need to handle them differently than + // other regular sections. + if (S == InX::GnuHashTab) + InX::GnuHashTab = nullptr; + if (S == InX::HashTab) + InX::HashTab = nullptr; + S->Assigned = false; S->Live = false; discard(S->DependentSections); } } -std::vector<InputSection *> LinkerScript::createInputSectionList( - OutputSection &OutCmd, const DenseMap<SectionBase *, int> &Order) { +std::vector<InputSection *> +LinkerScript::createInputSectionList(OutputSection &OutCmd) { std::vector<InputSection *> Ret; for (BaseCommand *Base : OutCmd.SectionCommands) { if (auto *Cmd = dyn_cast<InputSectionDescription>(Base)) { - Cmd->Sections = computeInputSections(Cmd, Order); + Cmd->Sections = computeInputSections(Cmd); Ret.insert(Ret.end(), Cmd->Sections.begin(), Cmd->Sections.end()); } } @@ -359,7 +467,6 @@ void LinkerScript::processSectionCommands() { Ctx->OutSec = Aether; size_t I = 0; - DenseMap<SectionBase *, int> Order = buildSectionOrder(); // Add input sections to output sections. for (BaseCommand *Base : SectionCommands) { // Handle symbol assignments outside of any output section. @@ -369,12 +476,13 @@ void LinkerScript::processSectionCommands() { } if (auto *Sec = dyn_cast<OutputSection>(Base)) { - std::vector<InputSection *> V = createInputSectionList(*Sec, Order); + std::vector<InputSection *> V = createInputSectionList(*Sec); // The output section name `/DISCARD/' is special. // Any input section assigned to it is discarded. if (Sec->Name == "/DISCARD/") { discard(V); + Sec->SectionCommands.clear(); continue; } @@ -414,6 +522,8 @@ void LinkerScript::processSectionCommands() { Sec->SectionIndex = I++; if (Sec->Noload) Sec->Type = SHT_NOBITS; + if (Sec->NonAlloc) + Sec->Flags &= ~(uint64_t)SHF_ALLOC; } } Ctx = nullptr; @@ -484,7 +594,7 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map, // ignored. We should not have two output .text sections just because one was // in a group and another was not for example. // - // It also seems that that wording was a late addition and didn't get the + // It also seems that wording was a late addition and didn't get the // necessary scrutiny. // // Merging sections with different flags is expected by some users. One @@ -529,11 +639,11 @@ static OutputSection *addInputSec(StringMap<OutputSection *> &Map, void LinkerScript::addOrphanSections() { unsigned End = SectionCommands.size(); StringMap<OutputSection *> Map; - std::vector<OutputSection *> V; - for (InputSectionBase *S : InputSections) { + + auto Add = [&](InputSectionBase *S) { if (!S->Live || S->Parent) - continue; + return; StringRef Name = getOutputSectionName(S); @@ -545,12 +655,24 @@ void LinkerScript::addOrphanSections() { if (OutputSection *Sec = findByName(makeArrayRef(SectionCommands).slice(0, End), Name)) { Sec->addSection(cast<InputSection>(S)); - continue; + return; } if (OutputSection *OS = addInputSec(Map, S, Name)) V.push_back(OS); - assert(S->getOutputSection()->SectionIndex == INT_MAX); + assert(S->getOutputSection()->SectionIndex == UINT32_MAX); + }; + + // For futher --emit-reloc handling code we need target output section + // to be created before we create relocation output section, so we want + // to create target sections first. We do not want priority handling + // for synthetic sections because them are special. + for (InputSectionBase *IS : InputSections) { + if (auto *Sec = dyn_cast<InputSection>(IS)) + if (InputSectionBase *Rel = Sec->getRelocatedSection()) + if (auto *RelIS = dyn_cast_or_null<InputSectionBase>(Rel->Parent)) + Add(RelIS); + Add(IS); } // If no SECTIONS command was given, we should insert sections commands @@ -585,36 +707,15 @@ void LinkerScript::output(InputSection *S) { // Update output section size after adding each section. This is so that // SIZEOF works correctly in the case below: // .foo { *(.aaa) a = SIZEOF(.foo); *(.bbb) } - Ctx->OutSec->Size = Pos - Ctx->OutSec->Addr; - - // If there is a memory region associated with this input section, then - // place the section in that region and update the region index. - if (Ctx->MemRegion) { - uint64_t &CurOffset = Ctx->MemRegionOffset[Ctx->MemRegion]; - CurOffset += Pos - Before; - uint64_t CurSize = CurOffset - Ctx->MemRegion->Origin; - if (CurSize > Ctx->MemRegion->Length) { - uint64_t OverflowAmt = CurSize - Ctx->MemRegion->Length; - error("section '" + Ctx->OutSec->Name + "' will not fit in region '" + - Ctx->MemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + - " bytes"); - } - } + expandOutputSection(Pos - Before); } void LinkerScript::switchTo(OutputSection *Sec) { - if (Ctx->OutSec == Sec) - return; - Ctx->OutSec = Sec; - Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment); - // If neither AT nor AT> is specified for an allocatable section, the linker - // will set the LMA such that the difference between VMA and LMA for the - // section is the same as the preceding output section in the same region - // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html - if (Ctx->LMAOffset) - Ctx->OutSec->LMAOffset = Ctx->LMAOffset(); + uint64_t Before = advance(0, 1); + Ctx->OutSec->Addr = advance(0, Ctx->OutSec->Alignment); + expandMemoryRegions(Ctx->OutSec->Addr - Before); } // This function searches for a memory region to place the given output @@ -624,9 +725,8 @@ MemoryRegion *LinkerScript::findMemoryRegion(OutputSection *Sec) { // If a memory region name was specified in the output section command, // then try to find that region first. if (!Sec->MemoryRegionName.empty()) { - auto It = MemoryRegions.find(Sec->MemoryRegionName); - if (It != MemoryRegions.end()) - return It->second; + if (MemoryRegion *M = MemoryRegions.lookup(Sec->MemoryRegionName)) + return M; error("memory region '" + Sec->MemoryRegionName + "' not declared"); return nullptr; } @@ -659,24 +759,27 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { setDot(Sec->AddrExpr, Sec->Location, false); Ctx->MemRegion = Sec->MemRegion; + Ctx->LMARegion = Sec->LMARegion; if (Ctx->MemRegion) - Dot = Ctx->MemRegionOffset[Ctx->MemRegion]; - - if (Sec->LMAExpr) { - uint64_t D = Dot; - Ctx->LMAOffset = [=] { return Sec->LMAExpr().getValue() - D; }; - } + Dot = Ctx->MemRegion->CurPos; switchTo(Sec); - // We do not support custom layout for compressed debug sectons. - // At this point we already know their size and have compressed content. - if (Ctx->OutSec->Flags & SHF_COMPRESSED) - return; + if (Sec->LMAExpr) + Ctx->LMAOffset = Sec->LMAExpr().getValue() - Dot; + + if (MemoryRegion *MR = Sec->LMARegion) + Ctx->LMAOffset = MR->CurPos - Dot; + + // If neither AT nor AT> is specified for an allocatable section, the linker + // will set the LMA such that the difference between VMA and LMA for the + // section is the same as the preceding output section in the same region + // https://sourceware.org/binutils/docs-2.20/ld/Output-Section-LMA.html + if (PhdrEntry *L = Ctx->OutSec->PtLoad) + L->LMAOffset = Ctx->LMAOffset; - // The Size previously denoted how many InputSections had been added to this - // section, and was used for sorting SHF_LINK_ORDER sections. Reset it to - // compute the actual size value. + // We can call this method multiple times during the creation of + // thunks and want to start over calculation each time. Sec->Size = 0; // We visited SectionsCommands from processSectionCommands to @@ -685,7 +788,9 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { for (BaseCommand *Base : Sec->SectionCommands) { // This handles the assignments to symbol or to the dot. if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + Cmd->Addr = Dot; assignSymbol(Cmd, true); + Cmd->Size = Dot - Cmd->Addr; continue; } @@ -693,15 +798,7 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { if (auto *Cmd = dyn_cast<ByteCommand>(Base)) { Cmd->Offset = Dot - Ctx->OutSec->Addr; Dot += Cmd->Size; - if (Ctx->MemRegion) - Ctx->MemRegionOffset[Ctx->MemRegion] += Cmd->Size; - Ctx->OutSec->Size = Dot - Ctx->OutSec->Addr; - continue; - } - - // Handle ASSERT(). - if (auto *Cmd = dyn_cast<AssertCommand>(Base)) { - Cmd->Expression(); + expandOutputSection(Cmd->Size); continue; } @@ -726,24 +823,28 @@ void LinkerScript::assignOffsets(OutputSection *Sec) { } } -void LinkerScript::removeEmptyCommands() { - // It is common practice to use very generic linker scripts. So for any - // given run some of the output sections in the script will be empty. - // We could create corresponding empty output sections, but that would - // clutter the output. - // We instead remove trivially empty sections. The bfd linker seems even - // more aggressive at removing them. - llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { - if (auto *Sec = dyn_cast<OutputSection>(Base)) - return !Sec->Live; +static bool isDiscardable(OutputSection &Sec) { + // We do not remove empty sections that are explicitly + // assigned to any segment. + if (!Sec.Phdrs.empty()) return false; - }); -} -static bool isAllSectionDescription(const OutputSection &Cmd) { - for (BaseCommand *Base : Cmd.SectionCommands) + // We do not want to remove sections that reference symbols in address and + // other expressions. We add script symbols as undefined, and want to ensure + // all of them are defined in the output, hence have to keep them. + if (Sec.ExpressionsUseSymbols) + return false; + + for (BaseCommand *Base : Sec.SectionCommands) { + if (auto Cmd = dyn_cast<SymbolAssignment>(Base)) + // Don't create empty output sections just for unreferenced PROVIDE + // symbols. + if (Cmd->Name != "." && !Cmd->Sym) + continue; + if (!isa<InputSectionDescription>(*Base)) return false; + } return true; } @@ -759,7 +860,7 @@ void LinkerScript::adjustSectionsBeforeSorting() { // Given that we want to create the section, we have to worry what impact // it will have on the link. For example, if we just create a section with // 0 for flags, it would change which PT_LOADs are created. - // We could remember that that particular section is dummy and ignore it in + // We could remember that particular section is dummy and ignore it in // other parts of the linker, but unfortunately there are quite a few places // that would need to change: // * The program header creation. @@ -770,34 +871,54 @@ void LinkerScript::adjustSectionsBeforeSorting() { // the previous sections. Only a few flags are needed to keep the impact low. uint64_t Flags = SHF_ALLOC; - for (BaseCommand *Cmd : SectionCommands) { + for (BaseCommand *&Cmd : SectionCommands) { auto *Sec = dyn_cast<OutputSection>(Cmd); if (!Sec) continue; - if (Sec->Live) { - Flags = Sec->Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR); - continue; - } - - if (isAllSectionDescription(*Sec)) - continue; - Sec->Live = true; - Sec->Flags = Flags; + // Handle align (e.g. ".foo : ALIGN(16) { ... }"). + if (Sec->AlignExpr) + Sec->Alignment = + std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue()); + + // A live output section means that some input section was added to it. It + // might have been removed (if it was empty synthetic section), but we at + // least know the flags. + if (Sec->Live) + Flags = Sec->Flags; + + // We do not want to keep any special flags for output section + // in case it is empty. + bool IsEmpty = getInputSections(Sec).empty(); + if (IsEmpty) + Sec->Flags = Flags & (SHF_ALLOC | SHF_WRITE | SHF_EXECINSTR); + + if (IsEmpty && isDiscardable(*Sec)) { + Sec->Live = false; + Cmd = nullptr; + } } + + // It is common practice to use very generic linker scripts. So for any + // given run some of the output sections in the script will be empty. + // We could create corresponding empty output sections, but that would + // clutter the output. + // We instead remove trivially empty sections. The bfd linker seems even + // more aggressive at removing them. + llvm::erase_if(SectionCommands, [&](BaseCommand *Base) { return !Base; }); } void LinkerScript::adjustSectionsAfterSorting() { // Try and find an appropriate memory region to assign offsets in. for (BaseCommand *Base : SectionCommands) { if (auto *Sec = dyn_cast<OutputSection>(Base)) { - if (!Sec->Live) - continue; + if (!Sec->LMARegionName.empty()) { + if (MemoryRegion *M = MemoryRegions.lookup(Sec->LMARegionName)) + Sec->LMARegion = M; + else + error("memory region '" + Sec->LMARegionName + "' not declared"); + } Sec->MemRegion = findMemoryRegion(Sec); - // Handle align (e.g. ".foo : ALIGN(16) { ... }"). - if (Sec->AlignExpr) - Sec->Alignment = - std::max<uint32_t>(Sec->Alignment, Sec->AlignExpr().getValue()); } } @@ -808,9 +929,9 @@ void LinkerScript::adjustSectionsAfterSorting() { // PHDRS { seg PT_LOAD; } // SECTIONS { .aaa : { *(.aaa) } } std::vector<StringRef> DefPhdrs; - auto FirstPtLoad = - std::find_if(PhdrsCommands.begin(), PhdrsCommands.end(), - [](const PhdrsCommand &Cmd) { return Cmd.Type == PT_LOAD; }); + auto FirstPtLoad = llvm::find_if(PhdrsCommands, [](const PhdrsCommand &Cmd) { + return Cmd.Type == PT_LOAD; + }); if (FirstPtLoad != PhdrsCommands.end()) DefPhdrs.push_back(FirstPtLoad->Name); @@ -839,6 +960,15 @@ static OutputSection *findFirstSection(PhdrEntry *Load) { return nullptr; } +static uint64_t computeBase(uint64_t Min, bool AllocateHeaders) { + // If there is no SECTIONS or if the linkerscript is explicit about program + // headers, do our best to allocate them. + if (!Script->HasSectionsCommand || AllocateHeaders) + return 0; + // Otherwise only allocate program headers if that would not add a page. + return alignDown(Min, Config->MaxPageSize); +} + // Try to find an address for the file and program headers output sections, // which were unconditionally added to the first PT_LOAD segment earlier. // @@ -862,17 +992,22 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) { return; PhdrEntry *FirstPTLoad = *It; + bool HasExplicitHeaders = + llvm::any_of(PhdrsCommands, [](const PhdrsCommand &Cmd) { + return Cmd.HasPhdrs || Cmd.HasFilehdr; + }); uint64_t HeaderSize = getHeaderSize(); - // When linker script with SECTIONS is being used, don't output headers - // unless there's a space for them. - uint64_t Base = HasSectionsCommand ? alignDown(Min, Config->MaxPageSize) : 0; - if (HeaderSize <= Min - Base || Script->hasPhdrsCommands()) { + if (HeaderSize <= Min - computeBase(Min, HasExplicitHeaders)) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; return; } + // Error if we were explicitly asked to allocate headers. + if (HasExplicitHeaders) + error("could not allocate headers"); + Out::ElfHeader->PtLoad = nullptr; Out::ProgramHeaders->PtLoad = nullptr; FirstPTLoad->FirstSec = findFirstSection(FirstPTLoad); @@ -883,8 +1018,8 @@ void LinkerScript::allocateHeaders(std::vector<PhdrEntry *> &Phdrs) { LinkerScript::AddressState::AddressState() { for (auto &MRI : Script->MemoryRegions) { - const MemoryRegion *MR = MRI.second; - MemRegionOffset[MR] = MR->Origin; + MemoryRegion *MR = MRI.second; + MR->CurPos = MR->Origin; } } @@ -916,15 +1051,11 @@ void LinkerScript::assignAddresses() { for (BaseCommand *Base : SectionCommands) { if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + Cmd->Addr = Dot; assignSymbol(Cmd, false); + Cmd->Size = Dot - Cmd->Addr; continue; } - - if (auto *Cmd = dyn_cast<AssertCommand>(Base)) { - Cmd->Expression(); - continue; - } - assignOffsets(cast<OutputSection>(Base)); } Ctx = nullptr; @@ -988,9 +1119,9 @@ ExprValue LinkerScript::getSymbolValue(StringRef Name, const Twine &Loc) { if (Symbol *Sym = Symtab->find(Name)) { if (auto *DS = dyn_cast<Defined>(Sym)) return {DS->Section, false, DS->Value, Loc}; - if (auto *SS = dyn_cast<SharedSymbol>(Sym)) - if (!ErrorOnMissingSection || SS->CopyRelSec) - return {SS->CopyRelSec, false, 0, Loc}; + if (isa<SharedSymbol>(Sym)) + if (!ErrorOnMissingSection) + return {nullptr, false, 0, Loc}; } error(Loc + ": symbol not found: " + Name); diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index 11131dda8e26..3b790dd4669f 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -11,9 +11,9 @@ #define LLD_ELF_LINKER_SCRIPT_H #include "Config.h" -#include "Strings.h" #include "Writer.h" #include "lld/Common/LLVM.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -75,7 +75,6 @@ enum SectionsCommandKind { AssignmentKind, // . = expr or <sym> = expr OutputSectionKind, InputSectionKind, - AssertKind, // ASSERT(expr) ByteKind // BYTE(expr), SHORT(expr), LONG(expr) or QUAD(expr) }; @@ -106,6 +105,16 @@ struct SymbolAssignment : BaseCommand { // Holds file name and line number for error reporting. std::string Location; + + // A string representation of this command. We use this for -Map. + std::string CommandString; + + // Address of this assignment command. + unsigned Addr; + + // Size of this assignment command. This is usually 0, but if + // you move '.' this may be greater than 0. + unsigned Size; }; // Linker scripts allow additional constraints to be put on ouput sections. @@ -118,11 +127,17 @@ enum class ConstraintKind { NoConstraint, ReadOnly, ReadWrite }; // target memory. Instances of the struct are created by parsing the // MEMORY command. struct MemoryRegion { + MemoryRegion(StringRef Name, uint64_t Origin, uint64_t Length, uint32_t Flags, + uint32_t NegFlags) + : Name(Name), Origin(Origin), Length(Length), Flags(Flags), + NegFlags(NegFlags) {} + std::string Name; uint64_t Origin; uint64_t Length; uint32_t Flags; uint32_t NegFlags; + uint64_t CurPos = 0; }; // This struct represents one section match pattern in SECTIONS() command. @@ -161,24 +176,23 @@ struct InputSectionDescription : BaseCommand { std::vector<std::pair<ThunkSection *, uint32_t>> ThunkSections; }; -// Represents an ASSERT(). -struct AssertCommand : BaseCommand { - AssertCommand(Expr E) : BaseCommand(AssertKind), Expression(E) {} - - static bool classof(const BaseCommand *C) { return C->Kind == AssertKind; } - - Expr Expression; -}; - // Represents BYTE(), SHORT(), LONG(), or QUAD(). struct ByteCommand : BaseCommand { - ByteCommand(Expr E, unsigned Size) - : BaseCommand(ByteKind), Expression(E), Size(Size) {} + ByteCommand(Expr E, unsigned Size, std::string CommandString) + : BaseCommand(ByteKind), CommandString(CommandString), Expression(E), + Size(Size) {} static bool classof(const BaseCommand *C) { return C->Kind == ByteKind; } + // Keeps string representing the command. Used for -Map" is perhaps better. + std::string CommandString; + Expr Expression; + + // This is just an offset of this assignment command in the output section. unsigned Offset; + + // Size of this data command. unsigned Size; }; @@ -200,8 +214,8 @@ class LinkerScript final { uint64_t ThreadBssOffset = 0; OutputSection *OutSec = nullptr; MemoryRegion *MemRegion = nullptr; - llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset; - std::function<uint64_t()> LMAOffset; + MemoryRegion *LMARegion = nullptr; + uint64_t LMAOffset = 0; }; llvm::DenseMap<StringRef, OutputSection *> NameToOutputSection; @@ -209,14 +223,13 @@ class LinkerScript final { void addSymbol(SymbolAssignment *Cmd); void assignSymbol(SymbolAssignment *Cmd, bool InSec); void setDot(Expr E, const Twine &Loc, bool InSec); + void expandOutputSection(uint64_t Size); + void expandMemoryRegions(uint64_t Size); std::vector<InputSection *> - computeInputSections(const InputSectionDescription *, - const llvm::DenseMap<SectionBase *, int> &Order); + computeInputSections(const InputSectionDescription *); - std::vector<InputSection *> - createInputSectionList(OutputSection &Cmd, - const llvm::DenseMap<SectionBase *, int> &Order); + std::vector<InputSection *> createInputSectionList(OutputSection &Cmd); std::vector<size_t> getPhdrIndices(OutputSection *Sec); @@ -251,7 +264,6 @@ public: ExprValue getSymbolValue(StringRef Name, const Twine &Loc); void addOrphanSections(); - void removeEmptyCommands(); void adjustSectionsBeforeSorting(); void adjustSectionsAfterSorting(); @@ -262,6 +274,10 @@ public: void assignAddresses(); void allocateHeaders(std::vector<PhdrEntry *> &Phdrs); void processSectionCommands(); + void declareSymbols(); + + // Used to handle INSERT AFTER statements. + void processInsertCommands(); // SECTIONS command list. std::vector<BaseCommand *> SectionCommands; @@ -281,6 +297,11 @@ public: // A list of symbols referenced by the script. std::vector<llvm::StringRef> ReferencedSymbols; + + // Used to implement INSERT [AFTER|BEFORE]. Contains commands that need + // to be inserted into SECTIONS commands list. + llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertAfterCommands; + llvm::DenseMap<StringRef, std::vector<BaseCommand *>> InsertBeforeCommands; }; extern LinkerScript *Script; diff --git a/ELF/MapFile.cpp b/ELF/MapFile.cpp index dcc829315e64..54fddfb7b299 100644 --- a/ELF/MapFile.cpp +++ b/ELF/MapFile.cpp @@ -23,11 +23,13 @@ #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SetVector.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -36,57 +38,46 @@ using namespace llvm::object; using namespace lld; using namespace lld::elf; -typedef DenseMap<const SectionBase *, SmallVector<Symbol *, 4>> SymbolMapTy; +typedef DenseMap<const SectionBase *, SmallVector<Defined *, 4>> SymbolMapTy; + +static const std::string Indent8 = " "; // 8 spaces +static const std::string Indent16 = " "; // 16 spaces // Print out the first three columns of a line. -static void writeHeader(raw_ostream &OS, uint64_t Addr, uint64_t Size, - uint64_t Align) { - int W = Config->Is64 ? 16 : 8; - OS << format("%0*llx %0*llx %5lld ", W, Addr, W, Size, Align); +static void writeHeader(raw_ostream &OS, uint64_t VMA, uint64_t LMA, + uint64_t Size, uint64_t Align) { + if (Config->Is64) + OS << format("%16llx %16llx %8llx %5lld ", VMA, LMA, Size, Align); + else + OS << format("%8llx %8llx %8llx %5lld ", VMA, LMA, Size, Align); } -static std::string indent(int Depth) { return std::string(Depth * 8, ' '); } - // Returns a list of all symbols that we want to print out. -static std::vector<Symbol *> getSymbols() { - std::vector<Symbol *> V; - for (InputFile *File : ObjectFiles) { - for (Symbol *B : File->getSymbols()) { - if (auto *SS = dyn_cast<SharedSymbol>(B)) - if (SS->CopyRelSec || SS->NeedsPltAddr) - V.push_back(SS); +static std::vector<Defined *> getSymbols() { + std::vector<Defined *> V; + for (InputFile *File : ObjectFiles) + for (Symbol *B : File->getSymbols()) if (auto *DR = dyn_cast<Defined>(B)) - if (DR->File == File && !DR->isSection() && DR->Section && - DR->Section->Live) + if (!DR->isSection() && DR->Section && DR->Section->Live && + (DR->File == File || DR->NeedsPltAddr || DR->Section->Bss)) V.push_back(DR); - } - } return V; } // Returns a map from sections to their symbols. -static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) { +static SymbolMapTy getSectionSyms(ArrayRef<Defined *> Syms) { SymbolMapTy Ret; - for (Symbol *S : Syms) { - if (auto *DR = dyn_cast<Defined>(S)) { - Ret[DR->Section].push_back(S); - continue; - } - - SharedSymbol *SS = cast<SharedSymbol>(S); - if (SS->CopyRelSec) - Ret[SS->CopyRelSec].push_back(S); - else - Ret[InX::Plt].push_back(S); - } + for (Defined *DR : Syms) + Ret[DR->Section].push_back(DR); // Sort symbols by address. We want to print out symbols in the // order in the output file rather than the order they appeared // in the input files. for (auto &It : Ret) { - SmallVectorImpl<Symbol *> &V = It.second; - std::sort(V.begin(), V.end(), - [](Symbol *A, Symbol *B) { return A->getVA() < B->getVA(); }); + SmallVectorImpl<Defined *> &V = It.second; + std::stable_sort(V.begin(), V.end(), [](Defined *A, Defined *B) { + return A->getVA() < B->getVA(); + }); } return Ret; } @@ -95,12 +86,15 @@ static SymbolMapTy getSectionSyms(ArrayRef<Symbol *> Syms) { // Demangling symbols (which is what toString() does) is slow, so // we do that in batch using parallel-for. static DenseMap<Symbol *, std::string> -getSymbolStrings(ArrayRef<Symbol *> Syms) { +getSymbolStrings(ArrayRef<Defined *> Syms) { std::vector<std::string> Str(Syms.size()); parallelForEachN(0, Syms.size(), [&](size_t I) { raw_string_ostream OS(Str[I]); - writeHeader(OS, Syms[I]->getVA(), Syms[I]->getSize(), 0); - OS << indent(2) << toString(*Syms[I]); + OutputSection *OSec = Syms[I]->getOutputSection(); + uint64_t VMA = Syms[I]->getVA(); + uint64_t LMA = OSec ? OSec->getLMA() + VMA - OSec->getVA(0) : 0; + writeHeader(OS, VMA, LMA, Syms[I]->getSize(), 1); + OS << Indent16 << toString(*Syms[I]); }); DenseMap<Symbol *, std::string> Ret; @@ -109,6 +103,44 @@ getSymbolStrings(ArrayRef<Symbol *> Syms) { return Ret; } +// Print .eh_frame contents. Since the section consists of EhSectionPieces, +// we need a specialized printer for that section. +// +// .eh_frame tend to contain a lot of section pieces that are contiguous +// both in input file and output file. Such pieces are squashed before +// being displayed to make output compact. +static void printEhFrame(raw_ostream &OS, OutputSection *OSec) { + std::vector<EhSectionPiece> Pieces; + + auto Add = [&](const EhSectionPiece &P) { + // If P is adjacent to Last, squash the two. + if (!Pieces.empty()) { + EhSectionPiece &Last = Pieces.back(); + if (Last.Sec == P.Sec && Last.InputOff + Last.Size == P.InputOff && + Last.OutputOff + Last.Size == P.OutputOff) { + Last.Size += P.Size; + return; + } + } + Pieces.push_back(P); + }; + + // Gather section pieces. + for (const CieRecord *Rec : InX::EhFrame->getCieRecords()) { + Add(*Rec->Cie); + for (const EhSectionPiece *Fde : Rec->Fdes) + Add(*Fde); + } + + // Print out section pieces. + for (EhSectionPiece &P : Pieces) { + writeHeader(OS, OSec->Addr + P.OutputOff, OSec->getLMA() + P.OutputOff, + P.Size, 1); + OS << Indent8 << toString(P.Sec->File) << ":(" << P.Sec->Name << "+0x" + << Twine::utohexstr(P.InputOff) + ")\n"; + } +} + void elf::writeMapFile() { if (Config->MapFile.empty()) return; @@ -122,32 +154,109 @@ void elf::writeMapFile() { } // Collect symbol info that we want to print out. - std::vector<Symbol *> Syms = getSymbols(); + std::vector<Defined *> Syms = getSymbols(); SymbolMapTy SectionSyms = getSectionSyms(Syms); DenseMap<Symbol *, std::string> SymStr = getSymbolStrings(Syms); // Print out the header line. int W = Config->Is64 ? 16 : 8; - OS << left_justify("Address", W) << ' ' << left_justify("Size", W) - << " Align Out In Symbol\n"; + OS << right_justify("VMA", W) << ' ' << right_justify("LMA", W) + << " Size Align Out In Symbol\n"; + + for (BaseCommand *Base : Script->SectionCommands) { + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + if (Cmd->Provide && !Cmd->Sym) + continue; + //FIXME: calculate and print LMA. + writeHeader(OS, Cmd->Addr, 0, Cmd->Size, 1); + OS << Cmd->CommandString << '\n'; + continue; + } - // Print out file contents. - for (OutputSection *OSec : OutputSections) { - writeHeader(OS, OSec->Addr, OSec->Size, OSec->Alignment); + auto *OSec = cast<OutputSection>(Base); + writeHeader(OS, OSec->Addr, OSec->getLMA(), OSec->Size, OSec->Alignment); OS << OSec->Name << '\n'; // Dump symbols for each input section. for (BaseCommand *Base : OSec->SectionCommands) { - auto *ISD = dyn_cast<InputSectionDescription>(Base); - if (!ISD) + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) { + for (InputSection *IS : ISD->Sections) { + if (IS == InX::EhFrame) { + printEhFrame(OS, OSec); + continue; + } + + writeHeader(OS, IS->getVA(0), OSec->getLMA() + IS->getOffset(0), + IS->getSize(), IS->Alignment); + OS << Indent8 << toString(IS) << '\n'; + for (Symbol *Sym : SectionSyms[IS]) + OS << SymStr[Sym] << '\n'; + } + continue; + } + + if (auto *Cmd = dyn_cast<ByteCommand>(Base)) { + writeHeader(OS, OSec->Addr + Cmd->Offset, OSec->getLMA() + Cmd->Offset, + Cmd->Size, 1); + OS << Indent8 << Cmd->CommandString << '\n'; + continue; + } + + if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) { + if (Cmd->Provide && !Cmd->Sym) + continue; + writeHeader(OS, Cmd->Addr, OSec->getLMA() + Cmd->Addr - OSec->getVA(0), + Cmd->Size, 1); + OS << Indent8 << Cmd->CommandString << '\n'; continue; - for (InputSection *IS : ISD->Sections) { - writeHeader(OS, OSec->Addr + IS->OutSecOff, IS->getSize(), - IS->Alignment); - OS << indent(1) << toString(IS) << '\n'; - for (Symbol *Sym : SectionSyms[IS]) - OS << SymStr[Sym] << '\n'; } } } } + +static void print(StringRef A, StringRef B) { + outs() << left_justify(A, 49) << " " << B << "\n"; +} + +// Output a cross reference table to stdout. This is for --cref. +// +// For each global symbol, we print out a file that defines the symbol +// followed by files that uses that symbol. Here is an example. +// +// strlen /lib/x86_64-linux-gnu/libc.so.6 +// tools/lld/tools/lld/CMakeFiles/lld.dir/lld.cpp.o +// lib/libLLVMSupport.a(PrettyStackTrace.cpp.o) +// +// In this case, strlen is defined by libc.so.6 and used by other two +// files. +void elf::writeCrossReferenceTable() { + if (!Config->Cref) + return; + + // Collect symbols and files. + MapVector<Symbol *, SetVector<InputFile *>> Map; + for (InputFile *File : ObjectFiles) { + for (Symbol *Sym : File->getSymbols()) { + if (isa<SharedSymbol>(Sym)) + Map[Sym].insert(File); + if (auto *D = dyn_cast<Defined>(Sym)) + if (!D->isLocal() && (!D->Section || D->Section->Live)) + Map[D].insert(File); + } + } + + // Print out a header. + outs() << "Cross Reference Table\n\n"; + print("Symbol", "File"); + + // Print out a table. + for (auto KV : Map) { + Symbol *Sym = KV.first; + SetVector<InputFile *> &Files = KV.second; + + print(toString(*Sym), toString(Sym->File)); + for (InputFile *File : Files) + if (File != Sym->File) + print("", toString(File)); + } +} diff --git a/ELF/MapFile.h b/ELF/MapFile.h index 2d93e26d4cf8..0282425888b7 100644 --- a/ELF/MapFile.h +++ b/ELF/MapFile.h @@ -13,6 +13,7 @@ namespace lld { namespace elf { void writeMapFile(); +void writeCrossReferenceTable(); } // namespace elf } // namespace lld diff --git a/ELF/MarkLive.cpp b/ELF/MarkLive.cpp index 88f558c7a3c6..a8371e212c3e 100644 --- a/ELF/MarkLive.cpp +++ b/ELF/MarkLive.cpp @@ -20,15 +20,15 @@ // //===----------------------------------------------------------------------===// +#include "MarkLive.h" #include "InputSection.h" #include "LinkerScript.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" -#include "Writer.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" #include <functional> @@ -60,8 +60,9 @@ static typename ELFT::uint getAddend(InputSectionBase &Sec, static DenseMap<StringRef, std::vector<InputSectionBase *>> CNamedSections; template <class ELFT, class RelT> -static void resolveReloc(InputSectionBase &Sec, RelT &Rel, - std::function<void(InputSectionBase *, uint64_t)> Fn) { +static void +resolveReloc(InputSectionBase &Sec, RelT &Rel, + llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { Symbol &B = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); // If a symbol is referenced in a live section, it is used. @@ -90,7 +91,7 @@ static void resolveReloc(InputSectionBase &Sec, RelT &Rel, template <class ELFT> static void forEachSuccessor(InputSection &Sec, - std::function<void(InputSectionBase *, uint64_t)> Fn) { + llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { if (Sec.AreRelocsRela) { for (const typename ELFT::Rela &Rel : Sec.template relas<ELFT>()) resolveReloc<ELFT>(Sec, Rel, Fn); @@ -120,7 +121,7 @@ forEachSuccessor(InputSection &Sec, template <class ELFT, class RelTy> static void scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels, - std::function<void(InputSectionBase *, uint64_t)> Fn) { + llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { const endianness E = ELFT::TargetEndianness; for (unsigned I = 0, N = EH.Pieces.size(); I < N; ++I) { @@ -155,14 +156,10 @@ scanEhFrameSection(EhInputSection &EH, ArrayRef<RelTy> Rels, template <class ELFT> static void scanEhFrameSection(EhInputSection &EH, - std::function<void(InputSectionBase *, uint64_t)> Fn) { + llvm::function_ref<void(InputSectionBase *, uint64_t)> Fn) { if (!EH.NumRelocations) return; - // Unfortunately we need to split .eh_frame early since some relocations in - // .eh_frame keep other section alive and some don't. - EH.split<ELFT>(); - if (EH.AreRelocsRela) scanEhFrameSection<ELFT>(EH, EH.template relas<ELFT>(), Fn); else @@ -207,7 +204,7 @@ template <class ELFT> static void doGcSections() { // (splittable) sections, each piece of data has independent liveness bit. // So we explicitly tell it which offset is in use. if (auto *MS = dyn_cast<MergeInputSection>(Sec)) - MS->markLiveAt(Offset); + MS->getSectionPiece(Offset)->Live = true; if (Sec->Live) return; @@ -279,13 +276,18 @@ template <class ELFT> void elf::markLive() { // The -gc-sections option works only for SHF_ALLOC sections // (sections that are memory-mapped at runtime). So we can - // unconditionally make non-SHF_ALLOC sections alive. + // unconditionally make non-SHF_ALLOC sections alive except + // SHF_LINK_ORDER and SHT_REL/SHT_RELA sections. // - // Non SHF_ALLOC sections are not removed even if they are + // Usually, SHF_ALLOC sections are not removed even if they are // unreachable through relocations because reachability is not // a good signal whether they are garbage or not (e.g. there is // usually no section referring to a .comment section, but we - // want to keep it.) + // want to keep it.). + // + // Note on SHF_LINK_ORDER: Such sections contain metadata and they + // have a reverse dependency on the InputSection they are linked with. + // We are able to garbage collect them. // // Note on SHF_REL{,A}: Such sections reach here only when -r // or -emit-reloc were given. And they are subject of garbage @@ -293,8 +295,9 @@ template <class ELFT> void elf::markLive() { // remove its relocation section. for (InputSectionBase *Sec : InputSections) { bool IsAlloc = (Sec->Flags & SHF_ALLOC); + bool IsLinkOrder = (Sec->Flags & SHF_LINK_ORDER); bool IsRel = (Sec->Type == SHT_REL || Sec->Type == SHT_RELA); - if (!IsAlloc && !IsRel) + if (!IsAlloc && !IsLinkOrder && !IsRel) Sec->Live = true; } @@ -305,8 +308,7 @@ template <class ELFT> void elf::markLive() { if (Config->PrintGcSections) for (InputSectionBase *Sec : InputSections) if (!Sec->Live) - message("removing unused section from '" + Sec->Name + "' in file '" + - Sec->File->getName() + "'"); + message("removing unused section " + toString(Sec)); } template void elf::markLive<ELF32LE>(); diff --git a/ELF/MarkLive.h b/ELF/MarkLive.h new file mode 100644 index 000000000000..c9b99add34de --- /dev/null +++ b/ELF/MarkLive.h @@ -0,0 +1,21 @@ +//===- MarkLive.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_ELF_MARKLIVE_H +#define LLD_ELF_MARKLIVE_H + +namespace lld { +namespace elf { + +template <class ELFT> void markLive(); + +} // namespace elf +} // namespace lld + +#endif // LLD_ELF_MARKLIVE_H diff --git a/ELF/Options.td b/ELF/Options.td index 20027e90aefd..73457db8332f 100644 --- a/ELF/Options.td +++ b/ELF/Options.td @@ -4,66 +4,91 @@ include "llvm/Option/OptParser.td" // two can precede the option name except those that start with 'o'. class F<string name>: Flag<["--", "-"], name>; class J<string name>: Joined<["--", "-"], name>; -class S<string name>: Separate<["--", "-"], name>; -multiclass Eq<string name> { - def "": Separate<["--", "-"], name>; - def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>; +multiclass Eq<string name, string help> { + def NAME: Separate<["--", "-"], name>; + def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>, + HelpText<help>; } -def auxiliary: S<"auxiliary">, HelpText<"Set DT_AUXILIARY field to the specified name">; +multiclass B<string name, string help1, string help2> { + def NAME: Flag<["--", "-"], name>, HelpText<help1>; + def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>; +} + +defm auxiliary: Eq<"auxiliary", "Set DT_AUXILIARY field to the specified name">; def Bsymbolic: F<"Bsymbolic">, HelpText<"Bind defined symbols locally">; def Bsymbolic_functions: F<"Bsymbolic-functions">, HelpText<"Bind defined function symbols locally">; -def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries">; +def Bdynamic: F<"Bdynamic">, HelpText<"Link against shared libraries (default)">; def Bstatic: F<"Bstatic">, HelpText<"Do not link against shared libraries">; -def build_id: F<"build-id">, HelpText<"Generate build ID note">; +def build_id: F<"build-id">, HelpText<"Alias for --build-id=fast">; + +def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">, + MetaVarName<"[fast,md5,sha,uuid,0x<hexstring>]">; -def build_id_eq: J<"build-id=">, HelpText<"Generate build ID note">; +defm check_sections: B<"check-sections", + "Check section addresses for overlaps (default)", + "Do not check section addresses for overlaps">; -defm compress_debug_sections : Eq<"compress-debug-sections">, - HelpText<"Compress DWARF debug sections">; +defm compress_debug_sections: + Eq<"compress-debug-sections", "Compress DWARF debug sections">, + MetaVarName<"[none,zlib]">; -defm defsym: Eq<"defsym">, HelpText<"Define a symbol alias">; +defm defsym: Eq<"defsym", "Define a symbol alias">, MetaVarName<"<symbol>=<value>">; -defm library_path: Eq<"library-path">, - HelpText<"Add a directory to the library search path">, MetaVarName<"<dir>">; +defm library_path: + Eq<"library-path", "Add a directory to the library search path">, MetaVarName<"<dir>">; def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">; -defm Tbss: Eq<"Tbss">, - HelpText<"Same as --section-start with .bss as the sectionname">; +defm Tbss: Eq<"Tbss", "Same as --section-start with .bss as the sectionname">; -defm Tdata: Eq<"Tdata">, - HelpText<"Same as --section-start with .data as the sectionname">; +defm Tdata: Eq<"Tdata", "Same as --section-start with .data as the sectionname">; -defm Ttext: Eq<"Ttext">, - HelpText<"Same as --section-start with .text as the sectionname">; +defm Ttext: Eq<"Ttext", "Same as --section-start with .text as the sectionname">; -def allow_multiple_definition: F<"allow-multiple-definition">, - HelpText<"Allow multiple definitions">; +defm allow_multiple_definition: B<"allow-multiple-definition", + "Allow multiple definitions", + "Do not allow multiple definitions (default)">; -def as_needed: F<"as-needed">, - HelpText<"Only set DT_NEEDED for shared libraries if used">; +defm apply_dynamic_relocs: B<"apply-dynamic-relocs", + "Apply dynamic relocations to place", + "Do not apply dynamic relocations to place">; + +defm as_needed: B<"as-needed", + "Only set DT_NEEDED for shared libraries if used", + "Always set DT_NEEDED for shared libraries (default)">; + +defm call_graph_ordering_file: + Eq<"call-graph-ordering-file", "Layout sections to optimize the given callgraph">; // -chroot doesn't have a help text because it is an internal option. -def chroot: S<"chroot">; +def chroot: Separate<["--", "-"], "chroot">; def color_diagnostics: F<"color-diagnostics">, - HelpText<"Use colors in diagnostics">; + HelpText<"Alias for --color-diagnostics=always">; def color_diagnostics_eq: J<"color-diagnostics=">, - HelpText<"Use colors in diagnostics">; + HelpText<"Use colors in diagnostics">, + MetaVarName<"[auto,always,never]">; + +defm cref: B<"cref", + "Output cross reference table", + "Do not output cross reference table">; -def define_common: F<"define-common">, - HelpText<"Assign space to common symbols">; +defm define_common: B<"define-common", + "Assign space to common symbols", + "Do not assign space to common symbols">; -def demangle: F<"demangle">, HelpText<"Demangle symbol names">; +defm demangle: B<"demangle", + "Demangle symbol names (default)", + "Do not demangle symbol names">; def disable_new_dtags: F<"disable-new-dtags">, HelpText<"Disable new dynamic tags">; @@ -76,158 +101,126 @@ def discard_locals: F<"discard-locals">, def discard_none: F<"discard-none">, HelpText<"Keep all symbols in the symbol table">; -def dynamic_linker: S<"dynamic-linker">, - HelpText<"Which dynamic linker to use">; +defm dynamic_linker: Eq<"dynamic-linker", "Which dynamic linker to use">; -defm dynamic_list: Eq<"dynamic-list">, - HelpText<"Read a list of dynamic symbols">; +defm dynamic_list: Eq<"dynamic-list", "Read a list of dynamic symbols">; -def eh_frame_hdr: F<"eh-frame-hdr">, - HelpText<"Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header">; +defm eh_frame_hdr: B<"eh-frame-hdr", + "Request creation of .eh_frame_hdr section and PT_GNU_EH_FRAME segment header", + "Do not create .eh_frame_hdr section">; def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">; def enable_new_dtags: F<"enable-new-dtags">, - HelpText<"Enable new dynamic tags">; + HelpText<"Enable new dynamic tags (default)">; + +def end_group: F<"end-group">, + HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">; def end_lib: F<"end-lib">, HelpText<"End a grouping of objects that should be treated as if they were together in an archive">; -defm entry: Eq<"entry">, HelpText<"Name of entry point symbol">, +defm entry: Eq<"entry", "Name of entry point symbol">, MetaVarName<"<entry>">; -defm error_limit: Eq<"error-limit">, - HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">; +defm error_limit: + Eq<"error-limit", "Maximum number of errors to emit before stopping (0 = no limit)">; def error_unresolved_symbols: F<"error-unresolved-symbols">, HelpText<"Report unresolved symbols as errors">; -defm exclude_libs: Eq<"exclude-libs">, - HelpText<"Exclude static libraries from automatic export">; +defm exclude_libs: Eq<"exclude-libs", "Exclude static libraries from automatic export">; -def export_dynamic: F<"export-dynamic">, - HelpText<"Put symbols in the dynamic symbol table">; +defm export_dynamic: B<"export-dynamic", + "Put symbols in the dynamic symbol table", + "Do not put symbols in the dynamic symbol table (default)">; -defm export_dynamic_symbol: Eq<"export-dynamic-symbol">, - HelpText<"Put a symbol in the dynamic symbol table">; +defm export_dynamic_symbol: + Eq<"export-dynamic-symbol", "Put a symbol in the dynamic symbol table">; -def fatal_warnings: F<"fatal-warnings">, - HelpText<"Treat warnings as errors">; +defm fatal_warnings: B<"fatal-warnings", + "Treat warnings as errors", + "Do not treat warnings as errors (default)">; -defm filter: Eq<"filter">, - HelpText<"Set DT_FILTER field to the specified name">; +defm filter: Eq<"filter", "Set DT_FILTER field to the specified name">; -defm fini: Eq<"fini">, - HelpText<"Specify a finalizer function">, MetaVarName<"<symbol>">; +defm fini: Eq<"fini", "Specify a finalizer function">, MetaVarName<"<symbol>">; def fix_cortex_a53_843419: F<"fix-cortex-a53-843419">, HelpText<"Apply fixes for AArch64 Cortex-A53 erratum 843419">; -def full_shutdown : F<"full-shutdown">, - HelpText<"Perform a full shutdown instead of calling _exit">; +defm format: Eq<"format", "Change the input format of the inputs following this option">, + MetaVarName<"[default,elf,binary]">; -defm format: Eq<"format">, - HelpText<"Change the input format of the inputs following this option">, - MetaVarName<"<input-format>">; +defm gc_sections: B<"gc-sections", + "Enable garbage collection of unused sections", + "Disable garbage collection of unused sections (default)">; -def gc_sections: F<"gc-sections">, - HelpText<"Enable garbage collection of unused sections">; +defm gdb_index: B<"gdb-index", + "Generate .gdb_index section", + "Do not generate .gdb_index section (default)">; -def gdb_index: F<"gdb-index">, - HelpText<"Generate .gdb_index section">; +defm gnu_unique: B<"gnu-unique", + "Enable STB_GNU_UNIQUE symbol binding (default)", + "Disable STB_GNU_UNIQUE symbol binding">; -defm hash_style: Eq<"hash-style">, - HelpText<"Specify hash style (sysv, gnu or both)">; +defm hash_style: Eq<"hash-style", "Specify hash style (sysv, gnu or both)">; def help: F<"help">, HelpText<"Print option help">; def icf_all: F<"icf=all">, HelpText<"Enable identical code folding">; -def icf_data: F<"icf-data">, - HelpText<"Enable ICF to also fold identical read only data">; +def icf_safe: F<"icf=safe">, HelpText<"Enable safe identical code folding">; + +def icf_none: F<"icf=none">, HelpText<"Disable identical code folding (default)">; + +def ignore_function_address_equality: F<"ignore-function-address-equality">, + HelpText<"lld can break the address equality of functions">; -def icf_none: F<"icf=none">, HelpText<"Disable identical code folding">; +def ignore_data_address_equality: F<"ignore-data-address-equality">, + HelpText<"lld can break the address equality of data">; -defm image_base : Eq<"image-base">, HelpText<"Set the base address">; +defm image_base: Eq<"image-base", "Set the base address">; -defm init: Eq<"init">, HelpText<"Specify an initializer function">, +defm init: Eq<"init", "Specify an initializer function">, MetaVarName<"<symbol>">; -defm library: Eq<"library">, HelpText<"Root name of library to use">, - MetaVarName<"<libName>">; +defm just_symbols: Eq<"just-symbols", "Just link symbols">; -def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, - HelpText<"Optimization level for LTO">; +defm keep_unique: Eq<"keep-unique", "Do not fold this symbol during ICF">; + +defm library: Eq<"library", "Root name of library to use">, + MetaVarName<"<libName>">; def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; -defm Map: Eq<"Map">, HelpText<"Print a link map to the specified file">; +defm Map: Eq<"Map", "Print a link map to the specified file">; -def merge_exidx_entries: F<"merge-exidx-entries">, - HelpText<"Enable merging .ARM.exidx entries">; +defm merge_exidx_entries: B<"merge-exidx-entries", + "Enable merging .ARM.exidx entries (default)", + "Disable merging .ARM.exidx entries">; def nostdlib: F<"nostdlib">, HelpText<"Only search directories specified on the command line">; -def no_as_needed: F<"no-as-needed">, - HelpText<"Always DT_NEEDED for shared libraries">; - def no_color_diagnostics: F<"no-color-diagnostics">, HelpText<"Do not use colors in diagnostics">; -def no_define_common: F<"no-define-common">, - HelpText<"Do not assign space to common symbols">; - -def no_demangle: F<"no-demangle">, - HelpText<"Do not demangle symbol names">; - def no_dynamic_linker: F<"no-dynamic-linker">, HelpText<"Inhibit output of .interp section">; -def no_eh_frame_hdr: F<"no-eh-frame-hdr">, - HelpText<"Do not create .eh_frame_hdr section">; - -def no_export_dynamic: F<"no-export-dynamic">; -def no_fatal_warnings: F<"no-fatal-warnings">; - -def no_gc_sections: F<"no-gc-sections">, - HelpText<"Disable garbage collection of unused sections">; - -def no_gdb_index: F<"no-gdb-index">, - HelpText<"Do not generate .gdb_index section">; - -def no_gnu_unique: F<"no-gnu-unique">, - HelpText<"Disable STB_GNU_UNIQUE symbol binding">; - -def no_merge_exidx_entries: F<"no-merge-exidx-entries">, - HelpText<"Disable merging .ARM.exidx entries">; - -def no_threads: F<"no-threads">, - HelpText<"Do not run the linker multi-threaded">; - -def no_whole_archive: F<"no-whole-archive">, - HelpText<"Restores the default behavior of loading archive members">; - def noinhibit_exec: F<"noinhibit-exec">, HelpText<"Retain the executable output file whenever it is still usable">; -def nopie: F<"nopie">, HelpText<"Do not create a position independent executable">; - -def no_omagic: Flag<["--"], "no-omagic">, MetaVarName<"<magic>">, +def no_omagic: F<"no-omagic">, MetaVarName<"<magic>">, HelpText<"Do not set the text data sections to be writable">; -def no_print_gc_sections: F<"no-print-gc-sections">, - HelpText<"Do not list removed unused sections">; - def no_rosegment: F<"no-rosegment">, HelpText<"Do not put read-only non-executable sections in their own segment">; def no_undefined: F<"no-undefined">, HelpText<"Report unresolved symbols even if the linker is creating a shared library">; -def no_undefined_version: F<"no-undefined-version">, - HelpText<"Report version scripts that refer undefined symbols">; - def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">, HelpText<"Path to file to write output">; @@ -237,42 +230,62 @@ def oformat: Separate<["--"], "oformat">, MetaVarName<"<format>">, def omagic: Flag<["--"], "omagic">, MetaVarName<"<magic>">, HelpText<"Set the text and data sections to be readable and writable">; -defm orphan_handling: Eq<"orphan-handling">, - HelpText<"Control how orphan sections are handled when linker script used">; +defm orphan_handling: + Eq<"orphan-handling", "Control how orphan sections are handled when linker script used">; + +defm pack_dyn_relocs: + Eq<"pack-dyn-relocs", "Pack dynamic relocations in the given format">, + MetaVarName<"[none,android,relr,android+relr]">; + +defm use_android_relr_tags: B<"use-android-relr-tags", + "Use SHT_ANDROID_RELR / DT_ANDROID_RELR* tags instead of SHT_RELR / DT_RELR*", + "Use SHT_RELR / DT_RELR* tags (default)">; + +defm pie: B<"pie", + "Create a position independent executable", + "Do not create a position independent executable (default)">; + +defm print_gc_sections: B<"print-gc-sections", + "List removed unused sections", + "Do not list removed unused sections (default)">; -def pack_dyn_relocs_eq: J<"pack-dyn-relocs=">, MetaVarName<"<format>">, - HelpText<"Pack dynamic relocations in the given format (none or android)">; +defm print_icf_sections: B<"print-icf-sections", + "List identical folded sections", + "Do not list identical folded sections (default)">; -def pie: F<"pie">, HelpText<"Create a position independent executable">; +def pop_state: F<"pop-state">, + HelpText<"Undo the effect of -push-state">; -def print_gc_sections: F<"print-gc-sections">, - HelpText<"List removed unused sections">; +def push_state: F<"push-state">, + HelpText<"Save the current state of -as-needed, -static and -whole-archive">; def print_map: F<"print-map">, HelpText<"Print a link map to the standard output">; -defm reproduce: Eq<"reproduce">, - HelpText<"Dump linker invocation and input files for debugging">; +defm reproduce: Eq<"reproduce", "Dump linker invocation and input files for debugging">; -defm rpath: Eq<"rpath">, HelpText<"Add a DT_RUNPATH to the output">; +defm rpath: Eq<"rpath", "Add a DT_RUNPATH to the output">; def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; -defm retain_symbols_file: Eq<"retain-symbols-file">, - HelpText<"Retain only the symbols listed in the file">, +defm retain_symbols_file: + Eq<"retain-symbols-file", "Retain only the symbols listed in the file">, MetaVarName<"<file>">; -defm script: Eq<"script">, HelpText<"Read linker script">; +defm script: Eq<"script", "Read linker script">; -def section_start: S<"section-start">, MetaVarName<"<address>">, - HelpText<"Set address of section">; +defm section_start: Eq<"section-start", "Set address of section">, + MetaVarName<"<address>">; def shared: F<"shared">, HelpText<"Build a shared object">; -defm soname: Eq<"soname">, HelpText<"Set DT_SONAME">; +defm soname: Eq<"soname", "Set DT_SONAME">; -defm sort_section: Eq<"sort-section">, - HelpText<"Specifies sections sorting rule when linkerscript is used">; +defm sort_section: + Eq<"sort-section", "Specifies sections sorting rule when linkerscript is used">; + +def start_group: F<"start-group">, + HelpText<"Ignored for compatibility with GNU unless you pass --warn-backrefs">; def start_lib: F<"start-lib">, HelpText<"Start a grouping of objects that should be treated as if they were together in an archive">; @@ -281,33 +294,39 @@ def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; -def symbol_ordering_file: S<"symbol-ordering-file">, - HelpText<"Layout sections in the order specified by symbol file">; +defm symbol_ordering_file: + Eq<"symbol-ordering-file", "Layout sections to place symbols in the order specified by symbol ordering file">; -defm sysroot: Eq<"sysroot">, HelpText<"Set the system root">; +defm sysroot: Eq<"sysroot", "Set the system root">; def target1_rel: F<"target1-rel">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_REL32">; -def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32">; +def target1_abs: F<"target1-abs">, HelpText<"Interpret R_ARM_TARGET1 as R_ARM_ABS32 (default)">; -defm target2: Eq<"target2">, - HelpText<"Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">, +defm target2: + Eq<"target2", "Interpret R_ARM_TARGET2 as <type>, where <type> is one of rel, abs, or got-rel">, MetaVarName<"<type>">; -def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; +defm threads: B<"threads", + "Run the linker multi-threaded (default)", + "Do not run the linker multi-threaded">; def trace: F<"trace">, HelpText<"Print the names of the input files">; -defm trace_symbol : Eq<"trace-symbol">, HelpText<"Trace references to symbols">; +defm trace_symbol: Eq<"trace-symbol", "Trace references to symbols">; + +defm undefined: Eq<"undefined", "Force undefined symbol during linking">, + MetaVarName<"<symbol>">; -defm undefined: Eq<"undefined">, - HelpText<"Force undefined symbol during linking">; +defm unresolved_symbols: + Eq<"unresolved-symbols", "Determine how to handle unresolved symbols">; -defm unresolved_symbols: Eq<"unresolved-symbols">, - HelpText<"Determine how to handle unresolved symbols">; +defm undefined_version: B<"undefined-version", + "Allow unused version in version script (default)", + "Report version scripts that refer undefined symbols">; -defm rsp_quoting: Eq<"rsp-quoting">, - HelpText<"Quoting style for response files. Values supported: windows|posix">; +defm rsp_quoting: Eq<"rsp-quoting", "Quoting style for response files">, + MetaVarName<"[posix,windows]">; def v: Flag<["-"], "v">, HelpText<"Display the version number">; @@ -315,91 +334,123 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">; def version: F<"version">, HelpText<"Display the version number and exit">; -defm version_script: Eq<"version-script">, HelpText<"Read a version script">; +defm version_script: Eq<"version-script", "Read a version script">; + +defm warn_backrefs: B<"warn-backrefs", + "Warn about backward symbol references to fetch archive members", + "Do not warn about backward symbol references to fetch archive members (default)">; + +defm warn_common: B<"warn-common", + "Warn about duplicate common symbols", + "Do not warn about duplicate common symbols (default)">; -def warn_common: F<"warn-common">, - HelpText<"Warn about duplicate common symbols">; +defm warn_symbol_ordering: B<"warn-symbol-ordering", + "Warn about problems with the symbol ordering file (default)", + "Do not warn about problems with the symbol ordering file">; def warn_unresolved_symbols: F<"warn-unresolved-symbols">, HelpText<"Report unresolved symbols as warnings">; -def whole_archive: F<"whole-archive">, - HelpText<"Force load of all members in a static library">; +defm whole_archive: B<"whole-archive", + "Force load of all members in a static library", + "Do not force load of all members in a static library (default)">; -defm wrap: Eq<"wrap">, HelpText<"Use wrapper functions for symbol">, - MetaVarName<"<symbol>">; +defm wrap: Eq<"wrap", "Use wrapper functions for symbol">, + MetaVarName<"<symbol>=<symbol>">; def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, HelpText<"Linker option extensions">; // Aliases -def alias_auxiliary: Separate<["-"], "f">, Alias<auxiliary>; -def alias_Bdynamic_call_shared: F<"call_shared">, Alias<Bdynamic>; -def alias_Bdynamic_dy: F<"dy">, Alias<Bdynamic>; -def alias_Bstatic_dn: F<"dn">, Alias<Bstatic>; -def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>; -def alias_Bstatic_static: F<"static">, Alias<Bstatic>; -def alias_define_common_d: Flag<["-"], "d">, Alias<define_common>; -def alias_define_common_dc: F<"dc">, Alias<define_common>; -def alias_define_common_dp: F<"dp">, Alias<define_common>; -def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>; -def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>; -def alias_emit_relocs: Flag<["-"], "q">, Alias<emit_relocs>; -def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; -def alias_export_dynamic_E: Flag<["-"], "E">, Alias<export_dynamic>; -def alias_filter: Separate<["-"], "F">, Alias<filter>; -def alias_format_b: S<"b">, Alias<format>; -def alias_library: JoinedOrSeparate<["-"], "l">, Alias<library>; -def alias_library_path: JoinedOrSeparate<["-"], "L">, Alias<library_path>; -def alias_omagic: Flag<["-"], "N">, Alias<omagic>; -def alias_o_output: Joined<["--"], "output=">, Alias<o>; -def alias_o_output2 : Separate<["--"], "output">, Alias<o>; -def alias_pie_pic_executable: F<"pic-executable">, Alias<pie>; -def alias_print_map_M: Flag<["-"], "M">, Alias<print_map>; -def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; -def alias_rpath_R: JoinedOrSeparate<["-"], "R">, Alias<rpath>; -def alias_script_T: JoinedOrSeparate<["-"], "T">, Alias<script>; -def alias_shared_Bshareable: F<"Bshareable">, Alias<shared>; -def alias_soname_h: JoinedOrSeparate<["-"], "h">, Alias<soname>; -def alias_strip_all: Flag<["-"], "s">, Alias<strip_all>; -def alias_strip_debug_S: Flag<["-"], "S">, Alias<strip_debug>; -def alias_trace: Flag<["-"], "t">, Alias<trace>; -def alias_trace_symbol_y : JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>; -def alias_Ttext_segment: S<"Ttext-segment">, Alias<Ttext>; -def alias_Ttext_segment_eq: J<"Ttext-segment=">, Alias<Ttext>; -def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>; -def alias_version_V: Flag<["-"], "V">, Alias<version>; - -// Our symbol resolution algorithm handles symbols in archive files differently -// than traditional linkers, so we don't need --start-group and --end-group. -// These options are recongized for compatibility but ignored. -def end_group: F<"end-group">; -def end_group_paren: Flag<["-"], ")">; -def start_group: F<"start-group">; -def start_group_paren: Flag<["-"], "(">; +def: Separate<["-"], "f">, Alias<auxiliary>, HelpText<"Alias for --auxiliary">; +def: F<"call_shared">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">; +def: F<"dy">, Alias<Bdynamic>, HelpText<"Alias for --Bdynamic">; +def: F<"dn">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">; +def: F<"non_shared">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">; +def: F<"static">, Alias<Bstatic>, HelpText<"Alias for --Bstatic">; +def: Flag<["-"], "d">, Alias<define_common>, HelpText<"Alias for --define-common">; +def: F<"dc">, Alias<define_common>, HelpText<"Alias for --define-common">; +def: F<"dp">, Alias<define_common>, HelpText<"Alias for --define-common">; +def: Flag<["-"], "x">, Alias<discard_all>, HelpText<"Alias for --discard-all">; +def: Flag<["-"], "X">, Alias<discard_locals>, HelpText<"Alias for --discard-locals">; +def: Flag<["-"], "q">, Alias<emit_relocs>, HelpText<"Alias for --emit-relocs">; +def: Flag<["-"], ")">, Alias<end_group>, HelpText<"Alias for --end-group">; +def: JoinedOrSeparate<["-"], "e">, Alias<entry>, HelpText<"Alias for --entry">; +def: Flag<["-"], "E">, Alias<export_dynamic>, HelpText<"Alias for --export-dynamic">; +def: Separate<["-"], "F">, Alias<filter>, HelpText<"Alias for --filter">; +def: Separate<["-"], "b">, Alias<format>, HelpText<"Alias for --format">; +def: JoinedOrSeparate<["-"], "l">, Alias<library>, HelpText<"Alias for --library">; +def: JoinedOrSeparate<["-"], "L">, Alias<library_path>, HelpText<"Alias for --library-path">; +def: F<"no-pic-executable">, Alias<no_pie>, HelpText<"Alias for --no-pie">; +def: Flag<["-"], "N">, Alias<omagic>, HelpText<"Alias for --omagic">; +def: Joined<["--"], "output=">, Alias<o>, HelpText<"Alias for -o">; +def: Separate<["--"], "output">, Alias<o>, HelpText<"Alias for -o">; +def: F<"pic-executable">, Alias<pie>, HelpText<"Alias for --pie">; +def: Flag<["-"], "M">, Alias<print_map>, HelpText<"Alias for --print-map">; +def: Flag<["-"], "r">, Alias<relocatable>, HelpText<"Alias for --relocatable">; +def: JoinedOrSeparate<["-"], "R">, Alias<rpath>, HelpText<"Alias for --rpath">; +def: JoinedOrSeparate<["-"], "T">, Alias<script>, HelpText<"Alias for --script">; +def: F<"Bshareable">, Alias<shared>, HelpText<"Alias for --shared">; +def: JoinedOrSeparate<["-"], "h">, Alias<soname>, HelpText<"Alias for --soname">; +def: Flag<["-"], "(">, Alias<start_group>, HelpText<"Alias for --start-group">; +def: Flag<["-"], "s">, Alias<strip_all>, HelpText<"Alias for --strip-all">; +def: Flag<["-"], "S">, Alias<strip_debug>, HelpText<"Alias for --strip-debug">; +def: Flag<["-"], "t">, Alias<trace>, HelpText<"Alias for --trace">; +def: JoinedOrSeparate<["-"], "y">, Alias<trace_symbol>, HelpText<"Alias for --trace-symbol">; +def: Separate<["-", "--"], "Ttext-segment">, Alias<Ttext>, HelpText<"Alias for --Ttext">; +def: Joined<["-", "--"], "Ttext-segment=">, Alias<Ttext>, HelpText<"Alias for --Ttext">; +def: JoinedOrSeparate<["-"], "u">, Alias<undefined>, HelpText<"Alias for --undefined">; +def: Flag<["-"], "V">, Alias<version>, HelpText<"Alias for --version">; // LTO-related options. def lto_aa_pipeline: J<"lto-aa-pipeline=">, HelpText<"AA pipeline to run during LTO. Used in conjunction with -lto-newpm-passes">; +def lto_debug_pass_manager: F<"lto-debug-pass-manager">, + HelpText<"Debug new pass manager">; +def lto_new_pass_manager: F<"lto-new-pass-manager">, + HelpText<"Use new pass manager">; def lto_newpm_passes: J<"lto-newpm-passes=">, HelpText<"Passes to run during LTO">; +def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, + HelpText<"Optimization level for LTO">; def lto_partitions: J<"lto-partitions=">, HelpText<"Number of LTO codegen partitions">; +def lto_sample_profile: J<"lto-sample-profile=">, + HelpText<"Sample profile file path">; def disable_verify: F<"disable-verify">; -def mllvm: S<"mllvm">; +defm mllvm: Eq<"mllvm", "Additional arguments to forward to LLVM's option processing">; def opt_remarks_filename: Separate<["--"], "opt-remarks-filename">, HelpText<"YAML output file for optimization remarks">; def opt_remarks_with_hotness: Flag<["--"], "opt-remarks-with-hotness">, - HelpText<"Include hotness informations in the optimization remarks file">; -defm plugin_opt: Eq<"plugin-opt">, - HelpText<"specifies LTO options for compatibility with GNU linkers">; + HelpText<"Include hotness information in the optimization remarks file">; +defm plugin_opt: Eq<"plugin-opt", "specifies LTO options for compatibility with GNU linkers">; def save_temps: F<"save-temps">; def thinlto_cache_dir: J<"thinlto-cache-dir=">, HelpText<"Path to ThinLTO cached object file directory">; -def thinlto_cache_policy: S<"thinlto-cache-policy">, - HelpText<"Pruning policy for the ThinLTO cache">; +defm thinlto_cache_policy: Eq<"thinlto-cache-policy", "Pruning policy for the ThinLTO cache">; def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; +def: J<"plugin-opt=O">, Alias<lto_O>, HelpText<"Alias for -lto-O">; +def: F<"plugin-opt=debug-pass-manager">, + Alias<lto_debug_pass_manager>, HelpText<"Alias for -lto-debug-pass-manager">; +def: F<"plugin-opt=disable-verify">, Alias<disable_verify>, HelpText<"Alias for -disable-verify">; +def plugin_opt_dwo_dir_eq: J<"plugin-opt=dwo_dir=">, + HelpText<"Directory to store .dwo files when LTO and debug fission are used">; +def: J<"plugin-opt=jobs=">, Alias<thinlto_jobs>, HelpText<"Alias for -thinlto-jobs">; +def: J<"plugin-opt=lto-partitions=">, Alias<lto_partitions>, HelpText<"Alias for -lto-partitions">; +def plugin_opt_mcpu_eq: J<"plugin-opt=mcpu=">; +def: F<"plugin-opt=new-pass-manager">, + Alias<lto_new_pass_manager>, HelpText<"Alias for -lto-new-pass-manager">; +def plugin_opt_obj_path_eq: J<"plugin-opt=obj-path=">; +def: J<"plugin-opt=sample-profile=">, + Alias<lto_sample_profile>, HelpText<"Alias for -lto-sample-profile">; +def: F<"plugin-opt=save-temps">, Alias<save_temps>, HelpText<"Alias for -save-temps">; +def plugin_opt_thinlto_emit_imports_files: F<"plugin-opt=thinlto-emit-imports-files">; +def plugin_opt_thinlto_index_only: F<"plugin-opt=thinlto-index-only">; +def plugin_opt_thinlto_index_only_eq: J<"plugin-opt=thinlto-index-only=">; +def plugin_opt_thinlto_object_suffix_replace_eq: J<"plugin-opt=thinlto-object-suffix-replace=">; +def plugin_opt_thinlto_prefix_replace_eq: J<"plugin-opt=thinlto-prefix-replace=">; + // Ignore LTO plugin-related options. // clang -flto passes -plugin and -plugin-opt to the linker. This is required // for ld.gold and ld.bfd to get LTO working. But it's not for lld which doesn't @@ -407,31 +458,38 @@ def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; // just ignore the option on lld side as it's easier. In fact, the linker could // be called 'ld' and understanding which linker is used would require parsing of // --version output. -def plugin: S<"plugin">; -def plugin_eq: J<"plugin=">; +defm plugin: Eq<"plugin", "Ignored for compatibility with GNU linkers">; + +def plugin_opt_fresolution_eq: J<"plugin-opt=-fresolution=">; +def plugin_opt_pass_through_eq: J<"plugin-opt=-pass-through=">; +def plugin_opt_thinlto: J<"plugin-opt=thinlto">; +def plugin_opt_slash: J<"plugin-opt=/">; // Options listed below are silently ignored for now for compatibility. -def allow_shlib_undefined: F<"allow-shlib-undefined">; -def cref: F<"cref">; -def detect_odr_violations: F<"detect-odr-violations">; -def g: Flag<["-"], "g">; -def long_plt: F<"long-plt">; -def no_add_needed: F<"no-add-needed">; -def no_allow_shlib_undefined: F<"no-allow-shlib-undefined">; -def no_copy_dt_needed_entries: F<"no-copy-dt-needed-entries">; -def no_ctors_in_init_array: F<"no-ctors-in-init-array">; -def no_keep_memory: F<"no-keep-memory">; -def no_mmap_output_file: F<"no-mmap-output-file">; -def no_warn_common: F<"no-warn-common">; -def no_warn_mismatch: F<"no-warn-mismatch">; -def rpath_link: S<"rpath-link">; -def rpath_link_eq: J<"rpath-link=">; -def sort_common: F<"sort-common">; -def stats: F<"stats">; -def warn_execstack: F<"warn-execstack">; -def warn_once: F<"warn-once">; -def warn_shared_textrel: F<"warn-shared-textrel">; -def EB : F<"EB">; -def EL : F<"EL">; -def G: JoinedOrSeparate<["-"], "G">; -def Qy : F<"Qy">; +def: F<"allow-shlib-undefined">; +def: F<"detect-odr-violations">; +def: Flag<["-"], "g">; +def: F<"long-plt">; +def: F<"no-add-needed">; +def: F<"no-allow-shlib-undefined">; +def: F<"no-copy-dt-needed-entries">; +def: F<"no-ctors-in-init-array">; +def: F<"no-keep-memory">; +def: F<"no-mmap-output-file">; +def: F<"no-warn-mismatch">; +def: Separate<["--", "-"], "rpath-link">; +def: J<"rpath-link=">; +def: F<"sort-common">; +def: F<"stats">; +def: F<"warn-execstack">; +def: F<"warn-once">; +def: F<"warn-shared-textrel">; +def: F<"EB">; +def: F<"EL">; +def: JoinedOrSeparate<["-"], "G">; +def: F<"Qy">; + +// Hidden option used for testing MIPS multi-GOT implementation. +defm mips_got_size: + Eq<"mips-got-size", "Max size of a single MIPS GOT. 0x10000 by default.">, + Flags<[HelpHidden]>; diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index f0677f7e1ca5..8253b18b486c 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -10,11 +10,11 @@ #include "OutputSections.h" #include "Config.h" #include "LinkerScript.h" -#include "Strings.h" #include "SymbolTable.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Support/Compression.h" @@ -25,15 +25,12 @@ using namespace llvm; using namespace llvm::dwarf; using namespace llvm::object; -using namespace llvm::support::endian; using namespace llvm::ELF; using namespace lld; using namespace lld::elf; uint8_t Out::First; -OutputSection *Out::Opd; -uint8_t *Out::OpdBuf; PhdrEntry *Out::TlsPhdr; OutputSection *Out::DebugInfo; OutputSection *Out::ElfHeader; @@ -45,7 +42,9 @@ OutputSection *Out::FiniArray; std::vector<OutputSection *> elf::OutputSections; uint32_t OutputSection::getPhdrFlags() const { - uint32_t Ret = PF_R; + uint32_t Ret = 0; + if (Config->EMachine != EM_ARM || !(Flags & SHF_ARM_PURECODE)) + Ret |= PF_R; if (Flags & SHF_WRITE) Ret |= PF_W; if (Flags & SHF_EXECINSTR) @@ -70,9 +69,7 @@ void OutputSection::writeHeaderTo(typename ELFT::Shdr *Shdr) { OutputSection::OutputSection(StringRef Name, uint32_t Type, uint64_t Flags) : BaseCommand(OutputSectionKind), SectionBase(Output, Name, Flags, /*Entsize*/ 0, /*Alignment*/ 1, Type, - /*Info*/ 0, - /*Link*/ 0), - SectionIndex(INT_MAX) { + /*Info*/ 0, /*Link*/ 0) { Live = false; } @@ -91,13 +88,15 @@ static bool canMergeToProgbits(unsigned Type) { void OutputSection::addSection(InputSection *IS) { if (!Live) { // If IS is the first section to be added to this section, - // initialize Type and Entsize from IS. + // initialize Type, Entsize and flags from IS. Live = true; Type = IS->Type; Entsize = IS->Entsize; + Flags = IS->Flags; } else { // Otherwise, check if new type or flags are compatible with existing ones. - if ((Flags & (SHF_ALLOC | SHF_TLS)) != (IS->Flags & (SHF_ALLOC | SHF_TLS))) + unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER; + if ((Flags & Mask) != (IS->Flags & Mask)) error("incompatible section flags for " + Name + "\n>>> " + toString(IS) + ": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name + ": 0x" + utohexstr(Flags)); @@ -114,9 +113,14 @@ void OutputSection::addSection(InputSection *IS) { } IS->Parent = this; - Flags |= IS->Flags; + uint64_t AndMask = + Config->EMachine == EM_ARM ? (uint64_t)SHF_ARM_PURECODE : 0; + uint64_t OrMask = ~AndMask; + uint64_t AndFlags = (Flags & IS->Flags) & AndMask; + uint64_t OrFlags = (Flags | IS->Flags) & OrMask; + Flags = AndFlags | OrFlags; + Alignment = std::max(Alignment, IS->Alignment); - IS->OutSecOff = Size++; // If this section contains a table of fixed-size entries, sh_entsize // holds the element size. If it contains elements of different size we @@ -134,8 +138,8 @@ void OutputSection::addSection(InputSection *IS) { } } -void elf::sortByOrder(MutableArrayRef<InputSection *> In, - std::function<int(InputSectionBase *S)> Order) { +static void sortByOrder(MutableArrayRef<InputSection *> In, + llvm::function_ref<int(InputSectionBase *S)> Order) { typedef std::pair<int, InputSection *> Pair; auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; @@ -158,11 +162,11 @@ bool OutputSection::classof(const BaseCommand *C) { return C->Kind == OutputSectionKind; } -void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) { +void OutputSection::sort(llvm::function_ref<int(InputSectionBase *S)> Order) { assert(Live); - assert(SectionCommands.size() == 1); - sortByOrder(cast<InputSectionDescription>(SectionCommands[0])->Sections, - Order); + for (BaseCommand *B : SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) + sortByOrder(ISD->Sections, Order); } // Fill [Buf, Buf + Size) with Filler. @@ -183,15 +187,6 @@ template <class ELFT> void OutputSection::maybeCompress() { !Name.startswith(".debug_")) return; - // Calculate the section offsets and size pre-compression. - Size = 0; - for (BaseCommand *Cmd : SectionCommands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) - for (InputSection *IS : ISD->Sections) { - IS->OutSecOff = alignTo(Size, IS->Alignment); - this->Size = IS->OutSecOff + IS->getSize(); - } - // Create a section header. ZDebugHeader.resize(sizeof(Elf_Chdr)); auto *Hdr = reinterpret_cast<Elf_Chdr *>(ZDebugHeader.data()); @@ -214,11 +209,11 @@ static void writeInt(uint8_t *Buf, uint64_t Data, uint64_t Size) { if (Size == 1) *Buf = Data; else if (Size == 2) - write16(Buf, Data, Config->Endianness); + write16(Buf, Data); else if (Size == 4) - write32(Buf, Data, Config->Endianness); + write32(Buf, Data); else if (Size == 8) - write64(Buf, Data, Config->Endianness); + write64(Buf, Data); else llvm_unreachable("unsupported Size argument"); } @@ -240,12 +235,7 @@ template <class ELFT> void OutputSection::writeTo(uint8_t *Buf) { } // Write leading padding. - std::vector<InputSection *> Sections; - for (BaseCommand *Cmd : SectionCommands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) - for (InputSection *IS : ISD->Sections) - if (IS->Live) - Sections.push_back(IS); + std::vector<InputSection *> Sections = getInputSections(this); uint32_t Filler = getFiller(); if (Filler) fill(Buf, Sections.empty() ? Size : Sections[0]->OutSecOff, Filler); @@ -290,17 +280,13 @@ static void finalizeShtGroup(OutputSection *OS, } template <class ELFT> void OutputSection::finalize() { - InputSection *First = nullptr; - for (BaseCommand *Base : SectionCommands) { - if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) { - if (ISD->Sections.empty()) - continue; - if (First == nullptr) - First = ISD->Sections.front(); - } - if (isa<ByteCommand>(Base) && Type == SHT_NOBITS) - Type = SHT_PROGBITS; - } + if (Type == SHT_NOBITS) + for (BaseCommand *Base : SectionCommands) + if (isa<ByteCommand>(Base)) + Type = SHT_PROGBITS; + + std::vector<InputSection *> V = getInputSections(this); + InputSection *First = V.empty() ? nullptr : V[0]; if (Flags & SHF_LINK_ORDER) { // We must preserve the link order dependency of sections with the @@ -376,8 +362,6 @@ static bool compCtors(const InputSection *A, const InputSection *B) { assert(Y.startswith(".ctors") || Y.startswith(".dtors")); X = X.substr(6); Y = Y.substr(6); - if (X.empty() && Y.empty()) - return false; return X < Y; } @@ -403,6 +387,14 @@ int elf::getPriority(StringRef S) { return V; } +std::vector<InputSection *> elf::getInputSections(OutputSection *OS) { + std::vector<InputSection *> Ret; + for (BaseCommand *Base : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + Ret.insert(Ret.end(), ISD->Sections.begin(), ISD->Sections.end()); + return Ret; +} + // Sorts input sections by section name suffixes, so that .foo.N comes // before .foo.M if N < M. Used to sort .{init,fini}_array.N sections. // We want to keep the original order if the priorities are the same diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index b2845773e9af..efb6aabe9743 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -14,7 +14,6 @@ #include "InputSection.h" #include "LinkerScript.h" #include "Relocations.h" - #include "lld/Common/LLVM.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELF.h" @@ -49,10 +48,10 @@ public: static bool classof(const BaseCommand *C); - uint64_t getLMA() const { return Addr + LMAOffset; } + uint64_t getLMA() const { return PtLoad ? Addr + PtLoad->LMAOffset : Addr; } template <typename ELFT> void writeHeaderTo(typename ELFT::Shdr *SHdr); - unsigned SectionIndex; + uint32_t SectionIndex = UINT32_MAX; unsigned SortRank; uint32_t getPhdrFlags() const; @@ -78,7 +77,6 @@ public: // The following fields correspond to Elf_Shdr members. uint64_t Offset = 0; - uint64_t LMAOffset = 0; uint64_t Addr = 0; uint32_t ShName = 0; @@ -89,6 +87,7 @@ public: // The following members are normally only used in linker scripts. MemoryRegion *MemRegion = nullptr; + MemoryRegion *LMARegion = nullptr; Expr AddrExpr; Expr AlignExpr; Expr LMAExpr; @@ -99,13 +98,17 @@ public: ConstraintKind Constraint = ConstraintKind::NoConstraint; std::string Location; std::string MemoryRegionName; + std::string LMARegionName; + bool NonAlloc = false; bool Noload = false; + bool ExpressionsUseSymbols = false; + bool InOverlay = false; template <class ELFT> void finalize(); template <class ELFT> void writeTo(uint8_t *Buf); template <class ELFT> void maybeCompress(); - void sort(std::function<int(InputSectionBase *S)> Order); + void sort(llvm::function_ref<int(InputSectionBase *S)> Order); void sortInitFini(); void sortCtorsDtors(); @@ -119,13 +122,13 @@ private: int getPriority(StringRef S); +std::vector<InputSection *> getInputSections(OutputSection* OS); + // All output sections that are handled by the linker specially are // globally accessible. Writer initializes them, so don't use them // until Writer is initialized. struct Out { static uint8_t First; - static OutputSection *Opd; - static uint8_t *OpdBuf; static PhdrEntry *TlsPhdr; static OutputSection *DebugInfo; static OutputSection *ElfHeader; @@ -142,8 +145,6 @@ namespace lld { namespace elf { uint64_t getHeaderSize(); -void sortByOrder(llvm::MutableArrayRef<InputSection *> In, - std::function<int(InputSectionBase *S)> Order); extern std::vector<OutputSection *> OutputSections; } // namespace elf diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index 1aa0957b1d01..467219ad0542 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -45,14 +45,14 @@ #include "Config.h" #include "LinkerScript.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "Thunks.h" #include "lld/Common/Memory.h" - +#include "lld/Common/Strings.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Support/Endian.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -80,55 +80,22 @@ static std::string getLocation(InputSectionBase &S, const Symbol &Sym, return Msg + S.getObjMsg(Off); } -// This is a MIPS-specific rule. -// -// In case of MIPS GP-relative relocations always resolve to a definition -// in a regular input file, ignoring the one-definition rule. So we, -// for example, should not attempt to create a dynamic relocation even -// if the target symbol is preemptible. There are two two MIPS GP-relative -// relocations R_MIPS_GPREL16 and R_MIPS_GPREL32. But only R_MIPS_GPREL16 -// can be against a preemptible symbol. -// -// To get MIPS relocation type we apply 0xff mask. In case of O32 ABI all -// relocation types occupy eight bit. In case of N64 ABI we extract first -// relocation from 3-in-1 packet because only the first relocation can -// be against a real symbol. -static bool isMipsGprel(RelType Type) { - if (Config->EMachine != EM_MIPS) - return false; - Type &= 0xff; - return Type == R_MIPS_GPREL16 || Type == R_MICROMIPS_GPREL16 || - Type == R_MICROMIPS_GPREL7_S2; -} - // This function is similar to the `handleTlsRelocation`. MIPS does not // support any relaxations for TLS relocations so by factoring out MIPS // handling in to the separate function we can simplify the code and do not // pollute other `handleTlsRelocation` by MIPS `ifs` statements. // Mips has a custom MipsGotSection that handles the writing of GOT entries // without dynamic relocations. -template <class ELFT> static unsigned handleMipsTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, uint64_t Offset, int64_t Addend, RelExpr Expr) { if (Expr == R_MIPS_TLSLD) { - if (InX::MipsGot->addTlsIndex() && Config->Pic) - InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::MipsGot, - InX::MipsGot->getTlsIndexOff(), false, nullptr, - 0}); + InX::MipsGot->addTlsIndex(*C.File); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } - if (Expr == R_MIPS_TLSGD) { - if (InX::MipsGot->addDynTlsEntry(Sym) && Sym.IsPreemptible) { - uint64_t Off = InX::MipsGot->getGlobalDynOffset(Sym); - InX::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, InX::MipsGot, Off, false, &Sym, 0}); - if (Sym.IsPreemptible) - InX::RelaDyn->addReloc({Target->TlsOffsetRel, InX::MipsGot, - Off + Config->Wordsize, false, &Sym, 0}); - } + InX::MipsGot->addDynTlsEntry(*C.File, Sym); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } @@ -161,7 +128,7 @@ static unsigned handleARMTlsRelocation(RelType Type, Symbol &Sym, auto AddTlsReloc = [&](uint64_t Off, RelType Type, Symbol *Dest, bool Dyn) { if (Dyn) - InX::RelaDyn->addReloc({Type, InX::Got, Off, false, Dest, 0}); + InX::RelaDyn->addReloc(Type, InX::Got, Off, Dest); else InX::Got->Relocations.push_back({R_ABS, Type, Off, 0, Dest}); }; @@ -207,7 +174,7 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, if (Config->EMachine == EM_ARM) return handleARMTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); if (Config->EMachine == EM_MIPS) - return handleMipsTlsRelocation<ELFT>(Type, Sym, C, Offset, Addend, Expr); + return handleMipsTlsRelocation(Type, Sym, C, Offset, Addend, Expr); if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL>(Expr) && Config->Shared) { @@ -221,40 +188,62 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, return 1; } - if (isRelExprOneOf<R_TLSLD_PC, R_TLSLD>(Expr)) { + if (isRelExprOneOf<R_TLSLD_GOT, R_TLSLD_GOT_FROM_END, R_TLSLD_PC, + R_TLSLD_HINT>(Expr)) { // Local-Dynamic relocs can be relaxed to Local-Exec. if (!Config->Shared) { C.Relocations.push_back( - {R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); - return 2; + {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, + Offset, Addend, &Sym}); + return Target->TlsGdRelaxSkip; } + if (Expr == R_TLSLD_HINT) + return 1; if (InX::Got->addTlsIndex()) - InX::RelaDyn->addReloc({Target->TlsModuleIndexRel, InX::Got, - InX::Got->getTlsIndexOff(), false, nullptr, 0}); + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, + InX::Got->getTlsIndexOff(), nullptr); C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); return 1; } // Local-Dynamic relocs can be relaxed to Local-Exec. - if (isRelExprOneOf<R_ABS, R_TLSLD, R_TLSLD_PC>(Expr) && !Config->Shared) { - C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); + if (Expr == R_ABS && !Config->Shared) { + C.Relocations.push_back( + {Target->adjustRelaxExpr(Type, nullptr, R_RELAX_TLS_LD_TO_LE), Type, + Offset, Addend, &Sym}); return 1; } - if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD, - R_TLSGD_PC>(Expr)) { + // Local-Dynamic sequence where offset of tls variable relative to dynamic + // thread pointer is stored in the got. + if (Expr == R_TLSLD_GOT_OFF) { + // Local-Dynamic relocs can be relaxed to local-exec + if (!Config->Shared) { + C.Relocations.push_back({R_RELAX_TLS_LD_TO_LE, Type, Offset, Addend, &Sym}); + return 1; + } + if (!Sym.isInGot()) { + InX::Got->addEntry(Sym); + uint64_t Off = Sym.getGotOffset(); + InX::Got->Relocations.push_back({R_ABS, Target->TlsOffsetRel, Off, 0, &Sym}); + } + C.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return 1; + } + + if (isRelExprOneOf<R_TLSDESC, R_TLSDESC_PAGE, R_TLSDESC_CALL, R_TLSGD_GOT, + R_TLSGD_GOT_FROM_END, R_TLSGD_PC>(Expr)) { if (Config->Shared) { if (InX::Got->addDynTlsEntry(Sym)) { uint64_t Off = InX::Got->getGlobalDynOffset(Sym); - InX::RelaDyn->addReloc( - {Target->TlsModuleIndexRel, InX::Got, Off, false, &Sym, 0}); + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, InX::Got, Off, &Sym); // If the symbol is preemptible we need the dynamic linker to write // the offset too. uint64_t OffsetOff = Off + Config->Wordsize; if (Sym.IsPreemptible) - InX::RelaDyn->addReloc( - {Target->TlsOffsetRel, InX::Got, OffsetOff, false, &Sym, 0}); + InX::RelaDyn->addReloc(Target->TlsOffsetRel, InX::Got, OffsetOff, + &Sym); else InX::Got->Relocations.push_back( {R_ABS, Target->TlsOffsetRel, OffsetOff, 0, &Sym}); @@ -271,8 +260,8 @@ handleTlsRelocation(RelType Type, Symbol &Sym, InputSectionBase &C, Offset, Addend, &Sym}); if (!Sym.isInGot()) { InX::Got->addEntry(Sym); - InX::RelaDyn->addReloc( - {Target->TlsGotRel, InX::Got, Sym.getGotOffset(), false, &Sym, 0}); + InX::RelaDyn->addReloc(Target->TlsGotRel, InX::Got, Sym.getGotOffset(), + &Sym); } } else { C.Relocations.push_back( @@ -336,7 +325,7 @@ static bool isAbsoluteValue(const Symbol &Sym) { // Returns true if Expr refers a PLT entry. static bool needsPlt(RelExpr Expr) { - return isRelExprOneOf<R_PLT_PC, R_PPC_PLT_OPD, R_PLT, R_PLT_PAGE_PC>(Expr); + return isRelExprOneOf<R_PLT_PC, R_PPC_CALL_PLT, R_PLT, R_PLT_PAGE_PC>(Expr); } // Returns true if Expr refers a GOT entry. Note that this function @@ -352,7 +341,8 @@ static bool needsGot(RelExpr Expr) { // file (PC, or GOT for example). static bool isRelExpr(RelExpr Expr) { return isRelExprOneOf<R_PC, R_GOTREL, R_GOTREL_FROM_END, R_MIPS_GOTREL, - R_PAGE_PC, R_RELAX_GOT_PC>(Expr); + R_PPC_CALL, R_PPC_CALL_PLT, R_PAGE_PC, + R_RELAX_GOT_PC>(Expr); } // Returns true if a given relocation can be computed at link-time. @@ -367,11 +357,13 @@ static bool isRelExpr(RelExpr Expr) { static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, InputSectionBase &S, uint64_t RelOff) { // These expressions always compute a constant - if (isRelExprOneOf<R_SIZE, R_GOT_FROM_END, R_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, - R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, - R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, - R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_PC, R_TLSGD, - R_PPC_PLT_OPD, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT>(E)) + if (isRelExprOneOf< + R_GOT_FROM_END, R_GOT_OFF, R_TLSLD_GOT_OFF, R_MIPS_GOT_LOCAL_PAGE, + R_MIPS_GOTREL, R_MIPS_GOT_OFF, R_MIPS_GOT_OFF32, R_MIPS_GOT_GP_PC, + R_MIPS_TLSGD, R_GOT_PAGE_PC, R_GOT_PC, R_GOTONLY_PC, + R_GOTONLY_PC_FROM_END, R_PLT_PC, R_TLSGD_GOT, R_TLSGD_GOT_FROM_END, + R_TLSGD_PC, R_PPC_CALL_PLT, R_TLSDESC_CALL, R_TLSDESC_PAGE, R_HINT, + R_TLSLD_HINT>(E)) return true; // These never do, except if the entire file is position dependent or if @@ -384,6 +376,10 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, if (!Config->Pic) return true; + // The size of a non preemptible symbol is a constant. + if (E == R_SIZE) + return true; + // For the target and the relocation, we want to know if they are // absolute or relative. bool AbsVal = isAbsoluteValue(Sym); @@ -413,39 +409,45 @@ static bool isStaticLinkTimeConstant(RelExpr E, RelType Type, const Symbol &Sym, } static RelExpr toPlt(RelExpr Expr) { - if (Expr == R_PPC_OPD) - return R_PPC_PLT_OPD; - if (Expr == R_PC) + switch (Expr) { + case R_PPC_CALL: + return R_PPC_CALL_PLT; + case R_PC: return R_PLT_PC; - if (Expr == R_PAGE_PC) + case R_PAGE_PC: return R_PLT_PAGE_PC; - if (Expr == R_ABS) + case R_ABS: return R_PLT; - return Expr; + default: + return Expr; + } } static RelExpr fromPlt(RelExpr Expr) { // We decided not to use a plt. Optimize a reference to the plt to a // reference to the symbol itself. - if (Expr == R_PLT_PC) + switch (Expr) { + case R_PLT_PC: return R_PC; - if (Expr == R_PPC_PLT_OPD) - return R_PPC_OPD; - if (Expr == R_PLT) + case R_PPC_CALL_PLT: + return R_PPC_CALL; + case R_PLT: return R_ABS; - return Expr; + default: + return Expr; + } } // Returns true if a given shared symbol is in a read-only segment in a DSO. -template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { +template <class ELFT> static bool isReadOnly(SharedSymbol &SS) { typedef typename ELFT::Phdr Elf_Phdr; // Determine if the symbol is read-only by scanning the DSO's program headers. - const SharedFile<ELFT> &File = SS->getFile<ELFT>(); + const SharedFile<ELFT> &File = SS.getFile<ELFT>(); for (const Elf_Phdr &Phdr : check(File.getObj().program_headers())) if ((Phdr.p_type == ELF::PT_LOAD || Phdr.p_type == ELF::PT_GNU_RELRO) && - !(Phdr.p_flags & ELF::PF_W) && SS->Value >= Phdr.p_vaddr && - SS->Value < Phdr.p_vaddr + Phdr.p_memsz) + !(Phdr.p_flags & ELF::PF_W) && SS.Value >= Phdr.p_vaddr && + SS.Value < Phdr.p_vaddr + Phdr.p_memsz) return true; return false; } @@ -454,26 +456,45 @@ template <class ELFT> static bool isReadOnly(SharedSymbol *SS) { // // If two or more symbols are at the same offset, and at least one of // them are copied by a copy relocation, all of them need to be copied. -// Otherwise, they would refer different places at runtime. +// Otherwise, they would refer to different places at runtime. template <class ELFT> -static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { +static SmallSet<SharedSymbol *, 4> getSymbolsAt(SharedSymbol &SS) { typedef typename ELFT::Sym Elf_Sym; - SharedFile<ELFT> &File = SS->getFile<ELFT>(); + SharedFile<ELFT> &File = SS.getFile<ELFT>(); - std::vector<SharedSymbol *> Ret; + SmallSet<SharedSymbol *, 4> Ret; for (const Elf_Sym &S : File.getGlobalELFSyms()) { if (S.st_shndx == SHN_UNDEF || S.st_shndx == SHN_ABS || - S.st_value != SS->Value) + S.st_value != SS.Value) continue; StringRef Name = check(S.getName(File.getStringTable())); Symbol *Sym = Symtab->find(Name); if (auto *Alias = dyn_cast_or_null<SharedSymbol>(Sym)) - Ret.push_back(Alias); + Ret.insert(Alias); } return Ret; } +// When a symbol is copy relocated or we create a canonical plt entry, it is +// effectively a defined symbol. In the case of copy relocation the symbol is +// in .bss and in the case of a canonical plt entry it is in .plt. This function +// replaces the existing symbol with a Defined pointing to the appropriate +// location. +static void replaceWithDefined(Symbol &Sym, SectionBase *Sec, uint64_t Value, + uint64_t Size) { + Symbol Old = Sym; + replaceSymbol<Defined>(&Sym, Sym.File, Sym.getName(), Sym.Binding, + Sym.StOther, Sym.Type, Value, Size, Sec); + Sym.PltIndex = Old.PltIndex; + Sym.GotIndex = Old.GotIndex; + Sym.VerdefIndex = Old.VerdefIndex; + Sym.IsPreemptible = true; + Sym.ExportDynamic = true; + Sym.IsUsedInRegularObj = true; + Sym.Used = true; +} + // Reserve space in .bss or .bss.rel.ro for copy relocation. // // The copy relocation is pretty much a hack. If you use a copy relocation @@ -516,17 +537,17 @@ static std::vector<SharedSymbol *> getSymbolsAt(SharedSymbol *SS) { // to the variable in .bss. This kind of issue is sometimes very hard to // debug. What's a solution? Instead of exporting a varaible V from a DSO, // define an accessor getV(). -template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) { +template <class ELFT> static void addCopyRelSymbol(SharedSymbol &SS) { // Copy relocation against zero-sized symbol doesn't make sense. - uint64_t SymSize = SS->getSize(); - if (SymSize == 0) - fatal("cannot create a copy relocation for symbol " + toString(*SS)); + uint64_t SymSize = SS.getSize(); + if (SymSize == 0 || SS.Alignment == 0) + fatal("cannot create a copy relocation for symbol " + toString(SS)); // See if this symbol is in a read-only segment. If so, preserve the symbol's // memory protection by reserving space in the .bss.rel.ro section. bool IsReadOnly = isReadOnly<ELFT>(SS); BssSection *Sec = make<BssSection>(IsReadOnly ? ".bss.rel.ro" : ".bss", - SymSize, SS->Alignment); + SymSize, SS.Alignment); if (IsReadOnly) InX::BssRelRo->getParent()->addSection(Sec); else @@ -535,125 +556,10 @@ template <class ELFT> static void addCopyRelSymbol(SharedSymbol *SS) { // Look through the DSO's dynamic symbol table for aliases and create a // dynamic symbol for each one. This causes the copy relocation to correctly // interpose any aliases. - for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) { - Sym->CopyRelSec = Sec; - Sym->IsPreemptible = false; - Sym->IsUsedInRegularObj = true; - Sym->Used = true; - } - - InX::RelaDyn->addReloc({Target->CopyRel, Sec, 0, false, SS, 0}); -} - -static void errorOrWarn(const Twine &Msg) { - if (!Config->NoinhibitExec) - error(Msg); - else - warn(Msg); -} - -// Returns PLT relocation expression. -// -// This handles a non PIC program call to function in a shared library. In -// an ideal world, we could just report an error saying the relocation can -// overflow at runtime. In the real world with glibc, crt1.o has a -// R_X86_64_PC32 pointing to libc.so. -// -// The general idea on how to handle such cases is to create a PLT entry and -// use that as the function value. -// -// For the static linking part, we just return a plt expr and everything -// else will use the the PLT entry as the address. -// -// The remaining problem is making sure pointer equality still works. We -// need the help of the dynamic linker for that. We let it know that we have -// a direct reference to a so symbol by creating an undefined symbol with a -// non zero st_value. Seeing that, the dynamic linker resolves the symbol to -// the value of the symbol we created. This is true even for got entries, so -// pointer equality is maintained. To avoid an infinite loop, the only entry -// that points to the real function is a dedicated got entry used by the -// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, -// R_386_JMP_SLOT, etc). -static RelExpr getPltExpr(Symbol &Sym, RelExpr Expr, bool &IsConstant) { - Sym.NeedsPltAddr = true; - Sym.IsPreemptible = false; - IsConstant = true; - return toPlt(Expr); -} - -// This modifies the expression if we can use a copy relocation or point the -// symbol to the PLT. -template <class ELFT> -static RelExpr adjustExpr(Symbol &Sym, RelExpr Expr, RelType Type, - InputSectionBase &S, uint64_t RelOff, - bool &IsConstant) { - // If a relocation can be applied at link-time, we don't need to - // create a dynamic relocation in the first place. - if (IsConstant) - return Expr; - - // If the relocation is to a weak undef, and we are producing - // executable, give up on it and produce a non preemptible 0. - if (!Config->Shared && Sym.isUndefWeak()) { - Sym.IsPreemptible = false; - IsConstant = true; - return Expr; - } - - // We can create any dynamic relocation supported by the dynamic linker if a - // section is writable or we are passed -z notext. - bool CanWrite = (S.Flags & SHF_WRITE) || !Config->ZText; - if (CanWrite && Target->isPicRel(Type)) - return Expr; - - // If we got here we know that this relocation would require the dynamic - // linker to write a value to read only memory or use an unsupported - // relocation. - - // We can hack around it if we are producing an executable and - // the refered symbol can be preemepted to refer to the executable. - if (!CanWrite && (Config->Shared || (Config->Pic && !isRelExpr(Expr)))) { - error( - "can't create dynamic relocation " + toString(Type) + " against " + - (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + - " in readonly segment; recompile object files with -fPIC" + - getLocation(S, Sym, RelOff)); - return Expr; - } - - // Copy relocations are only possible if we are creating an executable and the - // symbol is shared. - if (!Sym.isShared() || Config->Shared) - return Expr; - - if (Sym.getVisibility() != STV_DEFAULT) { - error("cannot preempt symbol: " + toString(Sym) + - getLocation(S, Sym, RelOff)); - return Expr; - } - - if (Sym.isObject()) { - // Produce a copy relocation. - auto *B = dyn_cast<SharedSymbol>(&Sym); - if (B && !B->CopyRelSec) { - if (Config->ZNocopyreloc) - error("unresolvable relocation " + toString(Type) + - " against symbol '" + toString(*B) + - "'; recompile with -fPIC or remove '-z nocopyreloc'" + - getLocation(S, Sym, RelOff)); - - addCopyRelSymbol<ELFT>(B); - } - IsConstant = true; - return Expr; - } - - if (Sym.isFunc()) - return getPltExpr(Sym, Expr, IsConstant); + for (SharedSymbol *Sym : getSymbolsAt<ELFT>(SS)) + replaceWithDefined(*Sym, Sec, 0, Sym->Size); - errorOrWarn("symbol '" + toString(Sym) + "' defined in " + - toString(Sym.File) + " has no type"); - return Expr; + InX::RelaDyn->addReloc(Target->CopyRel, Sec, 0, &SS); } // MIPS has an odd notion of "paired" relocations to calculate addends. @@ -728,7 +634,7 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, return false; bool CanBeExternal = - Sym.computeBinding() != STB_LOCAL && Sym.getVisibility() == STV_DEFAULT; + Sym.computeBinding() != STB_LOCAL && Sym.Visibility == STV_DEFAULT; if (Config->UnresolvedSymbols == UnresolvedPolicy::Ignore && CanBeExternal) return false; @@ -756,12 +662,12 @@ static bool maybeReportUndefined(Symbol &Sym, InputSectionBase &Sec, // this for the N32 ABI. Iterate over relocation with the same offset and put // theirs types into the single bit-set. template <class RelTy> static RelType getMipsN32RelType(RelTy *&Rel, RelTy *End) { - RelType Type = Rel->getType(Config->IsMips64EL); + RelType Type = 0; uint64_t Offset = Rel->r_offset; int N = 0; - while (Rel + 1 != End && (Rel + 1)->r_offset == Offset) - Type |= (++Rel)->getType(Config->IsMips64EL) << (8 * ++N); + while (Rel != End && Rel->r_offset == Offset) + Type |= (Rel++)->getType(Config->IsMips64EL) << (8 * N++); return Type; } @@ -811,16 +717,34 @@ private: }; } // namespace +static void addRelativeReloc(InputSectionBase *IS, uint64_t OffsetInSec, + Symbol *Sym, int64_t Addend, RelExpr Expr, + RelType Type) { + // Add a relative relocation. If RelrDyn section is enabled, and the + // relocation offset is guaranteed to be even, add the relocation to + // the RelrDyn section, otherwise add it to the RelaDyn section. + // RelrDyn sections don't support odd offsets. Also, RelrDyn sections + // don't store the addend values, so we must write it to the relocated + // address. + if (InX::RelrDyn && IS->Alignment >= 2 && OffsetInSec % 2 == 0) { + IS->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); + InX::RelrDyn->Relocs.push_back({IS, OffsetInSec}); + return; + } + InX::RelaDyn->addReloc(Target->RelativeRel, IS, OffsetInSec, Sym, Addend, + Expr, Type); +} + template <class ELFT, class GotPltSection> static void addPltEntry(PltSection *Plt, GotPltSection *GotPlt, - RelocationBaseSection *Rel, RelType Type, Symbol &Sym, - bool UseSymVA) { + RelocationBaseSection *Rel, RelType Type, Symbol &Sym) { Plt->addEntry<ELFT>(Sym); GotPlt->addEntry(Sym); - Rel->addReloc({Type, GotPlt, Sym.getGotPltOffset(), UseSymVA, &Sym, 0}); + Rel->addReloc( + {Type, GotPlt, Sym.getGotPltOffset(), !Sym.IsPreemptible, &Sym, 0}); } -template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { +template <class ELFT> static void addGotEntry(Symbol &Sym) { InX::Got->addEntry(Sym); RelExpr Expr = Sym.isTls() ? R_TLS : R_ABS; @@ -833,7 +757,8 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // add a static relocation to a Relocations vector so that // InputSection::relocate will do the work for us. We may be able // to just write a value now, but it is a TODO.) - bool IsLinkTimeConstant = !Preemptible && (!Config->Pic || isAbsolute(Sym)); + bool IsLinkTimeConstant = + !Sym.IsPreemptible && (!Config->Pic || isAbsolute(Sym)); if (IsLinkTimeConstant) { InX::Got->Relocations.push_back({Expr, Target->GotRel, Off, 0, &Sym}); return; @@ -841,23 +766,33 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // Otherwise, we emit a dynamic relocation to .rel[a].dyn so that // the GOT slot will be fixed at load-time. - RelType Type; - if (Sym.isTls()) - Type = Target->TlsGotRel; - else if (!Preemptible && Config->Pic && !isAbsolute(Sym)) - Type = Target->RelativeRel; - else - Type = Target->GotRel; - InX::RelaDyn->addReloc({Type, InX::Got, Off, !Preemptible, &Sym, 0}); + if (!Sym.isTls() && !Sym.IsPreemptible && Config->Pic && !isAbsolute(Sym)) { + addRelativeReloc(InX::Got, Off, &Sym, 0, R_ABS, Target->GotRel); + return; + } + InX::RelaDyn->addReloc(Sym.isTls() ? Target->TlsGotRel : Target->GotRel, + InX::Got, Off, &Sym, 0, + Sym.IsPreemptible ? R_ADDEND : R_ABS, Target->GotRel); +} - // REL type relocations don't have addend fields unlike RELAs, and - // their addends are stored to the section to which they are applied. - // So, store addends if we need to. - // - // This is ugly -- the difference between REL and RELA should be - // handled in a better way. It's a TODO. - if (!Config->IsRela && !Preemptible) - InX::Got->Relocations.push_back({R_ABS, Target->GotRel, Off, 0, &Sym}); +// Return true if we can define a symbol in the executable that +// contains the value/function of a symbol defined in a shared +// library. +static bool canDefineSymbolInExecutable(Symbol &Sym) { + // If the symbol has default visibility the symbol defined in the + // executable will preempt it. + // Note that we want the visibility of the shared symbol itself, not + // the visibility of the symbol in the output file we are producing. That is + // why we use Sym.StOther. + if ((Sym.StOther & 0x3) == STV_DEFAULT) + return true; + + // If we are allowed to break address equality of functions, defining + // a plt entry will allow the program to call the function in the + // .so, but the .so and the executable will no agree on the address + // of the function. Similar logic for objects. + return ((Sym.isFunc() && Config->IgnoreFunctionAddressEquality) || + (Sym.isObject() && Config->IgnoreDataAddressEquality)); } // The reason we have to do this early scan is as follows @@ -874,129 +809,23 @@ template <class ELFT> static void addGotEntry(Symbol &Sym, bool Preemptible) { // complicates things for the dynamic linker and means we would have to reserve // space for the extra PT_LOAD even if we end up not using it. template <class ELFT, class RelTy> -static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { - OffsetGetter GetOffset(Sec); - - // Not all relocations end up in Sec.Relocations, but a lot do. - Sec.Relocations.reserve(Rels.size()); - - for (auto I = Rels.begin(), End = Rels.end(); I != End; ++I) { - const RelTy &Rel = *I; - Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); - RelType Type = Rel.getType(Config->IsMips64EL); - - // Deal with MIPS oddity. - if (Config->MipsN32Abi) - Type = getMipsN32RelType(I, End); - - // Get an offset in an output section this relocation is applied to. - uint64_t Offset = GetOffset.get(Rel.r_offset); - if (Offset == uint64_t(-1)) - continue; - - // Skip if the target symbol is an erroneous undefined symbol. - if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) - continue; - - RelExpr Expr = - Target->getRelExpr(Type, Sym, Sec.Data.begin() + Rel.r_offset); - - // Ignore "hint" relocations because they are only markers for relaxation. - if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) - continue; - - // Handle yet another MIPS-ness. - if (isMipsGprel(Type)) { - int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); - Sec.Relocations.push_back({R_MIPS_GOTREL, Type, Offset, Addend, &Sym}); - continue; - } - - bool Preemptible = Sym.IsPreemptible; - - // Strenghten or relax a PLT access. - // - // GNU ifunc symbols must be accessed via PLT because their addresses - // are determined by runtime. - // - // On the other hand, if we know that a PLT entry will be resolved within - // the same ELF module, we can skip PLT access and directly jump to the - // destination function. For example, if we are linking a main exectuable, - // all dynamic symbols that can be resolved within the executable will - // actually be resolved that way at runtime, because the main exectuable - // is always at the beginning of a search list. We can leverage that fact. - if (Sym.isGnuIFunc()) - Expr = toPlt(Expr); - else if (!Preemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) - Expr = - Target->adjustRelaxExpr(Type, Sec.Data.data() + Rel.r_offset, Expr); - else if (!Preemptible) - Expr = fromPlt(Expr); - - bool IsConstant = - isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Rel.r_offset); - - Expr = adjustExpr<ELFT>(Sym, Expr, Type, Sec, Rel.r_offset, IsConstant); - if (errorCount()) - continue; - - // This relocation does not require got entry, but it is relative to got and - // needs it to be created. Here we request for that. - if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, - R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) - InX::Got->HasGotOffRel = true; - - // Read an addend. - int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); - - // Process some TLS relocations, including relaxing TLS relocations. - // Note that this function does not handle all TLS relocations. - if (unsigned Processed = - handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { - I += (Processed - 1); - continue; - } - - // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. - if (needsPlt(Expr) && !Sym.isInPlt()) { - if (Sym.isGnuIFunc() && !Preemptible) - addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, - Target->IRelativeRel, Sym, true); - else - addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, - Sym, !Preemptible); - } - - // Create a GOT slot if a relocation needs GOT. - if (needsGot(Expr)) { - if (Config->EMachine == EM_MIPS) { - // MIPS ABI has special rules to process GOT entries and doesn't - // require relocation entries for them. A special case is TLS - // relocations. In that case dynamic loader applies dynamic - // relocations to initialize TLS GOT entries. - // See "Global Offset Table" in Chapter 5 in the following document - // for detailed description: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - InX::MipsGot->addEntry(Sym, Addend, Expr); - if (Sym.isTls() && Sym.IsPreemptible) - InX::RelaDyn->addReloc({Target->TlsGotRel, InX::MipsGot, - Sym.getGotOffset(), false, &Sym, 0}); - } else if (!Sym.isInGot()) { - addGotEntry<ELFT>(Sym, Preemptible); - } - } - - if (!needsPlt(Expr) && !needsGot(Expr) && Sym.IsPreemptible) { - // We don't know anything about the finaly symbol. Just ask the dynamic - // linker to handle the relocation for us. - if (!Target->isPicRel(Type)) - errorOrWarn( - "relocation " + toString(Type) + - " cannot be used against shared object; recompile with -fPIC" + - getLocation(Sec, Sym, Offset)); +static void processRelocAux(InputSectionBase &Sec, RelExpr Expr, RelType Type, + uint64_t Offset, Symbol &Sym, const RelTy &Rel, + int64_t Addend) { + if (isStaticLinkTimeConstant(Expr, Type, Sym, Sec, Offset)) { + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } + bool CanWrite = (Sec.Flags & SHF_WRITE) || !Config->ZText; + if (CanWrite) { + // R_GOT refers to a position in the got, even if the symbol is preemptible. + bool IsPreemptibleValue = Sym.IsPreemptible && Expr != R_GOT; - InX::RelaDyn->addReloc( - {Target->getDynRel(Type), &Sec, Offset, false, &Sym, Addend}); + if (!IsPreemptibleValue) { + addRelativeReloc(&Sec, Offset, &Sym, Addend, Expr, Type); + return; + } else if (RelType Rel = Target->getDynRel(Type)) { + InX::RelaDyn->addReloc(Rel, &Sec, Offset, &Sym, Addend, R_ADDEND, Type); // MIPS ABI turns using of GOT and dynamic relocations inside out. // While regular ABI uses dynamic relocations to fill up GOT entries @@ -1014,37 +843,210 @@ static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { // a dynamic relocation. // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf p.4-19 if (Config->EMachine == EM_MIPS) - InX::MipsGot->addEntry(Sym, Addend, Expr); - continue; + InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); + return; } + } - // The size is not going to change, so we fold it in here. - if (Expr == R_SIZE) - Addend += Sym.getSize(); + // If the relocation is to a weak undef, and we are producing + // executable, give up on it and produce a non preemptible 0. + if (!Config->Shared && Sym.isUndefWeak()) { + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } - // If the produced value is a constant, we just remember to write it - // when outputting this section. We also have to do it if the format - // uses Elf_Rel, since in that case the written value is the addend. - if (IsConstant) { - Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); - continue; + if (!CanWrite && (Config->Pic && !isRelExpr(Expr))) { + error( + "can't create dynamic relocation " + toString(Type) + " against " + + (Sym.getName().empty() ? "local symbol" : "symbol: " + toString(Sym)) + + " in readonly segment; recompile object files with -fPIC " + "or pass '-Wl,-z,notext' to allow text relocations in the output" + + getLocation(Sec, Sym, Offset)); + return; + } + + // Copy relocations are only possible if we are creating an executable. + if (Config->Shared) { + errorOrWarn("relocation " + toString(Type) + + " cannot be used against symbol " + toString(Sym) + + "; recompile with -fPIC" + getLocation(Sec, Sym, Offset)); + return; + } + + // If the symbol is undefined we already reported any relevant errors. + if (Sym.isUndefined()) + return; + + if (!canDefineSymbolInExecutable(Sym)) { + error("cannot preempt symbol: " + toString(Sym) + + getLocation(Sec, Sym, Offset)); + return; + } + + if (Sym.isObject()) { + // Produce a copy relocation. + if (auto *SS = dyn_cast<SharedSymbol>(&Sym)) { + if (!Config->ZCopyreloc) + error("unresolvable relocation " + toString(Type) + + " against symbol '" + toString(*SS) + + "'; recompile with -fPIC or remove '-z nocopyreloc'" + + getLocation(Sec, Sym, Offset)); + addCopyRelSymbol<ELFT>(*SS); } + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } - // If the output being produced is position independent, the final value - // is still not known. In that case we still need some help from the - // dynamic linker. We can however do better than just copying the incoming - // relocation. We can process some of it and and just ask the dynamic - // linker to add the load address. - if (Config->IsRela) { - InX::RelaDyn->addReloc( - {Target->RelativeRel, &Sec, Offset, true, &Sym, Addend}); - } else { - // In REL, addends are stored to the target section. - InX::RelaDyn->addReloc( - {Target->RelativeRel, &Sec, Offset, true, &Sym, 0}); - Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + if (Sym.isFunc()) { + // This handles a non PIC program call to function in a shared library. In + // an ideal world, we could just report an error saying the relocation can + // overflow at runtime. In the real world with glibc, crt1.o has a + // R_X86_64_PC32 pointing to libc.so. + // + // The general idea on how to handle such cases is to create a PLT entry and + // use that as the function value. + // + // For the static linking part, we just return a plt expr and everything + // else will use the PLT entry as the address. + // + // The remaining problem is making sure pointer equality still works. We + // need the help of the dynamic linker for that. We let it know that we have + // a direct reference to a so symbol by creating an undefined symbol with a + // non zero st_value. Seeing that, the dynamic linker resolves the symbol to + // the value of the symbol we created. This is true even for got entries, so + // pointer equality is maintained. To avoid an infinite loop, the only entry + // that points to the real function is a dedicated got entry used by the + // plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT, + // R_386_JMP_SLOT, etc). + + // For position independent executable on i386, the plt entry requires ebx + // to be set. This causes two problems: + // * If some code has a direct reference to a function, it was probably + // compiled without -fPIE/-fPIC and doesn't maintain ebx. + // * If a library definition gets preempted to the executable, it will have + // the wrong ebx value. + if (Config->Pie && Config->EMachine == EM_386) + errorOrWarn("symbol '" + toString(Sym) + + "' cannot be preempted; recompile with -fPIE" + + getLocation(Sec, Sym, Offset)); + if (!Sym.isInPlt()) + addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, + Sym); + if (!Sym.isDefined()) + replaceWithDefined(Sym, InX::Plt, Sym.getPltOffset(), 0); + Sym.NeedsPltAddr = true; + Sec.Relocations.push_back({Expr, Type, Offset, Addend, &Sym}); + return; + } + + errorOrWarn("symbol '" + toString(Sym) + "' has no type" + + getLocation(Sec, Sym, Offset)); +} + +template <class ELFT, class RelTy> +static void scanReloc(InputSectionBase &Sec, OffsetGetter &GetOffset, RelTy *&I, + RelTy *End) { + const RelTy &Rel = *I; + Symbol &Sym = Sec.getFile<ELFT>()->getRelocTargetSym(Rel); + RelType Type; + + // Deal with MIPS oddity. + if (Config->MipsN32Abi) { + Type = getMipsN32RelType(I, End); + } else { + Type = Rel.getType(Config->IsMips64EL); + ++I; + } + + // Get an offset in an output section this relocation is applied to. + uint64_t Offset = GetOffset.get(Rel.r_offset); + if (Offset == uint64_t(-1)) + return; + + // Skip if the target symbol is an erroneous undefined symbol. + if (maybeReportUndefined(Sym, Sec, Rel.r_offset)) + return; + + const uint8_t *RelocatedAddr = Sec.Data.begin() + Rel.r_offset; + RelExpr Expr = Target->getRelExpr(Type, Sym, RelocatedAddr); + + // Ignore "hint" relocations because they are only markers for relaxation. + if (isRelExprOneOf<R_HINT, R_NONE>(Expr)) + return; + + // Strenghten or relax relocations. + // + // GNU ifunc symbols must be accessed via PLT because their addresses + // are determined by runtime. + // + // On the other hand, if we know that a PLT entry will be resolved within + // the same ELF module, we can skip PLT access and directly jump to the + // destination function. For example, if we are linking a main exectuable, + // all dynamic symbols that can be resolved within the executable will + // actually be resolved that way at runtime, because the main exectuable + // is always at the beginning of a search list. We can leverage that fact. + if (Sym.isGnuIFunc()) + Expr = toPlt(Expr); + else if (!Sym.IsPreemptible && Expr == R_GOT_PC && !isAbsoluteValue(Sym)) + Expr = Target->adjustRelaxExpr(Type, RelocatedAddr, Expr); + else if (!Sym.IsPreemptible) + Expr = fromPlt(Expr); + + // This relocation does not require got entry, but it is relative to got and + // needs it to be created. Here we request for that. + if (isRelExprOneOf<R_GOTONLY_PC, R_GOTONLY_PC_FROM_END, R_GOTREL, + R_GOTREL_FROM_END, R_PPC_TOC>(Expr)) + InX::Got->HasGotOffRel = true; + + // Read an addend. + int64_t Addend = computeAddend<ELFT>(Rel, End, Sec, Expr, Sym.isLocal()); + + // Process some TLS relocations, including relaxing TLS relocations. + // Note that this function does not handle all TLS relocations. + if (unsigned Processed = + handleTlsRelocation<ELFT>(Type, Sym, Sec, Offset, Addend, Expr)) { + I += (Processed - 1); + return; + } + + // If a relocation needs PLT, we create PLT and GOTPLT slots for the symbol. + if (needsPlt(Expr) && !Sym.isInPlt()) { + if (Sym.isGnuIFunc() && !Sym.IsPreemptible) + addPltEntry<ELFT>(InX::Iplt, InX::IgotPlt, InX::RelaIplt, + Target->IRelativeRel, Sym); + else + addPltEntry<ELFT>(InX::Plt, InX::GotPlt, InX::RelaPlt, Target->PltRel, + Sym); + } + + // Create a GOT slot if a relocation needs GOT. + if (needsGot(Expr)) { + if (Config->EMachine == EM_MIPS) { + // MIPS ABI has special rules to process GOT entries and doesn't + // require relocation entries for them. A special case is TLS + // relocations. In that case dynamic loader applies dynamic + // relocations to initialize TLS GOT entries. + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed description: + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + InX::MipsGot->addEntry(*Sec.File, Sym, Addend, Expr); + } else if (!Sym.isInGot()) { + addGotEntry<ELFT>(Sym); } } + + processRelocAux<ELFT>(Sec, Expr, Type, Offset, Sym, Rel, Addend); +} + +template <class ELFT, class RelTy> +static void scanRelocs(InputSectionBase &Sec, ArrayRef<RelTy> Rels) { + OffsetGetter GetOffset(Sec); + + // Not all relocations end up in Sec.Relocations, but a lot do. + Sec.Relocations.reserve(Rels.size()); + + for (auto I = Rels.begin(), End = Rels.end(); I != End;) + scanReloc<ELFT>(Sec, GetOffset, I, End); } template <class ELFT> void elf::scanRelocations(InputSectionBase &S) { @@ -1259,17 +1261,30 @@ ThunkSection *ThunkCreator::getISThunkSec(InputSection *IS) { // // We follow a simple but conservative heuristic to place ThunkSections at // offsets that are multiples of a Target specific branch range. -// For an InputSectionRange that is smaller than the range, a single +// For an InputSectionDescription that is smaller than the range, a single // ThunkSection at the end of the range will do. +// +// For an InputSectionDescription that is more than twice the size of the range, +// we place the last ThunkSection at range bytes from the end of the +// InputSectionDescription in order to increase the likelihood that the +// distance from a thunk to its target will be sufficiently small to +// allow for the creation of a short thunk. void ThunkCreator::createInitialThunkSections( ArrayRef<OutputSection *> OutputSections) { forEachInputSectionDescription( OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { if (ISD->Sections.empty()) return; + uint32_t ISDBegin = ISD->Sections.front()->OutSecOff; + uint32_t ISDEnd = + ISD->Sections.back()->OutSecOff + ISD->Sections.back()->getSize(); + uint32_t LastThunkLowerBound = -1; + if (ISDEnd - ISDBegin > Target->ThunkSectionSpacing * 2) + LastThunkLowerBound = ISDEnd - Target->ThunkSectionSpacing; + uint32_t ISLimit; - uint32_t PrevISLimit = ISD->Sections.front()->OutSecOff; - uint32_t ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; + uint32_t PrevISLimit = ISDBegin; + uint32_t ThunkUpperBound = ISDBegin + Target->ThunkSectionSpacing; for (const InputSection *IS : ISD->Sections) { ISLimit = IS->OutSecOff + IS->getSize(); @@ -1277,6 +1292,8 @@ void ThunkCreator::createInitialThunkSections( addThunkSection(OS, ISD, PrevISLimit); ThunkUpperBound = PrevISLimit + Target->ThunkSectionSpacing; } + if (ISLimit > LastThunkLowerBound) + break; PrevISLimit = ISLimit; } addThunkSection(OS, ISD, ISLimit); @@ -1293,17 +1310,22 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, uint64_t Src) { - auto Res = ThunkedSymbols.insert({&Sym, std::vector<Thunk *>()}); - if (!Res.second) { - // Check existing Thunks for Sym to see if they can be reused - for (Thunk *ET : Res.first->second) - if (ET->isCompatibleWith(Type) && - Target->inBranchRange(Type, Src, ET->ThunkSym->getVA())) - return std::make_pair(ET, false); - } + std::vector<Thunk *> *ThunkVec = nullptr; + // We use (section, offset) pair to find the thunk position if possible so + // that we create only one thunk for aliased symbols or ICFed sections. + if (auto *D = dyn_cast<Defined>(&Sym)) + if (!D->isInPlt() && D->Section) + ThunkVec = &ThunkedSymbolsBySection[{D->Section->Repl, D->Value}]; + if (!ThunkVec) + ThunkVec = &ThunkedSymbols[&Sym]; + // Check existing Thunks for Sym to see if they can be reused + for (Thunk *ET : *ThunkVec) + if (ET->isCompatibleWith(Type) && + Target->inBranchRange(Type, Src, ET->getThunkTargetSym()->getVA())) + return std::make_pair(ET, false); // No existing compatible Thunk in range, create a new one Thunk *T = addThunk(Type, Sym); - Res.first->second.push_back(T); + ThunkVec->push_back(T); return std::make_pair(T, true); } @@ -1311,7 +1333,7 @@ std::pair<Thunk *, bool> ThunkCreator::getThunk(Symbol &Sym, RelType Type, // InputSectionDescription::Sections. void ThunkCreator::forEachInputSectionDescription( ArrayRef<OutputSection *> OutputSections, - std::function<void(OutputSection *, InputSectionDescription *)> Fn) { + llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn) { for (OutputSection *OS : OutputSections) { if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; @@ -1379,7 +1401,7 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { OutputSections, [&](OutputSection *OS, InputSectionDescription *ISD) { for (InputSection *IS : ISD->Sections) for (Relocation &Rel : IS->Relocations) { - uint64_t Src = OS->Addr + IS->OutSecOff + Rel.Offset; + uint64_t Src = IS->getVA(Rel.Offset); // If we are a relocation to an existing Thunk, check if it is // still in range. If not then Rel will be altered to point to its @@ -1394,7 +1416,6 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { bool IsNew; std::tie(T, IsNew) = getThunk(*Rel.Sym, Rel.Type, Src); if (IsNew) { - AddressesChanged = true; // Find or create a ThunkSection for the new Thunk ThunkSection *TS; if (auto *TIS = T->getTargetInputSection()) @@ -1402,13 +1423,18 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> OutputSections) { else TS = getISDThunkSec(OS, IS, ISD, Rel.Type, Src); TS->addThunk(T); - Thunks[T->ThunkSym] = T; + Thunks[T->getThunkTargetSym()] = T; } // Redirect relocation to Thunk, we never go via the PLT to a Thunk - Rel.Sym = T->ThunkSym; + Rel.Sym = T->getThunkTargetSym(); Rel.Expr = fromPlt(Rel.Expr); } + for (auto &P : ISD->ThunkSections) + AddressesChanged |= P.first->assignOffsets(); }); + for (auto &P : ThunkedSections) + AddressesChanged |= P.second->assignOffsets(); + // Merge all created synthetic ThunkSections back into OutputSection mergeThunks(OutputSections); ++Pass; diff --git a/ELF/Relocations.h b/ELF/Relocations.h index 2cc8adfa5985..a4125111c4fe 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -21,7 +21,7 @@ class Symbol; class InputSection; class InputSectionBase; class OutputSection; -class OutputSection; +class SectionBase; // Represents a relocation type, such as R_X86_64_PC32 or R_ARM_THM_CALL. typedef uint32_t RelType; @@ -32,6 +32,7 @@ typedef uint32_t RelType; enum RelExpr { R_INVALID, R_ABS, + R_ADDEND, R_ARM_SBREL, R_GOT, R_GOTONLY_PC, @@ -58,27 +59,33 @@ enum RelExpr { R_PLT, R_PLT_PAGE_PC, R_PLT_PC, - R_PPC_OPD, - R_PPC_PLT_OPD, + R_PPC_CALL, + R_PPC_CALL_PLT, R_PPC_TOC, R_RELAX_GOT_PC, R_RELAX_GOT_PC_NOPIC, R_RELAX_TLS_GD_TO_IE, R_RELAX_TLS_GD_TO_IE_ABS, R_RELAX_TLS_GD_TO_IE_END, + R_RELAX_TLS_GD_TO_IE_GOT_OFF, R_RELAX_TLS_GD_TO_IE_PAGE_PC, R_RELAX_TLS_GD_TO_LE, R_RELAX_TLS_GD_TO_LE_NEG, R_RELAX_TLS_IE_TO_LE, R_RELAX_TLS_LD_TO_LE, + R_RELAX_TLS_LD_TO_LE_ABS, R_SIZE, R_TLS, R_TLSDESC, R_TLSDESC_CALL, R_TLSDESC_PAGE, - R_TLSGD, + R_TLSGD_GOT, + R_TLSGD_GOT_FROM_END, R_TLSGD_PC, - R_TLSLD, + R_TLSLD_GOT, + R_TLSLD_GOT_FROM_END, + R_TLSLD_GOT_OFF, + R_TLSLD_HINT, R_TLSLD_PC, }; @@ -150,7 +157,7 @@ private: void forEachInputSectionDescription( ArrayRef<OutputSection *> OutputSections, - std::function<void(OutputSection *, InputSectionDescription *)> Fn); + llvm::function_ref<void(OutputSection *, InputSectionDescription *)> Fn); std::pair<Thunk *, bool> getThunk(Symbol &Sym, RelType Type, uint64_t Src); @@ -160,6 +167,8 @@ private: bool normalizeExistingThunk(Relocation &Rel, uint64_t Src); // Record all the available Thunks for a Symbol + llvm::DenseMap<std::pair<SectionBase *, uint64_t>, std::vector<Thunk *>> + ThunkedSymbolsBySection; llvm::DenseMap<Symbol *, std::vector<Thunk *>> ThunkedSymbols; // Find a Thunk from the Thunks symbol definition, we can use this to find diff --git a/ELF/ScriptLexer.cpp b/ELF/ScriptLexer.cpp index ef5a1cff7590..d4b1f6d99cc1 100644 --- a/ELF/ScriptLexer.cpp +++ b/ELF/ScriptLexer.cpp @@ -66,8 +66,6 @@ size_t ScriptLexer::getColumnNumber() { std::string ScriptLexer::getCurrentLocation() { std::string Filename = getCurrentMB().getBufferIdentifier(); - if (!Pos) - return Filename; return (Filename + ":" + Twine(getLineNumber())).str(); } @@ -116,8 +114,9 @@ void ScriptLexer::tokenize(MemoryBufferRef MB) { } // ">foo" is parsed to ">" and "foo", but ">>" is parsed to ">>". + // "|", "||", "&" and "&&" are different operators. if (S.startswith("<<") || S.startswith("<=") || S.startswith(">>") || - S.startswith(">=")) { + S.startswith(">=") || S.startswith("||") || S.startswith("&&")) { Vec.push_back(S.substr(0, 2)); S = S.substr(2); continue; @@ -282,10 +281,7 @@ static bool encloses(StringRef S, StringRef T) { MemoryBufferRef ScriptLexer::getCurrentMB() { // Find input buffer containing the current token. - assert(!MBs.empty()); - if (!Pos) - return MBs[0]; - + assert(!MBs.empty() && Pos > 0); for (MemoryBufferRef MB : MBs) if (encloses(MB.getBuffer(), Tokens[Pos - 1])) return MB; diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 4263944981f2..ddb4a49a3e5e 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -63,6 +63,7 @@ private: void readExtern(); void readGroup(); void readInclude(); + void readInput(); void readMemory(); void readOutput(); void readOutputArch(); @@ -74,12 +75,14 @@ private: void readVersion(); void readVersionScriptCommand(); - SymbolAssignment *readAssignment(StringRef Name); + SymbolAssignment *readSymbolAssignment(StringRef Name); ByteCommand *readByteCommand(StringRef Tok); uint32_t readFill(); uint32_t parseFill(StringRef Tok); void readSectionAddressType(OutputSection *Cmd); + OutputSection *readOverlaySectionDescription(); OutputSection *readOutputSectionDescription(StringRef OutSec); + std::vector<BaseCommand *> readOverlay(); std::vector<StringRef> readOutputSectionPhdrs(); InputSectionDescription *readInputSectionDescription(StringRef Tok); StringMatcher readFilePatterns(); @@ -88,16 +91,16 @@ private: unsigned readPhdrType(); SortSectionPolicy readSortKind(); SymbolAssignment *readProvideHidden(bool Provide, bool Hidden); - SymbolAssignment *readProvideOrAssignment(StringRef Tok); + SymbolAssignment *readAssignment(StringRef Tok); void readSort(); - AssertCommand *readAssert(); - Expr readAssertExpr(); + Expr readAssert(); Expr readConstant(); Expr getPageSize(); uint64_t readMemoryAssignment(StringRef, StringRef, StringRef); std::pair<uint32_t, uint32_t> readMemoryAttributes(); + Expr combine(StringRef Op, Expr L, Expr R); Expr readExpr(); Expr readExpr1(Expr Lhs, int MinPrec); StringRef readParenLiteral(); @@ -157,17 +160,6 @@ static ExprValue sub(ExprValue A, ExprValue B) { return {A.Sec, false, A.getSectionOffset() - B.getValue(), A.Loc}; } -static ExprValue mul(ExprValue A, ExprValue B) { - return A.getValue() * B.getValue(); -} - -static ExprValue div(ExprValue A, ExprValue B) { - if (uint64_t BV = B.getValue()) - return A.getValue() / BV; - error("division by zero"); - return 0; -} - static ExprValue bitAnd(ExprValue A, ExprValue B) { moveAbsRight(A, B); return {A.Sec, A.ForceAbsolute, @@ -237,16 +229,16 @@ void ScriptParser::readLinkerScript() { if (Tok == ";") continue; - if (Tok == "ASSERT") { - Script->SectionCommands.push_back(readAssert()); - } else if (Tok == "ENTRY") { + if (Tok == "ENTRY") { readEntry(); } else if (Tok == "EXTERN") { readExtern(); - } else if (Tok == "GROUP" || Tok == "INPUT") { + } else if (Tok == "GROUP") { readGroup(); } else if (Tok == "INCLUDE") { readInclude(); + } else if (Tok == "INPUT") { + readInput(); } else if (Tok == "MEMORY") { readMemory(); } else if (Tok == "OUTPUT") { @@ -265,7 +257,7 @@ void ScriptParser::readLinkerScript() { readSections(); } else if (Tok == "VERSION") { readVersion(); - } else if (SymbolAssignment *Cmd = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Cmd = readAssignment(Tok)) { Script->SectionCommands.push_back(Cmd); } else { setError("unknown directive: " + Tok); @@ -336,13 +328,12 @@ void ScriptParser::readExtern() { } void ScriptParser::readGroup() { - expect("("); - while (!errorCount() && !consume(")")) { - if (consume("AS_NEEDED")) - readAsNeeded(); - else - addFile(unquote(next())); - } + bool Orig = InputFile::IsInGroup; + InputFile::IsInGroup = true; + readInput(); + InputFile::IsInGroup = Orig; + if (!Orig) + ++InputFile::NextGroupId; } void ScriptParser::readInclude() { @@ -353,7 +344,7 @@ void ScriptParser::readInclude() { return; } - if (Optional<std::string> Path = searchLinkerScript(Tok)) { + if (Optional<std::string> Path = searchScript(Tok)) { if (Optional<MemoryBufferRef> MB = readFile(*Path)) tokenize(*MB); return; @@ -361,6 +352,16 @@ void ScriptParser::readInclude() { setError("cannot find linker script " + Tok); } +void ScriptParser::readInput() { + expect("("); + while (!errorCount() && !consume(")")) { + if (consume("AS_NEEDED")) + readAsNeeded(); + else + addFile(unquote(next())); + } +} + void ScriptParser::readOutput() { // -o <file> takes predecence over OUTPUT(<file>). expect("("); @@ -437,6 +438,49 @@ void ScriptParser::readSearchDir() { expect(")"); } +// This reads an overlay description. Overlays are used to describe output +// sections that use the same virtual memory range and normally would trigger +// linker's sections sanity check failures. +// https://sourceware.org/binutils/docs/ld/Overlay-Description.html#Overlay-Description +std::vector<BaseCommand *> ScriptParser::readOverlay() { + // VA and LMA expressions are optional, though for simplicity of + // implementation we assume they are not. That is what OVERLAY was designed + // for first of all: to allow sections with overlapping VAs at different LMAs. + Expr AddrExpr = readExpr(); + expect(":"); + expect("AT"); + Expr LMAExpr = readParenExpr(); + expect("{"); + + std::vector<BaseCommand *> V; + OutputSection *Prev = nullptr; + while (!errorCount() && !consume("}")) { + // VA is the same for all sections. The LMAs are consecutive in memory + // starting from the base load address specified. + OutputSection *OS = readOverlaySectionDescription(); + OS->AddrExpr = AddrExpr; + if (Prev) + OS->LMAExpr = [=] { return Prev->getLMA() + Prev->Size; }; + else + OS->LMAExpr = LMAExpr; + V.push_back(OS); + Prev = OS; + } + + // According to the specification, at the end of the overlay, the location + // counter should be equal to the overlay base address plus size of the + // largest section seen in the overlay. + // Here we want to create the Dot assignment command to achieve that. + Expr MoveDot = [=] { + uint64_t Max = 0; + for (BaseCommand *Cmd : V) + Max = std::max(Max, cast<OutputSection>(Cmd)->Size); + return AddrExpr().getValue() + Max; + }; + V.push_back(make<SymbolAssignment>(".", MoveDot, getCurrentLocation())); + return V; +} + void ScriptParser::readSections() { Script->HasSectionsCommand = true; @@ -446,26 +490,48 @@ void ScriptParser::readSections() { Config->SingleRoRx = true; expect("{"); + std::vector<BaseCommand *> V; while (!errorCount() && !consume("}")) { StringRef Tok = next(); - BaseCommand *Cmd = readProvideOrAssignment(Tok); - if (!Cmd) { - if (Tok == "ASSERT") - Cmd = readAssert(); - else - Cmd = readOutputSectionDescription(Tok); + if (Tok == "OVERLAY") { + for (BaseCommand *Cmd : readOverlay()) + V.push_back(Cmd); + continue; } - Script->SectionCommands.push_back(Cmd); + + if (BaseCommand *Cmd = readAssignment(Tok)) + V.push_back(Cmd); + else + V.push_back(readOutputSectionDescription(Tok)); + } + + if (!atEOF() && consume("INSERT")) { + std::vector<BaseCommand *> *Dest = nullptr; + if (consume("AFTER")) + Dest = &Script->InsertAfterCommands[next()]; + else if (consume("BEFORE")) + Dest = &Script->InsertBeforeCommands[next()]; + else + setError("expected AFTER/BEFORE, but got '" + next() + "'"); + if (Dest) + Dest->insert(Dest->end(), V.begin(), V.end()); + return; } + + Script->SectionCommands.insert(Script->SectionCommands.end(), V.begin(), + V.end()); } static int precedence(StringRef Op) { return StringSwitch<int>(Op) - .Cases("*", "/", 5) - .Cases("+", "-", 4) - .Cases("<<", ">>", 3) - .Cases("<", "<=", ">", ">=", "==", "!=", 2) - .Cases("&", "|", 1) + .Cases("*", "/", "%", 8) + .Cases("+", "-", 7) + .Cases("<<", ">>", 6) + .Cases("<", "<=", ">", ">=", "==", "!=", 5) + .Case("&", 4) + .Case("|", 3) + .Case("&&", 2) + .Case("||", 1) .Default(-1); } @@ -588,11 +654,7 @@ void ScriptParser::readSort() { expect(")"); } -AssertCommand *ScriptParser::readAssert() { - return make<AssertCommand>(readAssertExpr()); -} - -Expr ScriptParser::readAssertExpr() { +Expr ScriptParser::readAssert() { expect("("); Expr E = readExpr(); expect(","); @@ -617,12 +679,14 @@ uint32_t ScriptParser::readFill() { return V; } -// Reads an expression and/or the special directive "(NOLOAD)" for an -// output section definition. +// Reads an expression and/or the special directive for an output +// section definition. Directive is one of following: "(NOLOAD)", +// "(COPY)", "(INFO)" or "(OVERLAY)". // // An output section name can be followed by an address expression -// and/or by "(NOLOAD)". This grammar is not LL(1) because "(" can be -// interpreted as either the beginning of some expression or "(NOLOAD)". +// and/or directive. This grammar is not LL(1) because "(" can be +// interpreted as either the beginning of some expression or beginning +// of directive. // // https://sourceware.org/binutils/docs/ld/Output-Section-Address.html // https://sourceware.org/binutils/docs/ld/Output-Section-Type.html @@ -633,6 +697,11 @@ void ScriptParser::readSectionAddressType(OutputSection *Cmd) { Cmd->Noload = true; return; } + if (consume("COPY") || consume("INFO") || consume("OVERLAY")) { + expect(")"); + Cmd->NonAlloc = true; + return; + } Cmd->AddrExpr = readExpr(); expect(")"); } else { @@ -657,10 +726,23 @@ static Expr checkAlignment(Expr E, std::string &Loc) { }; } +OutputSection *ScriptParser::readOverlaySectionDescription() { + OutputSection *Cmd = + Script->createOutputSection(next(), getCurrentLocation()); + Cmd->InOverlay = true; + expect("{"); + while (!errorCount() && !consume("}")) + Cmd->SectionCommands.push_back(readInputSectionRules(next())); + Cmd->Phdrs = readOutputSectionPhdrs(); + return Cmd; +} + OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { OutputSection *Cmd = Script->createOutputSection(OutSec, getCurrentLocation()); + size_t SymbolsReferenced = Script->ReferencedSymbols.size(); + if (peek() != ":") readSectionAddressType(Cmd); expect(":"); @@ -684,13 +766,10 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { StringRef Tok = next(); if (Tok == ";") { // Empty commands are allowed. Do nothing here. - } else if (SymbolAssignment *Assign = readProvideOrAssignment(Tok)) { + } else if (SymbolAssignment *Assign = readAssignment(Tok)) { Cmd->SectionCommands.push_back(Assign); } else if (ByteCommand *Data = readByteCommand(Tok)) { Cmd->SectionCommands.push_back(Data); - } else if (Tok == "ASSERT") { - Cmd->SectionCommands.push_back(readAssert()); - expect(";"); } else if (Tok == "CONSTRUCTORS") { // CONSTRUCTORS is a keyword to make the linker recognize C++ ctors/dtors // by name. This is for very old file formats such as ECOFF/XCOFF. @@ -709,6 +788,14 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { if (consume(">")) Cmd->MemoryRegionName = next(); + if (consume("AT")) { + expect(">"); + Cmd->LMARegionName = next(); + } + + if (Cmd->LMAExpr && !Cmd->LMARegionName.empty()) + error("section can't have both LMA and a load region"); + Cmd->Phdrs = readOutputSectionPhdrs(); if (consume("=")) @@ -719,6 +806,8 @@ OutputSection *ScriptParser::readOutputSectionDescription(StringRef OutSec) { // Consume optional comma following output section command. consume(","); + if (Script->ReferencedSymbols.size() > SymbolsReferenced) + Cmd->ExpressionsUseSymbols = true; return Cmd; } @@ -741,30 +830,39 @@ uint32_t ScriptParser::parseFill(StringRef Tok) { SymbolAssignment *ScriptParser::readProvideHidden(bool Provide, bool Hidden) { expect("("); - SymbolAssignment *Cmd = readAssignment(next()); + SymbolAssignment *Cmd = readSymbolAssignment(next()); Cmd->Provide = Provide; Cmd->Hidden = Hidden; expect(")"); - expect(";"); return Cmd; } -SymbolAssignment *ScriptParser::readProvideOrAssignment(StringRef Tok) { +SymbolAssignment *ScriptParser::readAssignment(StringRef Tok) { + // Assert expression returns Dot, so this is equal to ".=." + if (Tok == "ASSERT") + return make<SymbolAssignment>(".", readAssert(), getCurrentLocation()); + + size_t OldPos = Pos; SymbolAssignment *Cmd = nullptr; - if (peek() == "=" || peek() == "+=") { - Cmd = readAssignment(Tok); - expect(";"); - } else if (Tok == "PROVIDE") { + if (peek() == "=" || peek() == "+=") + Cmd = readSymbolAssignment(Tok); + else if (Tok == "PROVIDE") Cmd = readProvideHidden(true, false); - } else if (Tok == "HIDDEN") { + else if (Tok == "HIDDEN") Cmd = readProvideHidden(false, true); - } else if (Tok == "PROVIDE_HIDDEN") { + else if (Tok == "PROVIDE_HIDDEN") Cmd = readProvideHidden(true, true); + + if (Cmd) { + Cmd->CommandString = + Tok.str() + " " + + llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " "); + expect(";"); } return Cmd; } -SymbolAssignment *ScriptParser::readAssignment(StringRef Name) { +SymbolAssignment *ScriptParser::readSymbolAssignment(StringRef Name) { StringRef Op = next(); assert(Op == "=" || Op == "+="); Expr E = readExpr(); @@ -787,15 +885,31 @@ Expr ScriptParser::readExpr() { return E; } -static Expr combine(StringRef Op, Expr L, Expr R) { +Expr ScriptParser::combine(StringRef Op, Expr L, Expr R) { if (Op == "+") return [=] { return add(L(), R()); }; if (Op == "-") return [=] { return sub(L(), R()); }; if (Op == "*") - return [=] { return mul(L(), R()); }; - if (Op == "/") - return [=] { return div(L(), R()); }; + return [=] { return L().getValue() * R().getValue(); }; + if (Op == "/") { + std::string Loc = getCurrentLocation(); + return [=]() -> uint64_t { + if (uint64_t RV = R().getValue()) + return L().getValue() / RV; + error(Loc + ": division by zero"); + return 0; + }; + } + if (Op == "%") { + std::string Loc = getCurrentLocation(); + return [=]() -> uint64_t { + if (uint64_t RV = R().getValue()) + return L().getValue() % RV; + error(Loc + ": modulo by zero"); + return 0; + }; + } if (Op == "<<") return [=] { return L().getValue() << R().getValue(); }; if (Op == ">>") @@ -812,6 +926,10 @@ static Expr combine(StringRef Op, Expr L, Expr R) { return [=] { return L().getValue() == R().getValue(); }; if (Op == "!=") return [=] { return L().getValue() != R().getValue(); }; + if (Op == "||") + return [=] { return L().getValue() || R().getValue(); }; + if (Op == "&&") + return [=] { return L().getValue() && R().getValue(); }; if (Op == "&") return [=] { return bitAnd(L(), R()); }; if (Op == "|") @@ -865,20 +983,13 @@ Expr ScriptParser::readConstant() { if (S == "MAXPAGESIZE") return [] { return Config->MaxPageSize; }; setError("unknown constant: " + S); - return {}; + return [] { return 0; }; } // Parses Tok as an integer. It recognizes hexadecimal (prefixed with // "0x" or suffixed with "H") and decimal numbers. Decimal numbers may // have "K" (Ki) or "M" (Mi) suffixes. static Optional<uint64_t> parseInt(StringRef Tok) { - // Negative number - if (Tok.startswith("-")) { - if (Optional<uint64_t> Val = parseInt(Tok.substr(1))) - return -*Val; - return None; - } - // Hexadecimal uint64_t Val; if (Tok.startswith_lower("0x")) { @@ -917,12 +1028,21 @@ ByteCommand *ScriptParser::readByteCommand(StringRef Tok) { .Default(-1); if (Size == -1) return nullptr; - return make<ByteCommand>(readParenExpr(), Size); + + size_t OldPos = Pos; + Expr E = readParenExpr(); + std::string CommandString = + Tok.str() + " " + + llvm::join(Tokens.begin() + OldPos, Tokens.begin() + Pos, " "); + return make<ByteCommand>(E, Size, CommandString); } StringRef ScriptParser::readParenLiteral() { expect("("); + bool Orig = InExpr; + InExpr = false; StringRef Tok = next(); + InExpr = Orig; expect(")"); return Tok; } @@ -995,7 +1115,7 @@ Expr ScriptParser::readPrimary() { }; } if (Tok == "ASSERT") - return readAssertExpr(); + return readAssert(); if (Tok == "CONSTANT") return readConstant(); if (Tok == "DATA_SEGMENT_ALIGN") { @@ -1032,8 +1152,10 @@ Expr ScriptParser::readPrimary() { } if (Tok == "LENGTH") { StringRef Name = readParenLiteral(); - if (Script->MemoryRegions.count(Name) == 0) + if (Script->MemoryRegions.count(Name) == 0) { setError("memory region not defined: " + Name); + return [] { return 0; }; + } return [=] { return Script->MemoryRegions[Name]->Length; }; } if (Tok == "LOADADDR") { @@ -1044,10 +1166,22 @@ Expr ScriptParser::readPrimary() { return Cmd->getLMA(); }; } + if (Tok == "MAX" || Tok == "MIN") { + expect("("); + Expr A = readExpr(); + expect(","); + Expr B = readExpr(); + expect(")"); + if (Tok == "MIN") + return [=] { return std::min(A().getValue(), B().getValue()); }; + return [=] { return std::max(A().getValue(), B().getValue()); }; + } if (Tok == "ORIGIN") { StringRef Name = readParenLiteral(); - if (Script->MemoryRegions.count(Name) == 0) + if (Script->MemoryRegions.count(Name) == 0) { setError("memory region not defined: " + Name); + return [] { return 0; }; + } return [=] { return Script->MemoryRegions[Name]->Origin; }; } if (Tok == "SEGMENT_START") { @@ -1229,6 +1363,9 @@ ScriptParser::readSymbols() { // Reads an "extern C++" directive, e.g., // "extern "C++" { ns::*; "f(int, double)"; };" +// +// The last semicolon is optional. E.g. this is OK: +// "extern "C++" { ns::*; "f(int, double)" };" std::vector<SymbolVersion> ScriptParser::readVersionExtern() { StringRef Tok = next(); bool IsCXX = Tok == "\"C++\""; @@ -1241,6 +1378,8 @@ std::vector<SymbolVersion> ScriptParser::readVersionExtern() { StringRef Tok = next(); bool HasWildcard = !Tok.startswith("\"") && hasWildcard(Tok); Ret.push_back({unquote(Tok), IsCXX, HasWildcard}); + if (consume("}")) + return Ret; expect(";"); } @@ -1280,11 +1419,10 @@ void ScriptParser::readMemory() { uint64_t Length = readMemoryAssignment("LENGTH", "len", "l"); // Add the memory region to the region map. - if (Script->MemoryRegions.count(Name)) + MemoryRegion *MR = + make<MemoryRegion>(Name, Origin, Length, Flags, NegFlags); + if (!Script->MemoryRegions.insert({Name, MR}).second) setError("region '" + Name + "' already defined"); - MemoryRegion *MR = make<MemoryRegion>(); - *MR = {Name, Origin, Length, Flags, NegFlags}; - Script->MemoryRegions[Name] = MR; } } diff --git a/ELF/Strings.cpp b/ELF/Strings.cpp deleted file mode 100644 index 0ef33a14bc3d..000000000000 --- a/ELF/Strings.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===- Strings.cpp -------------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Strings.h" -#include "Config.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Demangle/Demangle.h" -#include <algorithm> -#include <cstring> - -using namespace llvm; -using namespace lld; -using namespace lld::elf; - -StringMatcher::StringMatcher(ArrayRef<StringRef> Pat) { - for (StringRef S : Pat) { - Expected<GlobPattern> Pat = GlobPattern::create(S); - if (!Pat) - error(toString(Pat.takeError())); - else - Patterns.push_back(*Pat); - } -} - -bool StringMatcher::match(StringRef S) const { - for (const GlobPattern &Pat : Patterns) - if (Pat.match(S)) - return true; - return false; -} - -// Converts a hex string (e.g. "deadbeef") to a vector. -std::vector<uint8_t> elf::parseHex(StringRef S) { - std::vector<uint8_t> Hex; - while (!S.empty()) { - StringRef B = S.substr(0, 2); - S = S.substr(2); - uint8_t H; - if (!to_integer(B, H, 16)) { - error("not a hexadecimal value: " + B); - return {}; - } - Hex.push_back(H); - } - return Hex; -} - -// Returns true if S is valid as a C language identifier. -bool elf::isValidCIdentifier(StringRef S) { - return !S.empty() && (isAlpha(S[0]) || S[0] == '_') && - std::all_of(S.begin() + 1, S.end(), - [](char C) { return C == '_' || isAlnum(C); }); -} diff --git a/ELF/Strings.h b/ELF/Strings.h deleted file mode 100644 index 5009df65f4c1..000000000000 --- a/ELF/Strings.h +++ /dev/null @@ -1,75 +0,0 @@ -//===- Strings.h ------------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_ELF_STRINGS_H -#define LLD_ELF_STRINGS_H - -#include "lld/Common/LLVM.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/GlobPattern.h" -#include <vector> - -namespace lld { -namespace elf { - -std::vector<uint8_t> parseHex(StringRef S); -bool isValidCIdentifier(StringRef S); - -// This is a lazy version of StringRef. String size is computed lazily -// when it is needed. It is more efficient than StringRef to instantiate -// if you have a string whose size is unknown. -// -// ELF string tables contain a lot of null-terminated strings. -// Most of them are not necessary for the linker because they are names -// of local symbols and the linker doesn't use local symbol names for -// name resolution. So, we use this class to represents strings read -// from string tables. -class StringRefZ { -public: - StringRefZ() : Start(nullptr), Size(0) {} - StringRefZ(const char *S, size_t Size) : Start(S), Size(Size) {} - - /*implicit*/ StringRefZ(const char *S) : Start(S), Size(-1) {} - - /*implicit*/ StringRefZ(llvm::StringRef S) - : Start(S.data()), Size(S.size()) {} - - operator llvm::StringRef() const { - if (Size == (size_t)-1) - Size = strlen(Start); - return {Start, Size}; - } - -private: - const char *Start; - mutable size_t Size; -}; - -// This class represents multiple glob patterns. -class StringMatcher { -public: - StringMatcher() = default; - explicit StringMatcher(ArrayRef<StringRef> Pat); - - bool match(StringRef S) const; - -private: - std::vector<llvm::GlobPattern> Patterns; -}; - -inline ArrayRef<uint8_t> toArrayRef(StringRef S) { - return {(const uint8_t *)S.data(), S.size()}; -} -} // namespace elf -} // namespace lld - -#endif diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index b6bf21998863..1f5a84ec2c7d 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -38,7 +38,7 @@ static InputFile *getFirstElf() { return ObjectFiles[0]; if (!SharedFiles.empty()) return SharedFiles[0]; - return nullptr; + return BitcodeFiles[0]; } // All input object files must be for the same architecture @@ -82,6 +82,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) { // Lazy object file if (auto *F = dyn_cast<LazyObjFile>(File)) { + LazyObjFiles.push_back(F); F->parse<ELFT>(); return; } @@ -117,7 +118,7 @@ template <class ELFT> void SymbolTable::addFile(InputFile *File) { // not in native object file format but in the LLVM bitcode format. // This function compiles bitcode files into a few big native files // using LLVM functions and replaces bitcode symbols with the results. -// Because all bitcode files that consist of a program are passed +// Because all bitcode files that the program consists of are passed // to the compiler at once, it can do whole-program optimization. template <class ELFT> void SymbolTable::addCombinedLTOObject() { if (BitcodeFiles.empty()) @@ -130,7 +131,10 @@ template <class ELFT> void SymbolTable::addCombinedLTOObject() { for (InputFile *File : LTO->compile()) { DenseSet<CachedHashStringRef> DummyGroups; - cast<ObjFile<ELFT>>(File)->parse(DummyGroups); + auto *Obj = cast<ObjFile<ELFT>>(File); + Obj->parse(DummyGroups); + for (Symbol *Sym : Obj->getGlobalSymbols()) + Sym->parseSymbolVersion(); ObjectFiles.push_back(File); } } @@ -154,6 +158,12 @@ template <class ELFT> void SymbolTable::addSymbolWrap(StringRef Name) { Symbol *Sym = find(Name); if (!Sym) return; + + // Do not wrap the same symbol twice. + for (const WrappedSymbol &S : WrappedSymbols) + if (S.Sym == Sym) + return; + Symbol *Real = addUndefined<ELFT>(Saver.save("__real_" + Name)); Symbol *Wrap = addUndefined<ELFT>(Saver.save("__wrap_" + Name)); WrappedSymbols.push_back({Sym, Real, Wrap}); @@ -186,7 +196,7 @@ void SymbolTable::applySymbolWrap() { // First, make a copy of __real_sym. Symbol *Real = nullptr; if (W.Real->isDefined()) { - Real = (Symbol *)make<SymbolUnion>(); + Real = reinterpret_cast<Symbol *>(make<SymbolUnion>()); memcpy(Real, W.Real, sizeof(SymbolUnion)); } @@ -234,8 +244,7 @@ std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { Symbol *Sym; if (IsNew) { - Sym = (Symbol *)make<SymbolUnion>(); - Sym->InVersionScript = false; + Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); Sym->Visibility = STV_DEFAULT; Sym->IsUsedInRegularObj = false; Sym->ExportDynamic = false; @@ -294,26 +303,88 @@ Symbol *SymbolTable::addUndefined(StringRef Name, uint8_t Binding, uint8_t Visibility = getVisibility(StOther); std::tie(S, WasInserted) = insert(Name, Type, Visibility, CanOmitFromDynSym, File); + // An undefined symbol with non default visibility must be satisfied // in the same DSO. if (WasInserted || (isa<SharedSymbol>(S) && Visibility != STV_DEFAULT)) { replaceSymbol<Undefined>(S, File, Name, Binding, StOther, Type); return S; } + if (S->isShared() || S->isLazy() || (S->isUndefined() && Binding != STB_WEAK)) S->Binding = Binding; - if (Binding != STB_WEAK) { + + if (!Config->GcSections && Binding != STB_WEAK) if (auto *SS = dyn_cast<SharedSymbol>(S)) - if (!Config->GcSections) - SS->getFile<ELFT>().IsNeeded = true; - } - if (auto *L = dyn_cast<Lazy>(S)) { + SS->getFile<ELFT>().IsNeeded = true; + + if (S->isLazy()) { // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. - if (Binding == STB_WEAK) - L->Type = Type; - else if (InputFile *F = L->fetch()) - addFile<ELFT>(F); + if (Binding == STB_WEAK) { + S->Type = Type; + return S; + } + + // Do extra check for --warn-backrefs. + // + // --warn-backrefs is an option to prevent an undefined reference from + // fetching an archive member written earlier in the command line. It can be + // used to keep compatibility with GNU linkers to some degree. + // I'll explain the feature and why you may find it useful in this comment. + // + // lld's symbol resolution semantics is more relaxed than traditional Unix + // linkers. For example, + // + // ld.lld foo.a bar.o + // + // succeeds even if bar.o contains an undefined symbol that has to be + // resolved by some object file in foo.a. Traditional Unix linkers don't + // allow this kind of backward reference, as they visit each file only once + // from left to right in the command line while resolving all undefined + // symbols at the moment of visiting. + // + // In the above case, since there's no undefined symbol when a linker visits + // foo.a, no files are pulled out from foo.a, and because the linker forgets + // about foo.a after visiting, it can't resolve undefined symbols in bar.o + // that could have been resolved otherwise. + // + // That lld accepts more relaxed form means that (besides it'd make more + // sense) you can accidentally write a command line or a build file that + // works only with lld, even if you have a plan to distribute it to wider + // users who may be using GNU linkers. With --warn-backrefs, you can detect + // a library order that doesn't work with other Unix linkers. + // + // The option is also useful to detect cyclic dependencies between static + // archives. Again, lld accepts + // + // ld.lld foo.a bar.a + // + // even if foo.a and bar.a depend on each other. With --warn-backrefs, it is + // handled as an error. + // + // Here is how the option works. We assign a group ID to each file. A file + // with a smaller group ID can pull out object files from an archive file + // with an equal or greater group ID. Otherwise, it is a reverse dependency + // and an error. + // + // A file outside --{start,end}-group gets a fresh ID when instantiated. All + // files within the same --{start,end}-group get the same group ID. E.g. + // + // ld.lld A B --start-group C D --end-group E + // + // A forms group 0. B form group 1. C and D (including their member object + // files) form group 2. E forms group 3. I think that you can see how this + // group assignment rule simulates the traditional linker's semantics. + bool Backref = + Config->WarnBackrefs && File && S->File->GroupId < File->GroupId; + fetchLazy<ELFT>(S); + + // We don't report backward references to weak symbols as they can be + // overridden later. + if (Backref && S->Binding != STB_WEAK) + warn("backward reference detected: " + Name + " in " + toString(File) + + " refers to " + toString(S->File)); } return S; } @@ -381,7 +452,11 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, bool WasInserted; std::tie(S, WasInserted) = insert(N, Type, getVisibility(StOther), /*CanOmitFromDynSym*/ false, &File); + int Cmp = compareDefined(S, WasInserted, Binding, N); + if (Cmp < 0) + return S; + if (Cmp > 0) { auto *Bss = make<BssSection>("COMMON", Size, Alignment); Bss->File = &File; @@ -389,45 +464,43 @@ Symbol *SymbolTable::addCommon(StringRef N, uint64_t Size, uint32_t Alignment, InputSections.push_back(Bss); replaceSymbol<Defined>(S, &File, N, Binding, StOther, Type, 0, Size, Bss); - } else if (Cmp == 0) { - auto *D = cast<Defined>(S); - auto *Bss = dyn_cast_or_null<BssSection>(D->Section); - if (!Bss) { - // Non-common symbols take precedence over common symbols. - if (Config->WarnCommon) - warn("common " + S->getName() + " is overridden"); - return S; - } + return S; + } + auto *D = cast<Defined>(S); + auto *Bss = dyn_cast_or_null<BssSection>(D->Section); + if (!Bss) { + // Non-common symbols take precedence over common symbols. if (Config->WarnCommon) - warn("multiple common of " + D->getName()); + warn("common " + S->getName() + " is overridden"); + return S; + } - Bss->Alignment = std::max(Bss->Alignment, Alignment); - if (Size > Bss->Size) { - D->File = Bss->File = &File; - D->Size = Bss->Size = Size; - } + if (Config->WarnCommon) + warn("multiple common of " + D->getName()); + + Bss->Alignment = std::max(Bss->Alignment, Alignment); + if (Size > Bss->Size) { + D->File = Bss->File = &File; + D->Size = Bss->Size = Size; } return S; } -static void warnOrError(const Twine &Msg) { - if (Config->AllowMultipleDefinition) - warn(Msg); - else - error(Msg); -} - static void reportDuplicate(Symbol *Sym, InputFile *NewFile) { - warnOrError("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + - toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); + if (!Config->AllowMultipleDefinition) + error("duplicate symbol: " + toString(*Sym) + "\n>>> defined in " + + toString(Sym->File) + "\n>>> defined in " + toString(NewFile)); } -static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, - uint64_t ErrOffset) { +static void reportDuplicate(Symbol *Sym, InputFile *NewFile, + InputSectionBase *ErrSec, uint64_t ErrOffset) { + if (Config->AllowMultipleDefinition) + return; + Defined *D = cast<Defined>(Sym); if (!D->Section || !ErrSec) { - reportDuplicate(Sym, ErrSec ? ErrSec->File : nullptr); + reportDuplicate(Sym, NewFile); return; } @@ -451,7 +524,7 @@ static void reportDuplicate(Symbol *Sym, InputSectionBase *ErrSec, if (!Src2.empty()) Msg += Src2 + "\n>>> "; Msg += Obj2; - warnOrError(Msg); + error(Msg); } Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, @@ -467,7 +540,8 @@ Symbol *SymbolTable::addRegular(StringRef Name, uint8_t StOther, uint8_t Type, replaceSymbol<Defined>(S, File, Name, Binding, StOther, Type, Value, Size, Section); else if (Cmp == 0) - reportDuplicate(S, dyn_cast_or_null<InputSectionBase>(Section), Value); + reportDuplicate(S, File, dyn_cast_or_null<InputSectionBase>(Section), + Value); return S; } @@ -488,15 +562,16 @@ void SymbolTable::addShared(StringRef Name, SharedFile<ELFT> &File, // An undefined symbol with non default visibility must be satisfied // in the same DSO. - if (WasInserted || ((S->isUndefined() || S->isLazy()) && - S->getVisibility() == STV_DEFAULT)) { + if (WasInserted || + ((S->isUndefined() || S->isLazy()) && S->Visibility == STV_DEFAULT)) { uint8_t Binding = S->Binding; + bool WasUndefined = S->isUndefined(); replaceSymbol<SharedSymbol>(S, File, Name, Sym.getBinding(), Sym.st_other, Sym.getType(), Sym.st_value, Sym.st_size, Alignment, VerdefIndex); if (!WasInserted) { S->Binding = Binding; - if (!S->isWeak() && !Config->GcSections) + if (!S->isWeak() && !Config->GcSections && WasUndefined) File.IsNeeded = true; } } @@ -527,85 +602,58 @@ Symbol *SymbolTable::find(StringRef Name) { return SymVector[It->second]; } -template <class ELFT> -Symbol *SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F, - const object::Archive::Symbol Sym) { +// This is used to handle lazy symbols. May replace existent +// symbol with lazy version or request to Fetch it. +template <class ELFT, typename LazyT, typename... ArgT> +static void replaceOrFetchLazy(StringRef Name, InputFile &File, + llvm::function_ref<InputFile *()> Fetch, + ArgT &&... Arg) { Symbol *S; bool WasInserted; - std::tie(S, WasInserted) = insert(Name); + std::tie(S, WasInserted) = Symtab->insert(Name); if (WasInserted) { - replaceSymbol<LazyArchive>(S, F, Sym, Symbol::UnknownType); - return S; + replaceSymbol<LazyT>(S, File, Symbol::UnknownType, + std::forward<ArgT>(Arg)...); + return; } if (!S->isUndefined()) - return S; + return; // An undefined weak will not fetch archive members. See comment on Lazy in // Symbols.h for the details. if (S->isWeak()) { - replaceSymbol<LazyArchive>(S, F, Sym, S->Type); + replaceSymbol<LazyT>(S, File, S->Type, std::forward<ArgT>(Arg)...); S->Binding = STB_WEAK; - return S; + return; } - std::pair<MemoryBufferRef, uint64_t> MBInfo = F.getMember(&Sym); - if (!MBInfo.first.getBuffer().empty()) - addFile<ELFT>(createObjectFile(MBInfo.first, F.getName(), MBInfo.second)); - return S; + + if (InputFile *F = Fetch()) + Symtab->addFile<ELFT>(F); } template <class ELFT> -void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { - Symbol *S; - bool WasInserted; - std::tie(S, WasInserted) = insert(Name); - if (WasInserted) { - replaceSymbol<LazyObject>(S, Obj, Name, Symbol::UnknownType); - return; - } - if (!S->isUndefined()) - return; - - // See comment for addLazyArchive above. - if (S->isWeak()) - replaceSymbol<LazyObject>(S, Obj, Name, S->Type); - else if (InputFile *F = Obj.fetch()) - addFile<ELFT>(F); -} - -// If we already saw this symbol, force loading its file. -template <class ELFT> void SymbolTable::fetchIfLazy(StringRef Name) { - if (Symbol *B = find(Name)) { - // Mark the symbol not to be eliminated by LTO - // even if it is a bitcode symbol. - B->IsUsedInRegularObj = true; - if (auto *L = dyn_cast<Lazy>(B)) - if (InputFile *File = L->fetch()) - addFile<ELFT>(File); - } +void SymbolTable::addLazyArchive(StringRef Name, ArchiveFile &F, + const object::Archive::Symbol Sym) { + replaceOrFetchLazy<ELFT, LazyArchive>(Name, F, [&]() { return F.fetch(Sym); }, + Sym); } -// This function takes care of the case in which shared libraries depend on -// the user program (not the other way, which is usual). Shared libraries -// may have undefined symbols, expecting that the user program provides -// the definitions for them. An example is BSD's __progname symbol. -// We need to put such symbols to the main program's .dynsym so that -// shared libraries can find them. -// Except this, we ignore undefined symbols in DSOs. -template <class ELFT> void SymbolTable::scanShlibUndefined() { - for (InputFile *F : SharedFiles) { - for (StringRef U : cast<SharedFile<ELFT>>(F)->getUndefinedSymbols()) { - Symbol *Sym = find(U); - if (!Sym || !Sym->isDefined()) - continue; - Sym->ExportDynamic = true; +template <class ELFT> +void SymbolTable::addLazyObject(StringRef Name, LazyObjFile &Obj) { + replaceOrFetchLazy<ELFT, LazyObject>(Name, Obj, [&]() { return Obj.fetch(); }, + Name); +} - // If -dynamic-list is given, the default version is set to - // VER_NDX_LOCAL, which prevents a symbol to be exported via .dynsym. - // Set to VER_NDX_GLOBAL so the symbol will be handled as if it were - // specified by -dynamic-list. - Sym->VersionId = VER_NDX_GLOBAL; - } +template <class ELFT> void SymbolTable::fetchLazy(Symbol *Sym) { + if (auto *S = dyn_cast<LazyArchive>(Sym)) { + if (InputFile *File = S->fetch()) + addFile<ELFT>(File); + return; } + + auto *S = cast<LazyObject>(Sym); + if (InputFile *File = cast<LazyObjFile>(S->File)->fetch()) + addFile<ELFT>(File); } // Initialize DemangledSyms with a map from demangled symbols to symbol @@ -704,7 +752,7 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, // Get a list of symbols which we need to assign the version to. std::vector<Symbol *> Syms = findByVersion(Ver); if (Syms.empty()) { - if (Config->NoUndefinedVersion) + if (!Config->UndefinedVersion) error("version script assignment of '" + VersionName + "' to symbol '" + Ver.Name + "' failed: symbol not defined"); return; @@ -718,10 +766,10 @@ void SymbolTable::assignExactVersion(SymbolVersion Ver, uint16_t VersionId, if (Sym->getName().contains('@')) continue; - if (Sym->InVersionScript) - warn("duplicate symbol '" + Ver.Name + "' in version script"); + if (Sym->VersionId != Config->DefaultSymbolVersion && + Sym->VersionId != VersionId) + error("duplicate symbol '" + Ver.Name + "' in version script"); Sym->VersionId = VersionId; - Sym->InVersionScript = true; } } @@ -769,6 +817,11 @@ void SymbolTable::scanVersionScript() { Sym->parseSymbolVersion(); } +template void SymbolTable::addFile<ELF32LE>(InputFile *); +template void SymbolTable::addFile<ELF32BE>(InputFile *); +template void SymbolTable::addFile<ELF64LE>(InputFile *); +template void SymbolTable::addFile<ELF64BE>(InputFile *); + template void SymbolTable::addSymbolWrap<ELF32LE>(StringRef); template void SymbolTable::addSymbolWrap<ELF32BE>(StringRef); template void SymbolTable::addSymbolWrap<ELF64LE>(StringRef); @@ -793,16 +846,16 @@ template void SymbolTable::addCombinedLTOObject<ELF32BE>(); template void SymbolTable::addCombinedLTOObject<ELF64LE>(); template void SymbolTable::addCombinedLTOObject<ELF64BE>(); -template Symbol * +template void SymbolTable::addLazyArchive<ELF32LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); -template Symbol * +template void SymbolTable::addLazyArchive<ELF32BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); -template Symbol * +template void SymbolTable::addLazyArchive<ELF64LE>(StringRef, ArchiveFile &, const object::Archive::Symbol); -template Symbol * +template void SymbolTable::addLazyArchive<ELF64BE>(StringRef, ArchiveFile &, const object::Archive::Symbol); @@ -811,6 +864,11 @@ template void SymbolTable::addLazyObject<ELF32BE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64LE>(StringRef, LazyObjFile &); template void SymbolTable::addLazyObject<ELF64BE>(StringRef, LazyObjFile &); +template void SymbolTable::fetchLazy<ELF32LE>(Symbol *); +template void SymbolTable::fetchLazy<ELF32BE>(Symbol *); +template void SymbolTable::fetchLazy<ELF64LE>(Symbol *); +template void SymbolTable::fetchLazy<ELF64BE>(Symbol *); + template void SymbolTable::addShared<ELF32LE>(StringRef, SharedFile<ELF32LE> &, const typename ELF32LE::Sym &, uint32_t Alignment, uint32_t); @@ -823,13 +881,3 @@ template void SymbolTable::addShared<ELF64LE>(StringRef, SharedFile<ELF64LE> &, template void SymbolTable::addShared<ELF64BE>(StringRef, SharedFile<ELF64BE> &, const typename ELF64BE::Sym &, uint32_t Alignment, uint32_t); - -template void SymbolTable::fetchIfLazy<ELF32LE>(StringRef); -template void SymbolTable::fetchIfLazy<ELF32BE>(StringRef); -template void SymbolTable::fetchIfLazy<ELF64LE>(StringRef); -template void SymbolTable::fetchIfLazy<ELF64BE>(StringRef); - -template void SymbolTable::scanShlibUndefined<ELF32LE>(); -template void SymbolTable::scanShlibUndefined<ELF32BE>(); -template void SymbolTable::scanShlibUndefined<ELF64LE>(); -template void SymbolTable::scanShlibUndefined<ELF64BE>(); diff --git a/ELF/SymbolTable.h b/ELF/SymbolTable.h index e7341b05baf5..5e6d44dfe4f9 100644 --- a/ELF/SymbolTable.h +++ b/ELF/SymbolTable.h @@ -12,7 +12,7 @@ #include "InputFiles.h" #include "LTO.h" -#include "Strings.h" +#include "lld/Common/Strings.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseMap.h" @@ -60,8 +60,8 @@ public: uint32_t VerdefIndex); template <class ELFT> - Symbol *addLazyArchive(StringRef Name, ArchiveFile &F, - const llvm::object::Archive::Symbol S); + void addLazyArchive(StringRef Name, ArchiveFile &F, + const llvm::object::Archive::Symbol S); template <class ELFT> void addLazyObject(StringRef Name, LazyObjFile &Obj); @@ -77,8 +77,8 @@ public: uint8_t Visibility, bool CanOmitFromDynSym, InputFile *File); - template <class ELFT> void fetchIfLazy(StringRef Name); - template <class ELFT> void scanShlibUndefined(); + template <class ELFT> void fetchLazy(Symbol *Sym); + void scanVersionScript(); Symbol *find(StringRef Name); @@ -90,7 +90,6 @@ public: private: std::vector<Symbol *> findByVersion(SymbolVersion Ver); std::vector<Symbol *> findAllByVersion(SymbolVersion Ver); - void defsym(Symbol *Dst, Symbol *Src); llvm::StringMap<std::vector<Symbol *>> &getDemangledSyms(); void handleAnonymousVersion(); diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index 13a91aab80bb..4243cb1e80ef 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -14,7 +14,6 @@ #include "SyntheticSections.h" #include "Target.h" #include "Writer.h" - #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" #include "llvm/ADT/STLExtras.h" @@ -39,6 +38,7 @@ Defined *ElfSym::GlobalOffsetTable; Defined *ElfSym::MipsGp; Defined *ElfSym::MipsGpDisp; Defined *ElfSym::MipsLocalGp; +Defined *ElfSym::RelaIpltEnd; static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { switch (Sym.kind()) { @@ -58,6 +58,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { return D.Value; IS = IS->Repl; + uint64_t Offset = D.Value; // An object in an SHF_MERGE section might be referenced via a @@ -76,8 +77,6 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { Addend = 0; } - const OutputSection *OutSec = IS->getOutputSection(); - // In the typical case, this is actually very simple and boils // down to adding together 3 numbers: // 1. The address of the output section. @@ -88,7 +87,7 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { // If you understand the data structures involved with this next // line (and how they get built), then you have a pretty good // understanding of the linker. - uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset); + uint64_t VA = IS->getVA(Offset); if (D.isTls() && !Config->Relocatable) { if (!Out::TlsPhdr) @@ -98,20 +97,12 @@ static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { } return VA; } - case Symbol::SharedKind: { - auto &SS = cast<SharedSymbol>(Sym); - if (SS.CopyRelSec) - return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff; - if (SS.NeedsPltAddr) - return Sym.getPltVA(); - return 0; - } + case Symbol::SharedKind: case Symbol::UndefinedKind: return 0; case Symbol::LazyArchiveKind: case Symbol::LazyObjectKind: - assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer"); - return 0; + llvm_unreachable("lazy symbol reached writer"); } llvm_unreachable("invalid symbol kind"); } @@ -134,22 +125,26 @@ uint64_t Symbol::getGotPltVA() const { } uint64_t Symbol::getGotPltOffset() const { - return GotPltIndex * Target->GotPltEntrySize; + if (IsInIgot) + return PltIndex * Target->GotPltEntrySize; + return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize; } uint64_t Symbol::getPltVA() const { if (this->IsInIplt) return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize; - return InX::Plt->getVA() + Target->PltHeaderSize + - PltIndex * Target->PltEntrySize; + return InX::Plt->getVA() + Target->getPltEntryOffset(PltIndex); +} + +uint64_t Symbol::getPltOffset() const { + assert(!this->IsInIplt); + return Target->getPltEntryOffset(PltIndex); } uint64_t Symbol::getSize() const { if (const auto *DR = dyn_cast<Defined>(this)) return DR->Size; - if (const auto *S = dyn_cast<SharedSymbol>(this)) - return S->Size; - return 0; + return cast<SharedSymbol>(this)->Size; } OutputSection *Symbol::getOutputSection() const { @@ -158,13 +153,6 @@ OutputSection *Symbol::getOutputSection() const { return Sec->Repl->getOutputSection(); return nullptr; } - - if (auto *S = dyn_cast<SharedSymbol>(this)) { - if (S->CopyRelSec) - return S->CopyRelSec->getParent(); - return nullptr; - } - return nullptr; } @@ -180,7 +168,7 @@ void Symbol::parseSymbolVersion() { return; // Truncate the symbol name so that it doesn't include the version string. - Name = {S.data(), Pos}; + NameSize = Pos; // If this is not in this DSO, it is not a definition. if (!isDefined()) @@ -206,33 +194,15 @@ void Symbol::parseSymbolVersion() { // It is an error if the specified version is not defined. // Usually version script is not provided when linking executable, // but we may still want to override a versioned symbol from DSO, - // so we do not report error in this case. - if (Config->Shared) + // so we do not report error in this case. We also do not error + // if the symbol has a local version as it won't be in the dynamic + // symbol table. + if (Config->Shared && VersionId != VER_NDX_LOCAL) error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); } -InputFile *Lazy::fetch() { - if (auto *S = dyn_cast<LazyArchive>(this)) - return S->fetch(); - return cast<LazyObject>(this)->fetch(); -} - -ArchiveFile &LazyArchive::getFile() { return *cast<ArchiveFile>(File); } - -InputFile *LazyArchive::fetch() { - std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile().getMember(&Sym); - - // getMember returns an empty buffer if the member was already - // read from the library. - if (MBInfo.first.getBuffer().empty()) - return nullptr; - return createObjectFile(MBInfo.first, getFile().getName(), MBInfo.second); -} - -LazyObjFile &LazyObject::getFile() { return *cast<LazyObjFile>(File); } - -InputFile *LazyObject::fetch() { return getFile().fetch(); } +InputFile *LazyArchive::fetch() { return cast<ArchiveFile>(File)->fetch(Sym); } uint8_t Symbol::computeBinding() const { if (Config->Relocatable) @@ -241,7 +211,7 @@ uint8_t Symbol::computeBinding() const { return STB_LOCAL; if (VersionId == VER_NDX_LOCAL && isDefined()) return STB_LOCAL; - if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE) + if (!Config->GnuUnique && Binding == STB_GNU_UNIQUE) return STB_GLOBAL; return Binding; } @@ -273,6 +243,27 @@ void elf::printTraceSymbol(Symbol *Sym) { message(toString(Sym->File) + S + Sym->getName()); } +void elf::warnUnorderableSymbol(const Symbol *Sym) { + if (!Config->WarnSymbolOrdering) + return; + + const InputFile *File = Sym->File; + auto *D = dyn_cast<Defined>(Sym); + + auto Warn = [&](StringRef S) { warn(toString(File) + S + Sym->getName()); }; + + if (Sym->isUndefined()) + Warn(": unable to order undefined symbol: "); + else if (Sym->isShared()) + Warn(": unable to order shared symbol: "); + else if (D && !D->Section) + Warn(": unable to order absolute symbol: "); + else if (D && isa<OutputSection>(D->Section)) + Warn(": unable to order synthetic symbol: "); + else if (D && !D->Section->Repl->Live) + Warn(": unable to order discarded symbol: "); +} + // Returns a symbol for an error message. std::string lld::toString(const Symbol &B) { if (Config->Demangle) diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 9b7207383345..8c9513b9368b 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -7,8 +7,7 @@ // //===----------------------------------------------------------------------===// // -// All symbols are handled as SymbolBodies regardless of their types. -// This file defines various types of SymbolBodies. +// This file defines various types of Symbols. // //===----------------------------------------------------------------------===// @@ -16,9 +15,8 @@ #define LLD_ELF_SYMBOLS_H #include "InputSection.h" -#include "Strings.h" - #include "lld/Common/LLVM.h" +#include "lld/Common/Strings.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ELF.h" @@ -34,6 +32,20 @@ template <class ELFT> class ObjFile; class OutputSection; template <class ELFT> class SharedFile; +// This is a StringRef-like container that doesn't run strlen(). +// +// ELF string tables contain a lot of null-terminated strings. Most of them +// are not necessary for the linker because they are names of local symbols, +// and the linker doesn't use local symbol names for name resolution. So, we +// use this class to represents strings read from string tables. +struct StringRefZ { + StringRefZ(const char *S) : Data(S), Size(-1) {} + StringRefZ(StringRef S) : Data(S.data()), Size(S.size()) {} + + const char *Data; + const uint32_t Size; +}; + // The base class for real symbol classes. class Symbol { public: @@ -47,6 +59,25 @@ public: Kind kind() const { return static_cast<Kind>(SymbolKind); } + // The file from which this symbol was created. + InputFile *File; + +protected: + const char *NameData; + mutable uint32_t NameSize; + +public: + uint32_t DynsymIndex = 0; + uint32_t GotIndex = -1; + uint32_t PltIndex = -1; + uint32_t GlobalDynIndex = -1; + + // This field is a index to the symbol's version definition. + uint32_t VerdefIndex = -1; + + // Version definition index. + uint16_t VersionId; + // Symbol binding. This is not overwritten by replaceSymbol to track // changes during resolution. In particular: // - An undefined weak is still weak when it resolves to a shared library. @@ -54,8 +85,11 @@ public: // remember it is weak. uint8_t Binding; - // Version definition index. - uint16_t VersionId; + // The following fields have the same meaning as the ELF symbol attributes. + uint8_t Type; // symbol type + uint8_t StOther; // st_other field value + + const uint8_t SymbolKind; // Symbol visibility. This is the computed minimum visibility of all // observed non-DSO symbols. @@ -81,12 +115,6 @@ public: // True if this symbol is specified by --trace-symbol option. unsigned Traced : 1; - // This symbol version was found in a version script. - unsigned InVersionScript : 1; - - // The file from which this symbol was created. - InputFile *File; - bool includeInDynsym() const; uint8_t computeBinding() const; bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; } @@ -100,15 +128,15 @@ public: return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } - // True is this is an undefined weak symbol. This only works once - // all input files have been added. - bool isUndefWeak() const { - // See comment on Lazy the details. - return isWeak() && (isUndefined() || isLazy()); + // True if this is an undefined weak symbol. + bool isUndefWeak() const { return isWeak() && isUndefined(); } + + StringRef getName() const { + if (NameSize == (uint32_t)-1) + NameSize = strlen(NameData); + return {NameData, NameSize}; } - StringRef getName() const { return Name; } - uint8_t getVisibility() const { return StOther & 0x3; } void parseSymbolVersion(); bool isInGot() const { return GotIndex != -1U; } @@ -121,34 +149,22 @@ public: uint64_t getGotPltOffset() const; uint64_t getGotPltVA() const; uint64_t getPltVA() const; + uint64_t getPltOffset() const; uint64_t getSize() const; OutputSection *getOutputSection() const; - uint32_t DynsymIndex = 0; - uint32_t GotIndex = -1; - uint32_t GotPltIndex = -1; - uint32_t PltIndex = -1; - uint32_t GlobalDynIndex = -1; - protected: Symbol(Kind K, InputFile *File, StringRefZ Name, uint8_t Binding, uint8_t StOther, uint8_t Type) - : Binding(Binding), File(File), SymbolKind(K), NeedsPltAddr(false), - IsInGlobalMipsGot(false), Is32BitMipsGot(false), IsInIplt(false), - IsInIgot(false), IsPreemptible(false), Used(!Config->GcSections), - Type(Type), StOther(StOther), Name(Name) {} - - const unsigned SymbolKind : 8; + : File(File), NameData(Name.Data), NameSize(Name.Size), Binding(Binding), + Type(Type), StOther(StOther), SymbolKind(K), NeedsPltAddr(false), + IsInIplt(false), IsInIgot(false), IsPreemptible(false), + Used(!Config->GcSections), NeedsTocRestore(false) {} public: // True the symbol should point to its PLT entry. // For SharedSymbol only. unsigned NeedsPltAddr : 1; - // True if this symbol has an entry in the global part of MIPS GOT. - unsigned IsInGlobalMipsGot : 1; - - // True if this symbol is referenced by 32-bit GOT relocations. - unsigned Is32BitMipsGot : 1; // True if this symbol is in the Iplt sub-section of the Plt. unsigned IsInIplt : 1; @@ -156,14 +172,15 @@ public: // True if this symbol is in the Igot sub-section of the .got.plt or .got. unsigned IsInIgot : 1; + // True if this symbol is preemptible at load time. unsigned IsPreemptible : 1; // True if an undefined or shared symbol is used from a live section. unsigned Used : 1; - // The following fields have the same meaning as the ELF symbol attributes. - uint8_t Type; // symbol type - uint8_t StOther; // st_other field value + // True if a call to this symbol needs to be followed by a restore of the + // PPC64 toc pointer. + unsigned NeedsTocRestore : 1; // The Type field may also have this value. It means that we have not yet seen // a non-Lazy symbol with this name, so we don't know what its type is. The @@ -178,9 +195,6 @@ public: bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; } bool isObject() const { return Type == llvm::ELF::STT_OBJECT; } bool isFile() const { return Type == llvm::ELF::STT_FILE; } - -protected: - StringRefZ Name; }; // Represents a symbol that is defined in the current output file. @@ -214,8 +228,9 @@ public: SharedSymbol(InputFile &File, StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type, uint64_t Value, uint64_t Size, uint32_t Alignment, uint32_t VerdefIndex) - : Symbol(SharedKind, &File, Name, Binding, StOther, Type), Value(Value), - Size(Size), VerdefIndex(VerdefIndex), Alignment(Alignment) { + : Symbol(SharedKind, &File, Name, Binding, StOther, Type), + Alignment(Alignment), Value(Value), Size(Size) { + this->VerdefIndex = VerdefIndex; // GNU ifunc is a mechanism to allow user-supplied functions to // resolve PLT slot values at load-time. This is contrary to the // regular symbol resolution scheme in which symbols are resolved just @@ -240,54 +255,36 @@ public: return *cast<SharedFile<ELFT>>(File); } - // If not null, there is a copy relocation to this section. - InputSection *CopyRelSec = nullptr; + uint32_t Alignment; uint64_t Value; // st_value uint64_t Size; // st_size - - // This field is a index to the symbol's version definition. - uint32_t VerdefIndex; - - uint32_t Alignment; }; -// This represents a symbol that is not yet in the link, but we know where to -// find it if needed. If the resolver finds both Undefined and Lazy for the same -// name, it will ask the Lazy to load a file. +// LazyArchive and LazyObject represent a symbols that is not yet in the link, +// but we know where to find it if needed. If the resolver finds both Undefined +// and Lazy for the same name, it will ask the Lazy to load a file. // // A special complication is the handling of weak undefined symbols. They should // not load a file, but we have to remember we have seen both the weak undefined // and the lazy. We represent that with a lazy symbol with a weak binding. This // means that code looking for undefined symbols normally also has to take lazy // symbols into consideration. -class Lazy : public Symbol { -public: - static bool classof(const Symbol *S) { return S->isLazy(); } - - // Returns an object file for this symbol, or a nullptr if the file - // was already returned. - InputFile *fetch(); - -protected: - Lazy(Kind K, InputFile &File, StringRef Name, uint8_t Type) - : Symbol(K, &File, Name, llvm::ELF::STB_GLOBAL, llvm::ELF::STV_DEFAULT, - Type) {} -}; // This class represents a symbol defined in an archive file. It is // created from an archive file header, and it knows how to load an // object file from an archive to replace itself with a defined // symbol. -class LazyArchive : public Lazy { +class LazyArchive : public Symbol { public: - LazyArchive(InputFile &File, const llvm::object::Archive::Symbol S, - uint8_t Type) - : Lazy(LazyArchiveKind, File, S.getName(), Type), Sym(S) {} + LazyArchive(InputFile &File, uint8_t Type, + const llvm::object::Archive::Symbol S) + : Symbol(LazyArchiveKind, &File, S.getName(), llvm::ELF::STB_GLOBAL, + llvm::ELF::STV_DEFAULT, Type), + Sym(S) {} static bool classof(const Symbol *S) { return S->kind() == LazyArchiveKind; } - ArchiveFile &getFile(); InputFile *fetch(); private: @@ -296,15 +293,13 @@ private: // LazyObject symbols represents symbols in object files between // --start-lib and --end-lib options. -class LazyObject : public Lazy { +class LazyObject : public Symbol { public: - LazyObject(InputFile &File, StringRef Name, uint8_t Type) - : Lazy(LazyObjectKind, File, Name, Type) {} + LazyObject(InputFile &File, uint8_t Type, StringRef Name) + : Symbol(LazyObjectKind, &File, Name, llvm::ELF::STB_GLOBAL, + llvm::ELF::STV_DEFAULT, Type) {} static bool classof(const Symbol *S) { return S->kind() == LazyObjectKind; } - - LazyObjFile &getFile(); - InputFile *fetch(); }; // Some linker-generated symbols need to be created as @@ -334,6 +329,9 @@ struct ElfSym { static Defined *MipsGp; static Defined *MipsGpDisp; static Defined *MipsLocalGp; + + // __rela_iplt_end or __rel_iplt_end + static Defined *RelaIpltEnd; }; // A buffer class that is large enough to hold any Symbol-derived @@ -351,6 +349,8 @@ void printTraceSymbol(Symbol *Sym); template <typename T, typename... ArgT> void replaceSymbol(Symbol *S, ArgT &&... Arg) { + static_assert(std::is_trivially_destructible<T>(), + "Symbol types must be trivially destructible"); static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small"); static_assert(alignof(T) <= alignof(SymbolUnion), "SymbolUnion not aligned enough"); @@ -367,13 +367,14 @@ void replaceSymbol(Symbol *S, ArgT &&... Arg) { S->ExportDynamic = Sym.ExportDynamic; S->CanInline = Sym.CanInline; S->Traced = Sym.Traced; - S->InVersionScript = Sym.InVersionScript; // Print out a log message if --trace-symbol was specified. // This is for debugging. if (S->Traced) printTraceSymbol(S); } + +void warnUnorderableSymbol(const Symbol *Sym); } // namespace elf std::string toString(const elf::Symbol &B); diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index a5e291b79a4d..38859e1650bf 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -20,15 +20,16 @@ #include "InputFiles.h" #include "LinkerScript.h" #include "OutputSections.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "Target.h" #include "Writer.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h" #include "llvm/Object/Decompressor.h" @@ -47,27 +48,20 @@ using namespace llvm::dwarf; using namespace llvm::ELF; using namespace llvm::object; using namespace llvm::support; -using namespace llvm::support::endian; using namespace lld; using namespace lld::elf; -constexpr size_t MergeNoTailSection::NumShards; - -static void write32(void *Buf, uint32_t Val) { - endian::write32(Buf, Val, Config->Endianness); -} +using llvm::support::endian::read32le; +using llvm::support::endian::write32le; +using llvm::support::endian::write64le; -uint64_t SyntheticSection::getVA() const { - if (OutputSection *Sec = getParent()) - return Sec->Addr + OutSecOff; - return 0; -} +constexpr size_t MergeNoTailSection::NumShards; // Returns an LLD version string. static ArrayRef<uint8_t> getVersion() { // Check LLD_VERSION first for ease of testing. - // You can get consitent output by using the environment variable. + // You can get consistent output by using the environment variable. // This is only for testing. StringRef S = getenv("LLD_VERSION"); if (S.empty()) @@ -192,8 +186,6 @@ MipsOptionsSection<ELFT> *MipsOptionsSection<ELFT>::create() { auto *Opt = reinterpret_cast<const Elf_Mips_Options *>(D.data()); if (Opt->kind == ODK_REGINFO) { - if (Config->Relocatable && Opt->getRegInfo().ri_gp_value) - error(Filename + ": unsupported non-zero ri_gp_value"); Reginfo.ri_gprmask |= Opt->getRegInfo().ri_gprmask; Sec->getFile<ELFT>()->MipsGp0 = Opt->getRegInfo().ri_gp_value; break; @@ -244,10 +236,8 @@ MipsReginfoSection<ELFT> *MipsReginfoSection<ELFT>::create() { error(toString(Sec->File) + ": invalid size of .reginfo section"); return nullptr; } - auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data()); - if (Config->Relocatable && R->ri_gp_value) - error(toString(Sec->File) + ": unsupported non-zero ri_gp_value"); + auto *R = reinterpret_cast<const Elf_Mips_RegInfo *>(Sec->Data.data()); Reginfo.ri_gprmask |= R->ri_gprmask; Sec->getFile<ELFT>()->MipsGp0 = R->ri_gp_value; }; @@ -266,8 +256,8 @@ InputSection *elf::createInterpSection() { return Sec; } -Symbol *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase &Section) { +Defined *elf::addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase &Section) { auto *S = make<Defined>(Section.File, Name, STB_LOCAL, STV_DEFAULT, Type, Value, Size, &Section); if (InX::SymTab) @@ -338,8 +328,6 @@ void BuildIdSection::computeHash( BssSection::BssSection(StringRef Name, uint64_t Size, uint32_t Alignment) : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_NOBITS, Alignment, Name) { this->Bss = true; - if (OutputSection *Sec = getParent()) - Sec->Alignment = std::max(Sec->Alignment, Alignment); this->Size = Size; } @@ -380,15 +368,11 @@ EhFrameSection::EhFrameSection() // and where their relocations point to. template <class ELFT, class RelTy> CieRecord *EhFrameSection::addCie(EhSectionPiece &Cie, ArrayRef<RelTy> Rels) { - auto *Sec = cast<EhInputSection>(Cie.Sec); - if (read32(Cie.data().data() + 4, Config->Endianness) != 0) - fatal(toString(Sec) + ": CIE expected at beginning of .eh_frame"); - Symbol *Personality = nullptr; unsigned FirstRelI = Cie.FirstRelocation; if (FirstRelI != (unsigned)-1) Personality = - &Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); + &Cie.Sec->template getFile<ELFT>()->getRelocTargetSym(Rels[FirstRelI]); // Search for an existing CIE by CIE contents/relocation target pair. CieRecord *&Rec = CieMap[{Cie.data(), Personality}]; @@ -433,14 +417,14 @@ bool EhFrameSection::isFdeLive(EhSectionPiece &Fde, ArrayRef<RelTy> Rels) { // one and associates FDEs to the CIE. template <class ELFT, class RelTy> void EhFrameSection::addSectionAux(EhInputSection *Sec, ArrayRef<RelTy> Rels) { - DenseMap<size_t, CieRecord *> OffsetToCie; + OffsetToCie.clear(); for (EhSectionPiece &Piece : Sec->Pieces) { // The empty record is the end marker. if (Piece.Size == 4) return; size_t Offset = Piece.InputOff; - uint32_t ID = read32(Piece.data().data() + 4, Config->Endianness); + uint32_t ID = read32(Piece.data().data() + 4); if (ID == 0) { OffsetToCie[Offset] = addCie<ELFT>(Piece, Rels); continue; @@ -468,10 +452,6 @@ template <class ELFT> void EhFrameSection::addSection(InputSectionBase *C) { for (auto *DS : Sec->DependentSections) DependentSections.push_back(DS); - // .eh_frame is a sequence of CIE or FDE records. This function - // splits it into pieces so that we can call - // SplitInputSection::getSectionPiece on the section. - Sec->split<ELFT>(); if (Sec->Pieces.empty()) return; @@ -494,9 +474,7 @@ static void writeCieFde(uint8_t *Buf, ArrayRef<uint8_t> D) { } void EhFrameSection::finalizeContents() { - if (this->Size) - return; // Already finalized. - + assert(!this->Size); // Not finalized. size_t Off = 0; for (CieRecord *Rec : CieRecords) { Rec->Cie->OutputOff = Off; @@ -509,10 +487,10 @@ void EhFrameSection::finalizeContents() { } // The LSB standard does not allow a .eh_frame section with zero - // Call Frame Information records. Therefore add a CIE record length - // 0 as a terminator if this .eh_frame section is empty. - if (Off == 0) - Off = 4; + // Call Frame Information records. glibc unwind-dw2-fde.c + // classify_object_over_fdes expects there is a CIE record length 0 as a + // terminator. Thus we add one unconditionally. + Off += 4; this->Size = Off; } @@ -524,25 +502,47 @@ std::vector<EhFrameSection::FdeData> EhFrameSection::getFdeData() const { uint8_t *Buf = getParent()->Loc + OutSecOff; std::vector<FdeData> Ret; + uint64_t VA = InX::EhFrameHdr->getVA(); for (CieRecord *Rec : CieRecords) { uint8_t Enc = getFdeEncoding(Rec->Cie); for (EhSectionPiece *Fde : Rec->Fdes) { - uint32_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); - uint32_t FdeVA = getParent()->Addr + Fde->OutputOff; - Ret.push_back({Pc, FdeVA}); + uint64_t Pc = getFdePc(Buf, Fde->OutputOff, Enc); + uint64_t FdeVA = getParent()->Addr + Fde->OutputOff; + if (!isInt<32>(Pc - VA)) + fatal(toString(Fde->Sec) + ": PC offset is too large: 0x" + + Twine::utohexstr(Pc - VA)); + Ret.push_back({uint32_t(Pc - VA), uint32_t(FdeVA - VA)}); } } + + // Sort the FDE list by their PC and uniqueify. Usually there is only + // one FDE for a PC (i.e. function), but if ICF merges two functions + // into one, there can be more than one FDEs pointing to the address. + auto Less = [](const FdeData &A, const FdeData &B) { + return A.PcRel < B.PcRel; + }; + std::stable_sort(Ret.begin(), Ret.end(), Less); + auto Eq = [](const FdeData &A, const FdeData &B) { + return A.PcRel == B.PcRel; + }; + Ret.erase(std::unique(Ret.begin(), Ret.end(), Eq), Ret.end()); + return Ret; } static uint64_t readFdeAddr(uint8_t *Buf, int Size) { switch (Size) { case DW_EH_PE_udata2: - return read16(Buf, Config->Endianness); + return read16(Buf); + case DW_EH_PE_sdata2: + return (int16_t)read16(Buf); case DW_EH_PE_udata4: - return read32(Buf, Config->Endianness); + return read32(Buf); + case DW_EH_PE_sdata4: + return (int32_t)read32(Buf); case DW_EH_PE_udata8: - return read64(Buf, Config->Endianness); + case DW_EH_PE_sdata8: + return read64(Buf); case DW_EH_PE_absptr: return readUint(Buf); } @@ -556,7 +556,7 @@ uint64_t EhFrameSection::getFdePc(uint8_t *Buf, size_t FdeOff, // The starting address to which this FDE applies is // stored at FDE + 8 byte. size_t Off = FdeOff + 8; - uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0x7); + uint64_t Addr = readFdeAddr(Buf + Off, Enc & 0xf); if ((Enc & 0x70) == DW_EH_PE_absptr) return Addr; if ((Enc & 0x70) == DW_EH_PE_pcrel) @@ -589,7 +589,15 @@ void EhFrameSection::writeTo(uint8_t *Buf) { GotSection::GotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotEntrySize, ".got") {} + Target->GotEntrySize, ".got") { + // PPC64 saves the ElfSym::GlobalOffsetTable .TOC. as the first entry in the + // .got. If there are no references to .TOC. in the symbol table, + // ElfSym::GlobalOffsetTable will not be defined and we won't need to save + // .TOC. in the .got. When it is defined, we increase NumEntries by the number + // of entries used to emit ElfSym::GlobalOffsetTable. + if (ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt) + NumEntries += Target->GotHeaderEntriesNum; +} void GotSection::addEntry(Symbol &Sym) { Sym.GotIndex = NumEntries; @@ -623,196 +631,383 @@ uint64_t GotSection::getGlobalDynOffset(const Symbol &B) const { return B.GlobalDynIndex * Config->Wordsize; } -void GotSection::finalizeContents() { Size = NumEntries * Config->Wordsize; } +void GotSection::finalizeContents() { + Size = NumEntries * Config->Wordsize; +} bool GotSection::empty() const { // We need to emit a GOT even if it's empty if there's a relocation that is // relative to GOT(such as GOTOFFREL) or there's a symbol that points to a GOT - // (i.e. _GLOBAL_OFFSET_TABLE_). - return NumEntries == 0 && !HasGotOffRel && !ElfSym::GlobalOffsetTable; + // (i.e. _GLOBAL_OFFSET_TABLE_) that the target defines relative to the .got. + return NumEntries == 0 && !HasGotOffRel && + !(ElfSym::GlobalOffsetTable && !Target->GotBaseSymInGotPlt); } void GotSection::writeTo(uint8_t *Buf) { // Buf points to the start of this section's buffer, // whereas InputSectionBase::relocateAlloc() expects its argument // to point to the start of the output section. + Target->writeGotHeader(Buf); relocateAlloc(Buf - OutSecOff, Buf - OutSecOff + Size); } +static uint64_t getMipsPageAddr(uint64_t Addr) { + return (Addr + 0x8000) & ~0xffff; +} + +static uint64_t getMipsPageCount(uint64_t Size) { + return (Size + 0xfffe) / 0xffff + 1; +} + MipsGotSection::MipsGotSection() : SyntheticSection(SHF_ALLOC | SHF_WRITE | SHF_MIPS_GPREL, SHT_PROGBITS, 16, ".got") {} -void MipsGotSection::addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr) { - // For "true" local symbols which can be referenced from the same module - // only compiler creates two instructions for address loading: - // - // lw $8, 0($gp) # R_MIPS_GOT16 - // addi $8, $8, 0 # R_MIPS_LO16 - // - // The first instruction loads high 16 bits of the symbol address while - // the second adds an offset. That allows to reduce number of required - // GOT entries because only one global offset table entry is necessary - // for every 64 KBytes of local data. So for local symbols we need to - // allocate number of GOT entries to hold all required "page" addresses. - // - // All global symbols (hidden and regular) considered by compiler uniformly. - // It always generates a single `lw` instruction and R_MIPS_GOT16 relocation - // to load address of the symbol. So for each such symbol we need to - // allocate dedicated GOT entry to store its address. - // - // If a symbol is preemptible we need help of dynamic linker to get its - // final address. The corresponding GOT entries are allocated in the - // "global" part of GOT. Entries for non preemptible global symbol allocated - // in the "local" part of GOT. - // - // See "Global Offset Table" in Chapter 5: - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf +void MipsGotSection::addEntry(InputFile &File, Symbol &Sym, int64_t Addend, + RelExpr Expr) { + FileGot &G = getGot(File); if (Expr == R_MIPS_GOT_LOCAL_PAGE) { - // At this point we do not know final symbol value so to reduce number - // of allocated GOT entries do the following trick. Save all output - // sections referenced by GOT relocations. Then later in the `finalize` - // method calculate number of "pages" required to cover all saved output - // section and allocate appropriate number of GOT entries. - PageIndexMap.insert({Sym.getOutputSection(), 0}); - return; - } - if (Sym.isTls()) { - // GOT entries created for MIPS TLS relocations behave like - // almost GOT entries from other ABIs. They go to the end - // of the global offset table. - Sym.GotIndex = TlsEntries.size(); - TlsEntries.push_back(&Sym); - return; - } - auto AddEntry = [&](Symbol &S, uint64_t A, GotEntries &Items) { - if (S.isInGot() && !A) - return; - size_t NewIndex = Items.size(); - if (!EntryIndexMap.insert({{&S, A}, NewIndex}).second) - return; - Items.emplace_back(&S, A); - if (!A) - S.GotIndex = NewIndex; - }; - if (Sym.IsPreemptible) { - // Ignore addends for preemptible symbols. They got single GOT entry anyway. - AddEntry(Sym, 0, GlobalEntries); - Sym.IsInGlobalMipsGot = true; - } else if (Expr == R_MIPS_GOT_OFF32) { - AddEntry(Sym, Addend, LocalEntries32); - Sym.Is32BitMipsGot = true; - } else { - // Hold local GOT entries accessed via a 16-bit index separately. - // That allows to write them in the beginning of the GOT and keep - // their indexes as less as possible to escape relocation's overflow. - AddEntry(Sym, Addend, LocalEntries); - } + if (const OutputSection *OS = Sym.getOutputSection()) + G.PagesMap.insert({OS, {}}); + else + G.Local16.insert({{nullptr, getMipsPageAddr(Sym.getVA(Addend))}, 0}); + } else if (Sym.isTls()) + G.Tls.insert({&Sym, 0}); + else if (Sym.IsPreemptible && Expr == R_ABS) + G.Relocs.insert({&Sym, 0}); + else if (Sym.IsPreemptible) + G.Global.insert({&Sym, 0}); + else if (Expr == R_MIPS_GOT_OFF32) + G.Local32.insert({{&Sym, Addend}, 0}); + else + G.Local16.insert({{&Sym, Addend}, 0}); } -bool MipsGotSection::addDynTlsEntry(Symbol &Sym) { - if (Sym.GlobalDynIndex != -1U) - return false; - Sym.GlobalDynIndex = TlsEntries.size(); - // Global Dynamic TLS entries take two GOT slots. - TlsEntries.push_back(nullptr); - TlsEntries.push_back(&Sym); - return true; +void MipsGotSection::addDynTlsEntry(InputFile &File, Symbol &Sym) { + getGot(File).DynTlsSymbols.insert({&Sym, 0}); } -// Reserves TLS entries for a TLS module ID and a TLS block offset. -// In total it takes two GOT slots. -bool MipsGotSection::addTlsIndex() { - if (TlsIndexOff != uint32_t(-1)) - return false; - TlsIndexOff = TlsEntries.size() * Config->Wordsize; - TlsEntries.push_back(nullptr); - TlsEntries.push_back(nullptr); - return true; +void MipsGotSection::addTlsIndex(InputFile &File) { + getGot(File).DynTlsSymbols.insert({nullptr, 0}); } -static uint64_t getMipsPageAddr(uint64_t Addr) { - return (Addr + 0x8000) & ~0xffff; +size_t MipsGotSection::FileGot::getEntriesNum() const { + return getPageEntriesNum() + Local16.size() + Global.size() + Relocs.size() + + Tls.size() + DynTlsSymbols.size() * 2; } -static uint64_t getMipsPageCount(uint64_t Size) { - return (Size + 0xfffe) / 0xffff + 1; +size_t MipsGotSection::FileGot::getPageEntriesNum() const { + size_t Num = 0; + for (const std::pair<const OutputSection *, FileGot::PageBlock> &P : PagesMap) + Num += P.second.Count; + return Num; } -uint64_t MipsGotSection::getPageEntryOffset(const Symbol &B, - int64_t Addend) const { - const OutputSection *OutSec = B.getOutputSection(); - uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); - uint64_t SymAddr = getMipsPageAddr(B.getVA(Addend)); - uint64_t Index = PageIndexMap.lookup(OutSec) + (SymAddr - SecAddr) / 0xffff; - assert(Index < PageEntriesNum); - return (HeaderEntriesNum + Index) * Config->Wordsize; +size_t MipsGotSection::FileGot::getIndexedEntriesNum() const { + size_t Count = getPageEntriesNum() + Local16.size() + Global.size(); + // If there are relocation-only entries in the GOT, TLS entries + // are allocated after them. TLS entries should be addressable + // by 16-bit index so count both reloc-only and TLS entries. + if (!Tls.empty() || !DynTlsSymbols.empty()) + Count += Relocs.size() + Tls.size() + DynTlsSymbols.size() * 2; + return Count; } -uint64_t MipsGotSection::getSymEntryOffset(const Symbol &B, - int64_t Addend) const { - // Calculate offset of the GOT entries block: TLS, global, local. - uint64_t Index = HeaderEntriesNum + PageEntriesNum; - if (B.isTls()) - Index += LocalEntries.size() + LocalEntries32.size() + GlobalEntries.size(); - else if (B.IsInGlobalMipsGot) - Index += LocalEntries.size() + LocalEntries32.size(); - else if (B.Is32BitMipsGot) - Index += LocalEntries.size(); - // Calculate offset of the GOT entry in the block. - if (B.isInGot()) - Index += B.GotIndex; - else { - auto It = EntryIndexMap.find({&B, Addend}); - assert(It != EntryIndexMap.end()); - Index += It->second; +MipsGotSection::FileGot &MipsGotSection::getGot(InputFile &F) { + if (!F.MipsGotIndex.hasValue()) { + Gots.emplace_back(); + Gots.back().File = &F; + F.MipsGotIndex = Gots.size() - 1; + } + return Gots[*F.MipsGotIndex]; +} + +uint64_t MipsGotSection::getPageEntryOffset(const InputFile *F, + const Symbol &Sym, + int64_t Addend) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + uint64_t Index = 0; + if (const OutputSection *OutSec = Sym.getOutputSection()) { + uint64_t SecAddr = getMipsPageAddr(OutSec->Addr); + uint64_t SymAddr = getMipsPageAddr(Sym.getVA(Addend)); + Index = G.PagesMap.lookup(OutSec).FirstIndex + (SymAddr - SecAddr) / 0xffff; + } else { + Index = G.Local16.lookup({nullptr, getMipsPageAddr(Sym.getVA(Addend))}); } return Index * Config->Wordsize; } -uint64_t MipsGotSection::getTlsOffset() const { - return (getLocalEntriesNum() + GlobalEntries.size()) * Config->Wordsize; +uint64_t MipsGotSection::getSymEntryOffset(const InputFile *F, const Symbol &S, + int64_t Addend) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + Symbol *Sym = const_cast<Symbol *>(&S); + if (Sym->isTls()) + return G.Tls.lookup(Sym) * Config->Wordsize; + if (Sym->IsPreemptible) + return G.Global.lookup(Sym) * Config->Wordsize; + return G.Local16.lookup({Sym, Addend}) * Config->Wordsize; } -uint64_t MipsGotSection::getGlobalDynOffset(const Symbol &B) const { - return B.GlobalDynIndex * Config->Wordsize; +uint64_t MipsGotSection::getTlsIndexOffset(const InputFile *F) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + return G.DynTlsSymbols.lookup(nullptr) * Config->Wordsize; +} + +uint64_t MipsGotSection::getGlobalDynOffset(const InputFile *F, + const Symbol &S) const { + const FileGot &G = Gots[*F->MipsGotIndex]; + Symbol *Sym = const_cast<Symbol *>(&S); + return G.DynTlsSymbols.lookup(Sym) * Config->Wordsize; } const Symbol *MipsGotSection::getFirstGlobalEntry() const { - return GlobalEntries.empty() ? nullptr : GlobalEntries.front().first; + if (Gots.empty()) + return nullptr; + const FileGot &PrimGot = Gots.front(); + if (!PrimGot.Global.empty()) + return PrimGot.Global.front().first; + if (!PrimGot.Relocs.empty()) + return PrimGot.Relocs.front().first; + return nullptr; } unsigned MipsGotSection::getLocalEntriesNum() const { - return HeaderEntriesNum + PageEntriesNum + LocalEntries.size() + - LocalEntries32.size(); + if (Gots.empty()) + return HeaderEntriesNum; + return HeaderEntriesNum + Gots.front().getPageEntriesNum() + + Gots.front().Local16.size(); +} + +bool MipsGotSection::tryMergeGots(FileGot &Dst, FileGot &Src, bool IsPrimary) { + FileGot Tmp = Dst; + set_union(Tmp.PagesMap, Src.PagesMap); + set_union(Tmp.Local16, Src.Local16); + set_union(Tmp.Global, Src.Global); + set_union(Tmp.Relocs, Src.Relocs); + set_union(Tmp.Tls, Src.Tls); + set_union(Tmp.DynTlsSymbols, Src.DynTlsSymbols); + + size_t Count = IsPrimary ? HeaderEntriesNum : 0; + Count += Tmp.getIndexedEntriesNum(); + + if (Count * Config->Wordsize > Config->MipsGotSize) + return false; + + std::swap(Tmp, Dst); + return true; } void MipsGotSection::finalizeContents() { updateAllocSize(); } bool MipsGotSection::updateAllocSize() { - PageEntriesNum = 0; - for (std::pair<const OutputSection *, size_t> &P : PageIndexMap) { - // For each output section referenced by GOT page relocations calculate - // and save into PageIndexMap an upper bound of MIPS GOT entries required - // to store page addresses of local symbols. We assume the worst case - - // each 64kb page of the output section has at least one GOT relocation - // against it. And take in account the case when the section intersects - // page boundaries. - P.second = PageEntriesNum; - PageEntriesNum += getMipsPageCount(P.first->Size); - } - Size = (getLocalEntriesNum() + GlobalEntries.size() + TlsEntries.size()) * - Config->Wordsize; + Size = HeaderEntriesNum * Config->Wordsize; + for (const FileGot &G : Gots) + Size += G.getEntriesNum() * Config->Wordsize; return false; } +template <class ELFT> void MipsGotSection::build() { + if (Gots.empty()) + return; + + std::vector<FileGot> MergedGots(1); + + // For each GOT move non-preemptible symbols from the `Global` + // to `Local16` list. Preemptible symbol might become non-preemptible + // one if, for example, it gets a related copy relocation. + for (FileGot &Got : Gots) { + for (auto &P: Got.Global) + if (!P.first->IsPreemptible) + Got.Local16.insert({{P.first, 0}, 0}); + Got.Global.remove_if([&](const std::pair<Symbol *, size_t> &P) { + return !P.first->IsPreemptible; + }); + } + + // For each GOT remove "reloc-only" entry if there is "global" + // entry for the same symbol. And add local entries which indexed + // using 32-bit value at the end of 16-bit entries. + for (FileGot &Got : Gots) { + Got.Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { + return Got.Global.count(P.first); + }); + set_union(Got.Local16, Got.Local32); + Got.Local32.clear(); + } + + // Evaluate number of "reloc-only" entries in the resulting GOT. + // To do that put all unique "reloc-only" and "global" entries + // from all GOTs to the future primary GOT. + FileGot *PrimGot = &MergedGots.front(); + for (FileGot &Got : Gots) { + set_union(PrimGot->Relocs, Got.Global); + set_union(PrimGot->Relocs, Got.Relocs); + Got.Relocs.clear(); + } + + // Evaluate number of "page" entries in each GOT. + for (FileGot &Got : Gots) { + for (std::pair<const OutputSection *, FileGot::PageBlock> &P : + Got.PagesMap) { + const OutputSection *OS = P.first; + uint64_t SecSize = 0; + for (BaseCommand *Cmd : OS->SectionCommands) { + if (auto *ISD = dyn_cast<InputSectionDescription>(Cmd)) + for (InputSection *IS : ISD->Sections) { + uint64_t Off = alignTo(SecSize, IS->Alignment); + SecSize = Off + IS->getSize(); + } + } + P.second.Count = getMipsPageCount(SecSize); + } + } + + // Merge GOTs. Try to join as much as possible GOTs but do not exceed + // maximum GOT size. At first, try to fill the primary GOT because + // the primary GOT can be accessed in the most effective way. If it + // is not possible, try to fill the last GOT in the list, and finally + // create a new GOT if both attempts failed. + for (FileGot &SrcGot : Gots) { + InputFile *File = SrcGot.File; + if (tryMergeGots(MergedGots.front(), SrcGot, true)) { + File->MipsGotIndex = 0; + } else { + // If this is the first time we failed to merge with the primary GOT, + // MergedGots.back() will also be the primary GOT. We must make sure not + // to try to merge again with IsPrimary=false, as otherwise, if the + // inputs are just right, we could allow the primary GOT to become 1 or 2 + // words too big due to ignoring the header size. + if (MergedGots.size() == 1 || + !tryMergeGots(MergedGots.back(), SrcGot, false)) { + MergedGots.emplace_back(); + std::swap(MergedGots.back(), SrcGot); + } + File->MipsGotIndex = MergedGots.size() - 1; + } + } + std::swap(Gots, MergedGots); + + // Reduce number of "reloc-only" entries in the primary GOT + // by substracting "global" entries exist in the primary GOT. + PrimGot = &Gots.front(); + PrimGot->Relocs.remove_if([&](const std::pair<Symbol *, size_t> &P) { + return PrimGot->Global.count(P.first); + }); + + // Calculate indexes for each GOT entry. + size_t Index = HeaderEntriesNum; + for (FileGot &Got : Gots) { + Got.StartIndex = &Got == PrimGot ? 0 : Index; + for (std::pair<const OutputSection *, FileGot::PageBlock> &P : + Got.PagesMap) { + // For each output section referenced by GOT page relocations calculate + // and save into PagesMap an upper bound of MIPS GOT entries required + // to store page addresses of local symbols. We assume the worst case - + // each 64kb page of the output section has at least one GOT relocation + // against it. And take in account the case when the section intersects + // page boundaries. + P.second.FirstIndex = Index; + Index += P.second.Count; + } + for (auto &P: Got.Local16) + P.second = Index++; + for (auto &P: Got.Global) + P.second = Index++; + for (auto &P: Got.Relocs) + P.second = Index++; + for (auto &P: Got.Tls) + P.second = Index++; + for (auto &P: Got.DynTlsSymbols) { + P.second = Index; + Index += 2; + } + } + + // Update Symbol::GotIndex field to use this + // value later in the `sortMipsSymbols` function. + for (auto &P : PrimGot->Global) + P.first->GotIndex = P.second; + for (auto &P : PrimGot->Relocs) + P.first->GotIndex = P.second; + + // Create dynamic relocations. + for (FileGot &Got : Gots) { + // Create dynamic relocations for TLS entries. + for (std::pair<Symbol *, size_t> &P : Got.Tls) { + Symbol *S = P.first; + uint64_t Offset = P.second * Config->Wordsize; + if (S->IsPreemptible) + InX::RelaDyn->addReloc(Target->TlsGotRel, this, Offset, S); + } + for (std::pair<Symbol *, size_t> &P : Got.DynTlsSymbols) { + Symbol *S = P.first; + uint64_t Offset = P.second * Config->Wordsize; + if (S == nullptr) { + if (!Config->Pic) + continue; + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + } else { + // When building a shared library we still need a dynamic relocation + // for the module index. Therefore only checking for + // S->IsPreemptible is not sufficient (this happens e.g. for + // thread-locals that have been marked as local through a linker script) + if (!S->IsPreemptible && !Config->Pic) + continue; + InX::RelaDyn->addReloc(Target->TlsModuleIndexRel, this, Offset, S); + // However, we can skip writing the TLS offset reloc for non-preemptible + // symbols since it is known even in shared libraries + if (!S->IsPreemptible) + continue; + Offset += Config->Wordsize; + InX::RelaDyn->addReloc(Target->TlsOffsetRel, this, Offset, S); + } + } + + // Do not create dynamic relocations for non-TLS + // entries in the primary GOT. + if (&Got == PrimGot) + continue; + + // Dynamic relocations for "global" entries. + for (const std::pair<Symbol *, size_t> &P : Got.Global) { + uint64_t Offset = P.second * Config->Wordsize; + InX::RelaDyn->addReloc(Target->RelativeRel, this, Offset, P.first); + } + if (!Config->Pic) + continue; + // Dynamic relocations for "local" entries in case of PIC. + for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : + Got.PagesMap) { + size_t PageCount = L.second.Count; + for (size_t PI = 0; PI < PageCount; ++PI) { + uint64_t Offset = (L.second.FirstIndex + PI) * Config->Wordsize; + InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, L.first, + int64_t(PI * 0x10000)}); + } + } + for (const std::pair<GotEntry, size_t> &P : Got.Local16) { + uint64_t Offset = P.second * Config->Wordsize; + InX::RelaDyn->addReloc({Target->RelativeRel, this, Offset, true, + P.first.first, P.first.second}); + } + } +} + bool MipsGotSection::empty() const { // We add the .got section to the result for dynamic MIPS target because // its address and properties are mentioned in the .dynamic section. return Config->Relocatable; } -uint64_t MipsGotSection::getGp() const { return ElfSym::MipsGp->getVA(0); } +uint64_t MipsGotSection::getGp(const InputFile *F) const { + // For files without related GOT or files refer a primary GOT + // returns "common" _gp value. For secondary GOTs calculate + // individual _gp values. + if (!F || !F->MipsGotIndex.hasValue() || *F->MipsGotIndex == 0) + return ElfSym::MipsGp->getVA(0); + return getVA() + Gots[*F->MipsGotIndex].StartIndex * Config->Wordsize + + 0x7ff0; +} void MipsGotSection::writeTo(uint8_t *Buf) { // Set the MSB of the second GOT slot. This is not required by any @@ -830,59 +1025,67 @@ void MipsGotSection::writeTo(uint8_t *Buf) { // keep doing this for now. We really need to revisit this to see // if we had to do this. writeUint(Buf + Config->Wordsize, (uint64_t)1 << (Config->Wordsize * 8 - 1)); - Buf += HeaderEntriesNum * Config->Wordsize; - // Write 'page address' entries to the local part of the GOT. - for (std::pair<const OutputSection *, size_t> &L : PageIndexMap) { - size_t PageCount = getMipsPageCount(L.first->Size); - uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); - for (size_t PI = 0; PI < PageCount; ++PI) { - uint8_t *Entry = Buf + (L.second + PI) * Config->Wordsize; - writeUint(Entry, FirstPageAddr + PI * 0x10000); - } - } - Buf += PageEntriesNum * Config->Wordsize; - auto AddEntry = [&](const GotEntry &SA) { - uint8_t *Entry = Buf; - Buf += Config->Wordsize; - const Symbol *Sym = SA.first; - uint64_t VA = Sym->getVA(SA.second); - if (Sym->StOther & STO_MIPS_MICROMIPS) - VA |= 1; - writeUint(Entry, VA); - }; - std::for_each(std::begin(LocalEntries), std::end(LocalEntries), AddEntry); - std::for_each(std::begin(LocalEntries32), std::end(LocalEntries32), AddEntry); - std::for_each(std::begin(GlobalEntries), std::end(GlobalEntries), AddEntry); - // Initialize TLS-related GOT entries. If the entry has a corresponding - // dynamic relocations, leave it initialized by zero. Write down adjusted - // TLS symbol's values otherwise. To calculate the adjustments use offsets - // for thread-local storage. - // https://www.linux-mips.org/wiki/NPTL - if (TlsIndexOff != -1U && !Config->Pic) - writeUint(Buf + TlsIndexOff, 1); - for (const Symbol *B : TlsEntries) { - if (!B || B->IsPreemptible) - continue; - uint64_t VA = B->getVA(); - if (B->GotIndex != -1U) { - uint8_t *Entry = Buf + B->GotIndex * Config->Wordsize; - writeUint(Entry, VA - 0x7000); + for (const FileGot &G : Gots) { + auto Write = [&](size_t I, const Symbol *S, int64_t A) { + uint64_t VA = A; + if (S) { + VA = S->getVA(A); + if (S->StOther & STO_MIPS_MICROMIPS) + VA |= 1; + } + writeUint(Buf + I * Config->Wordsize, VA); + }; + // Write 'page address' entries to the local part of the GOT. + for (const std::pair<const OutputSection *, FileGot::PageBlock> &L : + G.PagesMap) { + size_t PageCount = L.second.Count; + uint64_t FirstPageAddr = getMipsPageAddr(L.first->Addr); + for (size_t PI = 0; PI < PageCount; ++PI) + Write(L.second.FirstIndex + PI, nullptr, FirstPageAddr + PI * 0x10000); } - if (B->GlobalDynIndex != -1U) { - uint8_t *Entry = Buf + B->GlobalDynIndex * Config->Wordsize; - writeUint(Entry, 1); - Entry += Config->Wordsize; - writeUint(Entry, VA - 0x8000); + // Local, global, TLS, reloc-only entries. + // If TLS entry has a corresponding dynamic relocations, leave it + // initialized by zero. Write down adjusted TLS symbol's values otherwise. + // To calculate the adjustments use offsets for thread-local storage. + // https://www.linux-mips.org/wiki/NPTL + for (const std::pair<GotEntry, size_t> &P : G.Local16) + Write(P.second, P.first.first, P.first.second); + // Write VA to the primary GOT only. For secondary GOTs that + // will be done by REL32 dynamic relocations. + if (&G == &Gots.front()) + for (const std::pair<const Symbol *, size_t> &P : G.Global) + Write(P.second, P.first, 0); + for (const std::pair<Symbol *, size_t> &P : G.Relocs) + Write(P.second, P.first, 0); + for (const std::pair<Symbol *, size_t> &P : G.Tls) + Write(P.second, P.first, P.first->IsPreemptible ? 0 : -0x7000); + for (const std::pair<Symbol *, size_t> &P : G.DynTlsSymbols) { + if (P.first == nullptr && !Config->Pic) + Write(P.second, nullptr, 1); + else if (P.first && !P.first->IsPreemptible) { + // If we are emitting PIC code with relocations we mustn't write + // anything to the GOT here. When using Elf_Rel relocations the value + // one will be treated as an addend and will cause crashes at runtime + if (!Config->Pic) + Write(P.second, nullptr, 1); + Write(P.second + 1, P.first, -0x8000); + } } } } +// On PowerPC the .plt section is used to hold the table of function addresses +// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss +// section. I don't know why we have a BSS style type for the section but it is +// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI. GotPltSection::GotPltSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotPltEntrySize, ".got.plt") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, + Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, + Target->GotPltEntrySize, + Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {} void GotPltSection::addEntry(Symbol &Sym) { - Sym.GotPltIndex = Target->GotPltHeaderEntriesNum + Entries.size(); + assert(Sym.PltIndex == Entries.size()); Entries.push_back(&Sym); } @@ -900,16 +1103,37 @@ void GotPltSection::writeTo(uint8_t *Buf) { } } -// On ARM the IgotPltSection is part of the GotSection, on other Targets it is -// part of the .got.plt +bool GotPltSection::empty() const { + // We need to emit a GOT.PLT even if it's empty if there's a symbol that + // references the _GLOBAL_OFFSET_TABLE_ and the Target defines the symbol + // relative to the .got.plt section. + return Entries.empty() && + !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt); +} + +static StringRef getIgotPltName() { + // On ARM the IgotPltSection is part of the GotSection. + if (Config->EMachine == EM_ARM) + return ".got"; + + // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection + // needs to be named the same. + if (Config->EMachine == EM_PPC64) + return ".plt"; + + return ".got.plt"; +} + +// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit +// with the IgotPltSection. IgotPltSection::IgotPltSection() - : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS, - Target->GotPltEntrySize, - Config->EMachine == EM_ARM ? ".got" : ".got.plt") {} + : SyntheticSection(SHF_ALLOC | SHF_WRITE, + Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS, + Target->GotPltEntrySize, getIgotPltName()) {} void IgotPltSection::addEntry(Symbol &Sym) { Sym.IsInIgot = true; - Sym.GotPltIndex = Entries.size(); + assert(Sym.PltIndex == Entries.size()); Entries.push_back(&Sym); } @@ -1005,8 +1229,14 @@ void DynamicSection<ELFT>::addInt(int32_t Tag, uint64_t Val) { template <class ELFT> void DynamicSection<ELFT>::addInSec(int32_t Tag, InputSection *Sec) { + Entries.push_back({Tag, [=] { return Sec->getVA(0); }}); +} + +template <class ELFT> +void DynamicSection<ELFT>::addInSecRelative(int32_t Tag, InputSection *Sec) { + size_t TagOffset = Entries.size() * Entsize; Entries.push_back( - {Tag, [=] { return Sec->getParent()->Addr + Sec->OutSecOff; }}); + {Tag, [=] { return Sec->getVA(0) - (getVA() + TagOffset); }}); } template <class ELFT> @@ -1034,6 +1264,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { uint32_t DtFlags1 = 0; if (Config->Bsymbolic) DtFlags |= DF_SYMBOLIC; + if (Config->ZInitfirst) + DtFlags1 |= DF_1_INITFIRST; if (Config->ZNodelete) DtFlags1 |= DF_1_NODELETE; if (Config->ZNodlopen) @@ -1046,6 +1278,8 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { DtFlags |= DF_ORIGIN; DtFlags1 |= DF_1_ORIGIN; } + if (!Config->ZText) + DtFlags |= DF_TEXTREL; if (DtFlags) addInt(DT_FLAGS, DtFlags); @@ -1064,7 +1298,7 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { addInt(DT_DEBUG, 0); this->Link = InX::DynStrTab->getParent()->SectionIndex; - if (InX::RelaDyn->getParent() && !InX::RelaDyn->empty()) { + if (!InX::RelaDyn->empty()) { addInSec(InX::RelaDyn->DynamicTag, InX::RelaDyn); addSize(InX::RelaDyn->SizeDynamicTag, InX::RelaDyn->getParent()); @@ -1081,7 +1315,21 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { addInt(IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels); } } - if (InX::RelaPlt->getParent() && !InX::RelaPlt->empty()) { + if (InX::RelrDyn && !InX::RelrDyn->Relocs.empty()) { + addInSec(Config->UseAndroidRelrTags ? DT_ANDROID_RELR : DT_RELR, + InX::RelrDyn); + addSize(Config->UseAndroidRelrTags ? DT_ANDROID_RELRSZ : DT_RELRSZ, + InX::RelrDyn->getParent()); + addInt(Config->UseAndroidRelrTags ? DT_ANDROID_RELRENT : DT_RELRENT, + sizeof(Elf_Relr)); + } + // .rel[a].plt section usually consists of two parts, containing plt and + // iplt relocations. It is possible to have only iplt relocations in the + // output. In that case RelaPlt is empty and have zero offset, the same offset + // as RelaIplt have. And we still want to emit proper dynamic tags for that + // case, so here we always use RelaPlt as marker for the begining of + // .rel[a].plt section. + if (InX::RelaPlt->getParent()->Live) { addInSec(DT_JMPREL, InX::RelaPlt); addSize(DT_PLTRELSZ, InX::RelaPlt->getParent()); switch (Config->EMachine) { @@ -1154,8 +1402,23 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { else addInt(DT_MIPS_GOTSYM, InX::DynSymTab->getNumSymbols()); addInSec(DT_PLTGOT, InX::MipsGot); - if (InX::MipsRldMap) - addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap); + if (InX::MipsRldMap) { + if (!Config->Pie) + addInSec(DT_MIPS_RLD_MAP, InX::MipsRldMap); + // Store the offset to the .rld_map section + // relative to the address of the tag. + addInSecRelative(DT_MIPS_RLD_MAP_REL, InX::MipsRldMap); + } + } + + // Glink dynamic tag is required by the V2 abi if the plt section isn't empty. + if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) { + // The Glink tag points to 32 bytes before the first lazy symbol resolution + // stub, which starts directly after the header. + Entries.push_back({DT_PPC64_GLINK, [=] { + unsigned Offset = Target->PltHeaderSize - 32; + return InX::Plt->getVA(0) + Offset; + }}); } addInt(DT_NULL, 0); @@ -1175,13 +1438,16 @@ template <class ELFT> void DynamicSection<ELFT>::writeTo(uint8_t *Buf) { } uint64_t DynamicReloc::getOffset() const { - return InputSec->getOutputSection()->Addr + InputSec->getOffset(OffsetInSec); + return InputSec->getVA(OffsetInSec); } -int64_t DynamicReloc::getAddend() const { +int64_t DynamicReloc::computeAddend() const { if (UseSymVA) return Sym->getVA(Addend); - return Addend; + if (!OutputSec) + return Addend; + // See the comment in the DynamicReloc ctor. + return getMipsPageAddr(OutputSec->Addr) + Addend; } uint32_t DynamicReloc::getSymIndex() const { @@ -1196,6 +1462,23 @@ RelocationBaseSection::RelocationBaseSection(StringRef Name, uint32_t Type, : SyntheticSection(SHF_ALLOC, Type, Config->Wordsize, Name), DynamicTag(DynamicTag), SizeDynamicTag(SizeDynamicTag) {} +void RelocationBaseSection::addReloc(RelType DynType, InputSectionBase *IS, + uint64_t OffsetInSec, Symbol *Sym) { + addReloc({DynType, IS, OffsetInSec, false, Sym, 0}); +} + +void RelocationBaseSection::addReloc(RelType DynType, + InputSectionBase *InputSec, + uint64_t OffsetInSec, Symbol *Sym, + int64_t Addend, RelExpr Expr, + RelType Type) { + // Write the addends to the relocated address if required. We skip + // it if the written value would be zero. + if (Config->WriteAddends && (Expr != R_ADDEND || Addend != 0)) + InputSec->Relocations.push_back({Expr, Type, OffsetInSec, Addend, Sym}); + addReloc({DynType, InputSec, OffsetInSec, Expr != R_ADDEND, Sym, Addend}); +} + void RelocationBaseSection::addReloc(const DynamicReloc &Reloc) { if (Reloc.Type == Target->RelativeRel) ++NumRelativeRelocs; @@ -1212,23 +1495,17 @@ void RelocationBaseSection::finalizeContents() { getParent()->Link = Link; } +RelrBaseSection::RelrBaseSection() + : SyntheticSection(SHF_ALLOC, + Config->UseAndroidRelrTags ? SHT_ANDROID_RELR : SHT_RELR, + Config->Wordsize, ".relr.dyn") {} + template <class ELFT> static void encodeDynamicReloc(typename ELFT::Rela *P, const DynamicReloc &Rel) { if (Config->IsRela) - P->r_addend = Rel.getAddend(); + P->r_addend = Rel.computeAddend(); P->r_offset = Rel.getOffset(); - if (Config->EMachine == EM_MIPS && Rel.getInputSec() == InX::MipsGot) - // The MIPS GOT section contains dynamic relocations that correspond to TLS - // entries. These entries are placed after the global and local sections of - // the GOT. At the point when we create these relocations, the size of the - // global and local sections is unknown, so the offset that we store in the - // TLS entry's DynamicReloc is relative to the start of the TLS section of - // the GOT, rather than being relative to the start of the GOT. This line of - // code adds the size of the global and local sections to the virtual - // address computed by getOffset() in order to adjust it into the TLS - // section. - P->r_offset += InX::MipsGot->getTlsOffset(); P->setSymbolAndType(Rel.getSymIndex(), Rel.Type, Config->IsMips64EL); } @@ -1241,32 +1518,22 @@ RelocationSection<ELFT>::RelocationSection(StringRef Name, bool Sort) this->Entsize = Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } -template <class ELFT, class RelTy> -static bool compRelocations(const RelTy &A, const RelTy &B) { - bool AIsRel = A.getType(Config->IsMips64EL) == Target->RelativeRel; - bool BIsRel = B.getType(Config->IsMips64EL) == Target->RelativeRel; +static bool compRelocations(const DynamicReloc &A, const DynamicReloc &B) { + bool AIsRel = A.Type == Target->RelativeRel; + bool BIsRel = B.Type == Target->RelativeRel; if (AIsRel != BIsRel) return AIsRel; - - return A.getSymbol(Config->IsMips64EL) < B.getSymbol(Config->IsMips64EL); + return A.getSymIndex() < B.getSymIndex(); } template <class ELFT> void RelocationSection<ELFT>::writeTo(uint8_t *Buf) { - uint8_t *BufBegin = Buf; + if (Sort) + std::stable_sort(Relocs.begin(), Relocs.end(), compRelocations); + for (const DynamicReloc &Rel : Relocs) { encodeDynamicReloc<ELFT>(reinterpret_cast<Elf_Rela *>(Buf), Rel); Buf += Config->IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel); } - - if (Sort) { - if (Config->IsRela) - std::stable_sort((Elf_Rela *)BufBegin, - (Elf_Rela *)BufBegin + Relocs.size(), - compRelocations<ELFT, Elf_Rela>); - else - std::stable_sort((Elf_Rel *)BufBegin, (Elf_Rel *)BufBegin + Relocs.size(), - compRelocations<ELFT, Elf_Rel>); - } } template <class ELFT> unsigned RelocationSection<ELFT>::getRelocOffset() { @@ -1354,10 +1621,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { NonRelatives.push_back(R); } - std::sort(Relatives.begin(), Relatives.end(), - [](const Elf_Rel &A, const Elf_Rel &B) { - return A.r_offset < B.r_offset; - }); + llvm::sort(Relatives.begin(), Relatives.end(), + [](const Elf_Rel &A, const Elf_Rel &B) { + return A.r_offset < B.r_offset; + }); // Try to find groups of relative relocations which are spaced one word // apart from one another. These generally correspond to vtable entries. The @@ -1435,10 +1702,10 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { } // Finally the non-relative relocations. - std::sort(NonRelatives.begin(), NonRelatives.end(), - [](const Elf_Rela &A, const Elf_Rela &B) { - return A.r_offset < B.r_offset; - }); + llvm::sort(NonRelatives.begin(), NonRelatives.end(), + [](const Elf_Rela &A, const Elf_Rela &B) { + return A.r_offset < B.r_offset; + }); if (!NonRelatives.empty()) { Add(NonRelatives.size()); Add(HasAddendIfRela); @@ -1461,6 +1728,97 @@ bool AndroidPackedRelocationSection<ELFT>::updateAllocSize() { return RelocData.size() != OldSize; } +template <class ELFT> RelrSection<ELFT>::RelrSection() { + this->Entsize = Config->Wordsize; +} + +template <class ELFT> bool RelrSection<ELFT>::updateAllocSize() { + // This function computes the contents of an SHT_RELR packed relocation + // section. + // + // Proposal for adding SHT_RELR sections to generic-abi is here: + // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg + // + // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks + // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ] + // + // i.e. start with an address, followed by any number of bitmaps. The address + // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63 + // relocations each, at subsequent offsets following the last address entry. + // + // The bitmap entries must have 1 in the least significant bit. The assumption + // here is that an address cannot have 1 in lsb. Odd addresses are not + // supported. + // + // Excluding the least significant bit in the bitmap, each non-zero bit in + // the bitmap represents a relocation to be applied to a corresponding machine + // word that follows the base address word. The second least significant bit + // represents the machine word immediately following the initial address, and + // each bit that follows represents the next word, in linear order. As such, + // a single bitmap can encode up to 31 relocations in a 32-bit object, and + // 63 relocations in a 64-bit object. + // + // This encoding has a couple of interesting properties: + // 1. Looking at any entry, it is clear whether it's an address or a bitmap: + // even means address, odd means bitmap. + // 2. Just a simple list of addresses is a valid encoding. + + size_t OldSize = RelrRelocs.size(); + RelrRelocs.clear(); + + // Same as Config->Wordsize but faster because this is a compile-time + // constant. + const size_t Wordsize = sizeof(typename ELFT::uint); + + // Number of bits to use for the relocation offsets bitmap. + // Must be either 63 or 31. + const size_t NBits = Wordsize * 8 - 1; + + // Get offsets for all relative relocations and sort them. + std::vector<uint64_t> Offsets; + for (const RelativeReloc &Rel : Relocs) + Offsets.push_back(Rel.getOffset()); + llvm::sort(Offsets.begin(), Offsets.end()); + + // For each leading relocation, find following ones that can be folded + // as a bitmap and fold them. + for (size_t I = 0, E = Offsets.size(); I < E;) { + // Add a leading relocation. + RelrRelocs.push_back(Elf_Relr(Offsets[I])); + uint64_t Base = Offsets[I] + Wordsize; + ++I; + + // Find foldable relocations to construct bitmaps. + while (I < E) { + uint64_t Bitmap = 0; + + while (I < E) { + uint64_t Delta = Offsets[I] - Base; + + // If it is too far, it cannot be folded. + if (Delta >= NBits * Wordsize) + break; + + // If it is not a multiple of wordsize away, it cannot be folded. + if (Delta % Wordsize) + break; + + // Fold it. + Bitmap |= 1ULL << (Delta / Wordsize); + ++I; + } + + if (!Bitmap) + break; + + RelrRelocs.push_back(Elf_Relr((Bitmap << 1) | 1)); + Base += NBits * Wordsize; + } + } + + return RelrRelocs.size() != OldSize; +} + SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) : SyntheticSection(StrTabSec.isDynamic() ? (uint64_t)SHF_ALLOC : 0, StrTabSec.isDynamic() ? SHT_DYNSYM : SHT_SYMTAB, @@ -1476,50 +1834,70 @@ SymbolTableBaseSection::SymbolTableBaseSection(StringTableSection &StrTabSec) static bool sortMipsSymbols(const SymbolTableEntry &L, const SymbolTableEntry &R) { // Sort entries related to non-local preemptible symbols by GOT indexes. - // All other entries go to the first part of GOT in arbitrary order. - bool LIsInLocalGot = !L.Sym->IsInGlobalMipsGot; - bool RIsInLocalGot = !R.Sym->IsInGlobalMipsGot; - if (LIsInLocalGot || RIsInLocalGot) - return !RIsInLocalGot; - return L.Sym->GotIndex < R.Sym->GotIndex; + // All other entries go to the beginning of a dynsym in arbitrary order. + if (L.Sym->isInGot() && R.Sym->isInGot()) + return L.Sym->GotIndex < R.Sym->GotIndex; + if (!L.Sym->isInGot() && !R.Sym->isInGot()) + return false; + return !L.Sym->isInGot(); } void SymbolTableBaseSection::finalizeContents() { getParent()->Link = StrTabSec.getParent()->SectionIndex; + if (this->Type != SHT_DYNSYM) + return; + // If it is a .dynsym, there should be no local symbols, but we need // to do a few things for the dynamic linker. - if (this->Type == SHT_DYNSYM) { - // Section's Info field has the index of the first non-local symbol. - // Because the first symbol entry is a null entry, 1 is the first. - getParent()->Info = 1; - - if (InX::GnuHashTab) { - // NB: It also sorts Symbols to meet the GNU hash table requirements. - InX::GnuHashTab->addSymbols(Symbols); - } else if (Config->EMachine == EM_MIPS) { - std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); - } - size_t I = 0; - for (const SymbolTableEntry &S : Symbols) S.Sym->DynsymIndex = ++I; - return; + // Section's Info field has the index of the first non-local symbol. + // Because the first symbol entry is a null entry, 1 is the first. + getParent()->Info = 1; + + if (InX::GnuHashTab) { + // NB: It also sorts Symbols to meet the GNU hash table requirements. + InX::GnuHashTab->addSymbols(Symbols); + } else if (Config->EMachine == EM_MIPS) { + std::stable_sort(Symbols.begin(), Symbols.end(), sortMipsSymbols); } + + size_t I = 0; + for (const SymbolTableEntry &S : Symbols) + S.Sym->DynsymIndex = ++I; } // The ELF spec requires that all local symbols precede global symbols, so we // sort symbol entries in this function. (For .dynsym, we don't do that because // symbols for dynamic linking are inherently all globals.) +// +// Aside from above, we put local symbols in groups starting with the STT_FILE +// symbol. That is convenient for purpose of identifying where are local symbols +// coming from. void SymbolTableBaseSection::postThunkContents() { - if (this->Type == SHT_DYNSYM) - return; - // move all local symbols before global symbols. - auto It = std::stable_partition( + assert(this->Type == SHT_SYMTAB); + + // Move all local symbols before global symbols. + auto E = std::stable_partition( Symbols.begin(), Symbols.end(), [](const SymbolTableEntry &S) { return S.Sym->isLocal() || S.Sym->computeBinding() == STB_LOCAL; }); - size_t NumLocals = It - Symbols.begin(); + size_t NumLocals = E - Symbols.begin(); getParent()->Info = NumLocals + 1; + + // We want to group the local symbols by file. For that we rebuild the local + // part of the symbols vector. We do not need to care about the STT_FILE + // symbols, they are already naturally placed first in each group. That + // happens because STT_FILE is always the first symbol in the object and hence + // precede all other local symbols we add for a file. + MapVector<InputFile *, std::vector<SymbolTableEntry>> Arr; + for (const SymbolTableEntry &S : llvm::make_range(Symbols.begin(), E)) + Arr[S.Sym->File].push_back(S); + + auto I = Symbols.begin(); + for (std::pair<InputFile *, std::vector<SymbolTableEntry>> &P : Arr) + for (SymbolTableEntry &Entry : P.second) + *I++ = Entry; } void SymbolTableBaseSection::addSymbol(Symbol *B) { @@ -1586,6 +1964,8 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { CommonSec = dyn_cast_or_null<BssSection>(D->Section); if (CommonSec) ESym->st_shndx = SHN_COMMON; + else if (Sym->NeedsPltAddr) + ESym->st_shndx = SHN_UNDEF; else if (const OutputSection *OutSec = Sym->getOutputSection()) ESym->st_shndx = OutSec->SectionIndex; else if (isa<Defined>(Sym)) @@ -1627,9 +2007,11 @@ template <class ELFT> void SymbolTableSection<ELFT>::writeTo(uint8_t *Buf) { ESym->st_other |= STO_MIPS_PLT; if (isMicroMips()) { // Set STO_MIPS_MICROMIPS flag and less-significant bit for - // defined microMIPS symbols and shared symbols with PLT record. - if ((Sym->isDefined() && (Sym->StOther & STO_MIPS_MICROMIPS)) || - (Sym->isShared() && Sym->NeedsPltAddr)) { + // a defined microMIPS symbol and symbol should point to its + // PLT entry (in case of microMIPS, PLT entries always contain + // microMIPS code). + if (Sym->isDefined() && + ((Sym->StOther & STO_MIPS_MICROMIPS) || Sym->NeedsPltAddr)) { if (StrTabSec.isDynamic()) ESym->st_value |= 1; ESym->st_other |= STO_MIPS_MICROMIPS; @@ -1682,12 +2064,14 @@ GnuHashTableSection::GnuHashTableSection() void GnuHashTableSection::finalizeContents() { getParent()->Link = InX::DynSymTab->getParent()->SectionIndex; - // Computes bloom filter size in word size. We want to allocate 8 + // Computes bloom filter size in word size. We want to allocate 12 // bits for each symbol. It must be a power of two. - if (Symbols.empty()) + if (Symbols.empty()) { MaskWords = 1; - else - MaskWords = NextPowerOf2((Symbols.size() - 1) / Config->Wordsize); + } else { + uint64_t NumBits = Symbols.size() * 12; + MaskWords = NextPowerOf2(NumBits / (Config->Wordsize * 8)); + } Size = 16; // Header Size += Config->Wordsize * MaskWords; // Bloom filter @@ -1705,7 +2089,7 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) { write32(Buf, NBuckets); write32(Buf + 4, InX::DynSymTab->getNumSymbols() - Symbols.size()); write32(Buf + 8, MaskWords); - write32(Buf + 12, getShift2()); + write32(Buf + 12, Shift2); Buf += 16; // Write a bloom filter and a hash table. @@ -1722,12 +2106,12 @@ void GnuHashTableSection::writeTo(uint8_t *Buf) { // [1] Ulrich Drepper (2011), "How To Write Shared Libraries" (Ver. 4.1.2), // p.9, https://www.akkadia.org/drepper/dsohowto.pdf void GnuHashTableSection::writeBloomFilter(uint8_t *Buf) { - const unsigned C = Config->Wordsize * 8; + unsigned C = Config->Is64 ? 64 : 32; for (const Entry &Sym : Symbols) { size_t I = (Sym.Hash / C) & (MaskWords - 1); uint64_t Val = readUint(Buf + I * Config->Wordsize); Val |= uint64_t(1) << (Sym.Hash % C); - Val |= uint64_t(1) << ((Sym.Hash >> getShift2()) % C); + Val |= uint64_t(1) << ((Sym.Hash >> Shift2) % C); writeUint(Buf + I * Config->Wordsize, Val); } } @@ -1769,21 +2153,23 @@ void GnuHashTableSection::addSymbols(std::vector<SymbolTableEntry> &V) { // its type correctly. std::vector<SymbolTableEntry>::iterator Mid = std::stable_partition(V.begin(), V.end(), [](const SymbolTableEntry &S) { - // Shared symbols that this executable preempts are special. The dynamic - // linker has to look them up, so they have to be in the hash table. - if (auto *SS = dyn_cast<SharedSymbol>(S.Sym)) - return SS->CopyRelSec == nullptr && !SS->NeedsPltAddr; return !S.Sym->isDefined(); }); - if (Mid == V.end()) - return; // We chose load factor 4 for the on-disk hash table. For each hash // collision, the dynamic linker will compare a uint32_t hash value. - // Since the integer comparison is quite fast, we believe we can make - // the load factor even larger. 4 is just a conservative choice. + // Since the integer comparison is quite fast, we believe we can + // make the load factor even larger. 4 is just a conservative choice. + // + // Note that we don't want to create a zero-sized hash table because + // Android loader as of 2018 doesn't like a .gnu.hash containing such + // table. If that's the case, we create a hash table with one unused + // dummy slot. NBuckets = std::max<size_t>((V.end() - Mid) / 4, 1); + if (Mid == V.end()) + return; + for (SymbolTableEntry &Ent : llvm::make_range(Mid, V.end())) { Symbol *B = Ent.Sym; uint32_t Hash = hashGnu(B->getName()); @@ -1817,6 +2203,9 @@ void HashTableSection::finalizeContents() { } void HashTableSection::writeTo(uint8_t *Buf) { + // See comment in GnuHashTableSection::writeTo. + memset(Buf, 0, Size); + unsigned NumSymbols = InX::DynSymTab->getNumSymbols(); uint32_t *P = reinterpret_cast<uint32_t *>(Buf); @@ -1836,9 +2225,12 @@ void HashTableSection::writeTo(uint8_t *Buf) { } } -PltSection::PltSection(size_t S) - : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"), - HeaderSize(S) { +// On PowerPC64 the lazy symbol resolvers go into the `global linkage table` +// in the .glink section, rather then the typical .plt section. +PltSection::PltSection(bool IsIplt) + : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, + Config->EMachine == EM_PPC64 ? ".glink" : ".plt"), + HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) { // The PLT needs to be writable on SPARC as the dynamic linker will // modify the instructions in the PLT entries. if (Config->EMachine == EM_SPARCV9) @@ -1848,7 +2240,7 @@ PltSection::PltSection(size_t S) void PltSection::writeTo(uint8_t *Buf) { // At beginning of PLT but not the IPLT, we have code to call the dynamic // linker to resolve dynsyms at runtime. Write such code. - if (HeaderSize != 0) + if (!IsIplt) Target->writePltHeader(Buf); size_t Off = HeaderSize; // The IPlt is immediately after the Plt, account for this in RelOff @@ -1867,7 +2259,7 @@ void PltSection::writeTo(uint8_t *Buf) { template <class ELFT> void PltSection::addEntry(Symbol &Sym) { Sym.PltIndex = Entries.size(); RelocationBaseSection *PltRelocSection = InX::RelaPlt; - if (HeaderSize == 0) { + if (IsIplt) { PltRelocSection = InX::RelaIplt; Sym.IsInIplt = true; } @@ -1884,7 +2276,7 @@ size_t PltSection::getSize() const { // example ARM uses mapping symbols to aid disassembly void PltSection::addSymbols() { // The PLT may have symbols defined for the Header, the IPLT has no header - if (HeaderSize != 0) + if (!IsIplt) Target->addPltHeaderSymbols(*this); size_t Off = HeaderSize; for (size_t I = 0; I < Entries.size(); ++I) { @@ -1894,7 +2286,7 @@ void PltSection::addSymbols() { } unsigned PltSection::getPltRelocOff() const { - return (HeaderSize == 0) ? InX::Plt->getSize() : 0; + return IsIplt ? InX::Plt->getSize() : 0; } // The string hash function for .gdb_index. @@ -1905,16 +2297,48 @@ static uint32_t computeGdbHash(StringRef S) { return H; } -static std::vector<GdbIndexChunk::CuEntry> readCuList(DWARFContext &Dwarf) { - std::vector<GdbIndexChunk::CuEntry> Ret; +GdbIndexSection::GdbIndexSection() + : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index") {} + +// Returns the desired size of an on-disk hash table for a .gdb_index section. +// There's a tradeoff between size and collision rate. We aim 75% utilization. +size_t GdbIndexSection::computeSymtabSize() const { + return std::max<size_t>(NextPowerOf2(Symbols.size() * 4 / 3), 1024); +} + +// Compute the output section size. +void GdbIndexSection::initOutputSize() { + Size = sizeof(GdbIndexHeader) + computeSymtabSize() * 8; + + for (GdbChunk &Chunk : Chunks) + Size += Chunk.CompilationUnits.size() * 16 + Chunk.AddressAreas.size() * 20; + + // Add the constant pool size if exists. + if (!Symbols.empty()) { + GdbSymbol &Sym = Symbols.back(); + Size += Sym.NameOff + Sym.Name.size() + 1; + } +} + +static std::vector<InputSection *> getDebugInfoSections() { + std::vector<InputSection *> Ret; + for (InputSectionBase *S : InputSections) + if (InputSection *IS = dyn_cast<InputSection>(S)) + if (IS->Name == ".debug_info") + Ret.push_back(IS); + return Ret; +} + +static std::vector<GdbIndexSection::CuEntry> readCuList(DWARFContext &Dwarf) { + std::vector<GdbIndexSection::CuEntry> Ret; for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) Ret.push_back({Cu->getOffset(), Cu->getLength() + 4}); return Ret; } -static std::vector<GdbIndexChunk::AddressEntry> +static std::vector<GdbIndexSection::AddressEntry> readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) { - std::vector<GdbIndexChunk::AddressEntry> Ret; + std::vector<GdbIndexSection::AddressEntry> Ret; uint32_t CuIdx = 0; for (std::unique_ptr<DWARFCompileUnit> &Cu : Dwarf.compile_units()) { @@ -1938,218 +2362,192 @@ readAddressAreas(DWARFContext &Dwarf, InputSection *Sec) { return Ret; } -static std::vector<GdbIndexChunk::NameTypeEntry> -readPubNamesAndTypes(DWARFContext &Dwarf) { +static std::vector<GdbIndexSection::NameTypeEntry> +readPubNamesAndTypes(DWARFContext &Dwarf, uint32_t Idx) { StringRef Sec1 = Dwarf.getDWARFObj().getGnuPubNamesSection(); StringRef Sec2 = Dwarf.getDWARFObj().getGnuPubTypesSection(); - std::vector<GdbIndexChunk::NameTypeEntry> Ret; + std::vector<GdbIndexSection::NameTypeEntry> Ret; for (StringRef Sec : {Sec1, Sec2}) { DWARFDebugPubTable Table(Sec, Config->IsLE, true); - for (const DWARFDebugPubTable::Set &Set : Table.getData()) { - for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) { - CachedHashStringRef S(Ent.Name, computeGdbHash(Ent.Name)); - Ret.push_back({S, Ent.Descriptor.toBits()}); - } - } + for (const DWARFDebugPubTable::Set &Set : Table.getData()) + for (const DWARFDebugPubTable::Entry &Ent : Set.Entries) + Ret.push_back({{Ent.Name, computeGdbHash(Ent.Name)}, + (Ent.Descriptor.toBits() << 24) | Idx}); } return Ret; } -static std::vector<InputSection *> getDebugInfoSections() { - std::vector<InputSection *> Ret; - for (InputSectionBase *S : InputSections) - if (InputSection *IS = dyn_cast<InputSection>(S)) - if (IS->Name == ".debug_info") - Ret.push_back(IS); - return Ret; -} +// Create a list of symbols from a given list of symbol names and types +// by uniquifying them by name. +static std::vector<GdbIndexSection::GdbSymbol> +createSymbols(ArrayRef<std::vector<GdbIndexSection::NameTypeEntry>> NameTypes) { + typedef GdbIndexSection::GdbSymbol GdbSymbol; + typedef GdbIndexSection::NameTypeEntry NameTypeEntry; -void GdbIndexSection::fixCuIndex() { - uint32_t Idx = 0; - for (GdbIndexChunk &Chunk : Chunks) { - for (GdbIndexChunk::AddressEntry &Ent : Chunk.AddressAreas) - Ent.CuIndex += Idx; - Idx += Chunk.CompilationUnits.size(); - } -} + // The number of symbols we will handle in this function is of the order + // of millions for very large executables, so we use multi-threading to + // speed it up. + size_t NumShards = 32; + size_t Concurrency = 1; + if (ThreadsEnabled) + Concurrency = + std::min<size_t>(PowerOf2Floor(hardware_concurrency()), NumShards); -std::vector<std::vector<uint32_t>> GdbIndexSection::createCuVectors() { - std::vector<std::vector<uint32_t>> Ret; - uint32_t Idx = 0; - uint32_t Off = 0; + // A sharded map to uniquify symbols by name. + std::vector<DenseMap<CachedHashStringRef, size_t>> Map(NumShards); + size_t Shift = 32 - countTrailingZeros(NumShards); - for (GdbIndexChunk &Chunk : Chunks) { - for (GdbIndexChunk::NameTypeEntry &Ent : Chunk.NamesAndTypes) { - GdbSymbol *&Sym = Symbols[Ent.Name]; - if (!Sym) { - Sym = make<GdbSymbol>(GdbSymbol{Ent.Name.hash(), Off, Ret.size()}); - Off += Ent.Name.size() + 1; - Ret.push_back({}); - } + // Instantiate GdbSymbols while uniqufying them by name. + std::vector<std::vector<GdbSymbol>> Symbols(NumShards); + parallelForEachN(0, Concurrency, [&](size_t ThreadId) { + for (ArrayRef<NameTypeEntry> Entries : NameTypes) { + for (const NameTypeEntry &Ent : Entries) { + size_t ShardId = Ent.Name.hash() >> Shift; + if ((ShardId & (Concurrency - 1)) != ThreadId) + continue; - // gcc 5.4.1 produces a buggy .debug_gnu_pubnames that contains - // duplicate entries, so we want to dedup them. - std::vector<uint32_t> &Vec = Ret[Sym->CuVectorIndex]; - uint32_t Val = (Ent.Type << 24) | Idx; - if (Vec.empty() || Vec.back() != Val) - Vec.push_back(Val); + size_t &Idx = Map[ShardId][Ent.Name]; + if (Idx) { + Symbols[ShardId][Idx - 1].CuVector.push_back(Ent.Type); + continue; + } + + Idx = Symbols[ShardId].size() + 1; + Symbols[ShardId].push_back({Ent.Name, {Ent.Type}, 0, 0}); + } } - Idx += Chunk.CompilationUnits.size(); + }); + + size_t NumSymbols = 0; + for (ArrayRef<GdbSymbol> V : Symbols) + NumSymbols += V.size(); + + // The return type is a flattened vector, so we'll copy each vector + // contents to Ret. + std::vector<GdbSymbol> Ret; + Ret.reserve(NumSymbols); + for (std::vector<GdbSymbol> &Vec : Symbols) + for (GdbSymbol &Sym : Vec) + Ret.push_back(std::move(Sym)); + + // CU vectors and symbol names are adjacent in the output file. + // We can compute their offsets in the output file now. + size_t Off = 0; + for (GdbSymbol &Sym : Ret) { + Sym.CuVectorOff = Off; + Off += (Sym.CuVector.size() + 1) * 4; + } + for (GdbSymbol &Sym : Ret) { + Sym.NameOff = Off; + Off += Sym.Name.size() + 1; } - StringPoolSize = Off; return Ret; } -template <class ELFT> GdbIndexSection *elf::createGdbIndex() { - // Gather debug info to create a .gdb_index section. +// Returns a newly-created .gdb_index section. +template <class ELFT> GdbIndexSection *GdbIndexSection::create() { std::vector<InputSection *> Sections = getDebugInfoSections(); - std::vector<GdbIndexChunk> Chunks(Sections.size()); - - parallelForEachN(0, Chunks.size(), [&](size_t I) { - ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>(); - DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File)); - - Chunks[I].DebugInfoSec = Sections[I]; - Chunks[I].CompilationUnits = readCuList(Dwarf); - Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]); - Chunks[I].NamesAndTypes = readPubNamesAndTypes(Dwarf); - }); // .debug_gnu_pub{names,types} are useless in executables. // They are present in input object files solely for creating - // a .gdb_index. So we can remove it from the output. + // a .gdb_index. So we can remove them from the output. for (InputSectionBase *S : InputSections) if (S->Name == ".debug_gnu_pubnames" || S->Name == ".debug_gnu_pubtypes") S->Live = false; - // Create a .gdb_index and returns it. - return make<GdbIndexSection>(std::move(Chunks)); -} + std::vector<GdbChunk> Chunks(Sections.size()); + std::vector<std::vector<NameTypeEntry>> NameTypes(Sections.size()); -static size_t getCuSize(ArrayRef<GdbIndexChunk> Arr) { - size_t Ret = 0; - for (const GdbIndexChunk &D : Arr) - Ret += D.CompilationUnits.size(); - return Ret; -} - -static size_t getAddressAreaSize(ArrayRef<GdbIndexChunk> Arr) { - size_t Ret = 0; - for (const GdbIndexChunk &D : Arr) - Ret += D.AddressAreas.size(); - return Ret; -} - -std::vector<GdbSymbol *> GdbIndexSection::createGdbSymtab() { - uint32_t Size = NextPowerOf2(Symbols.size() * 4 / 3); - if (Size < 1024) - Size = 1024; - - uint32_t Mask = Size - 1; - std::vector<GdbSymbol *> Ret(Size); + parallelForEachN(0, Sections.size(), [&](size_t I) { + ObjFile<ELFT> *File = Sections[I]->getFile<ELFT>(); + DWARFContext Dwarf(make_unique<LLDDwarfObj<ELFT>>(File)); - for (auto &KV : Symbols) { - GdbSymbol *Sym = KV.second; - uint32_t I = Sym->NameHash & Mask; - uint32_t Step = ((Sym->NameHash * 17) & Mask) | 1; + Chunks[I].Sec = Sections[I]; + Chunks[I].CompilationUnits = readCuList(Dwarf); + Chunks[I].AddressAreas = readAddressAreas(Dwarf, Sections[I]); + NameTypes[I] = readPubNamesAndTypes(Dwarf, I); + }); - while (Ret[I]) - I = (I + Step) & Mask; - Ret[I] = Sym; - } + auto *Ret = make<GdbIndexSection>(); + Ret->Chunks = std::move(Chunks); + Ret->Symbols = createSymbols(NameTypes); + Ret->initOutputSize(); return Ret; } -GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&C) - : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), Chunks(std::move(C)) { - fixCuIndex(); - CuVectors = createCuVectors(); - GdbSymtab = createGdbSymtab(); - - // Compute offsets early to know the section size. - // Each chunk size needs to be in sync with what we write in writeTo. - CuTypesOffset = CuListOffset + getCuSize(Chunks) * 16; - SymtabOffset = CuTypesOffset + getAddressAreaSize(Chunks) * 20; - ConstantPoolOffset = SymtabOffset + GdbSymtab.size() * 8; - - size_t Off = 0; - for (ArrayRef<uint32_t> Vec : CuVectors) { - CuVectorOffsets.push_back(Off); - Off += (Vec.size() + 1) * 4; - } - StringPoolOffset = ConstantPoolOffset + Off; -} - -size_t GdbIndexSection::getSize() const { - return StringPoolOffset + StringPoolSize; -} - void GdbIndexSection::writeTo(uint8_t *Buf) { - // Write the section header. - write32le(Buf, 7); - write32le(Buf + 4, CuListOffset); - write32le(Buf + 8, CuTypesOffset); - write32le(Buf + 12, CuTypesOffset); - write32le(Buf + 16, SymtabOffset); - write32le(Buf + 20, ConstantPoolOffset); - Buf += 24; + // Write the header. + auto *Hdr = reinterpret_cast<GdbIndexHeader *>(Buf); + uint8_t *Start = Buf; + Hdr->Version = 7; + Buf += sizeof(*Hdr); // Write the CU list. - for (GdbIndexChunk &D : Chunks) { - for (GdbIndexChunk::CuEntry &Cu : D.CompilationUnits) { - write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset); + Hdr->CuListOff = Buf - Start; + for (GdbChunk &Chunk : Chunks) { + for (CuEntry &Cu : Chunk.CompilationUnits) { + write64le(Buf, Chunk.Sec->OutSecOff + Cu.CuOffset); write64le(Buf + 8, Cu.CuLength); Buf += 16; } } // Write the address area. - for (GdbIndexChunk &D : Chunks) { - for (GdbIndexChunk::AddressEntry &E : D.AddressAreas) { - uint64_t BaseAddr = - E.Section->getParent()->Addr + E.Section->getOffset(0); + Hdr->CuTypesOff = Buf - Start; + Hdr->AddressAreaOff = Buf - Start; + uint32_t CuOff = 0; + for (GdbChunk &Chunk : Chunks) { + for (AddressEntry &E : Chunk.AddressAreas) { + uint64_t BaseAddr = E.Section->getVA(0); write64le(Buf, BaseAddr + E.LowAddress); write64le(Buf + 8, BaseAddr + E.HighAddress); - write32le(Buf + 16, E.CuIndex); + write32le(Buf + 16, E.CuIndex + CuOff); Buf += 20; } + CuOff += Chunk.CompilationUnits.size(); } - // Write the symbol table. - for (GdbSymbol *Sym : GdbSymtab) { - if (Sym) { - write32le(Buf, Sym->NameOffset + StringPoolOffset - ConstantPoolOffset); - write32le(Buf + 4, CuVectorOffsets[Sym->CuVectorIndex]); - } - Buf += 8; + // Write the on-disk open-addressing hash table containing symbols. + Hdr->SymtabOff = Buf - Start; + size_t SymtabSize = computeSymtabSize(); + uint32_t Mask = SymtabSize - 1; + + for (GdbSymbol &Sym : Symbols) { + uint32_t H = Sym.Name.hash(); + uint32_t I = H & Mask; + uint32_t Step = ((H * 17) & Mask) | 1; + + while (read32le(Buf + I * 8)) + I = (I + Step) & Mask; + + write32le(Buf + I * 8, Sym.NameOff); + write32le(Buf + I * 8 + 4, Sym.CuVectorOff); } + Buf += SymtabSize * 8; + + // Write the string pool. + Hdr->ConstantPoolOff = Buf - Start; + for (GdbSymbol &Sym : Symbols) + memcpy(Buf + Sym.NameOff, Sym.Name.data(), Sym.Name.size()); + // Write the CU vectors. - for (ArrayRef<uint32_t> Vec : CuVectors) { - write32le(Buf, Vec.size()); + for (GdbSymbol &Sym : Symbols) { + write32le(Buf, Sym.CuVector.size()); Buf += 4; - for (uint32_t Val : Vec) { + for (uint32_t Val : Sym.CuVector) { write32le(Buf, Val); Buf += 4; } } - - // Write the string pool. - for (auto &KV : Symbols) { - CachedHashStringRef S = KV.first; - GdbSymbol *Sym = KV.second; - size_t Off = Sym->NameOffset; - memcpy(Buf + Off, S.val().data(), S.size()); - Buf[Off + S.size()] = '\0'; - } } bool GdbIndexSection::empty() const { return !Out::DebugInfo; } EhFrameHeader::EhFrameHeader() - : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 1, ".eh_frame_hdr") {} + : SyntheticSection(SHF_ALLOC, SHT_PROGBITS, 4, ".eh_frame_hdr") {} // .eh_frame_hdr contains a binary search table of pointers to FDEs. // Each entry of the search table consists of two values, @@ -2160,14 +2558,6 @@ void EhFrameHeader::writeTo(uint8_t *Buf) { std::vector<FdeData> Fdes = InX::EhFrame->getFdeData(); - // Sort the FDE list by their PC and uniqueify. Usually there is only - // one FDE for a PC (i.e. function), but if ICF merges two functions - // into one, there can be more than one FDEs pointing to the address. - auto Less = [](const FdeData &A, const FdeData &B) { return A.Pc < B.Pc; }; - std::stable_sort(Fdes.begin(), Fdes.end(), Less); - auto Eq = [](const FdeData &A, const FdeData &B) { return A.Pc == B.Pc; }; - Fdes.erase(std::unique(Fdes.begin(), Fdes.end(), Eq), Fdes.end()); - Buf[0] = 1; Buf[1] = DW_EH_PE_pcrel | DW_EH_PE_sdata4; Buf[2] = DW_EH_PE_udata4; @@ -2176,10 +2566,9 @@ void EhFrameHeader::writeTo(uint8_t *Buf) { write32(Buf + 8, Fdes.size()); Buf += 12; - uint64_t VA = this->getVA(); for (FdeData &Fde : Fdes) { - write32(Buf, Fde.Pc - VA); - write32(Buf + 4, Fde.FdeVA - VA); + write32(Buf, Fde.PcRel); + write32(Buf + 4, Fde.FdeVARel); Buf += 8; } } @@ -2289,11 +2678,9 @@ VersionNeedSection<ELFT>::VersionNeedSection() NextIndex = getVerDefNum() + 1; } -template <class ELFT> -void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { - SharedFile<ELFT> &File = SS->getFile<ELFT>(); - const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; - if (!Ver) { +template <class ELFT> void VersionNeedSection<ELFT>::addSymbol(Symbol *SS) { + auto &File = cast<SharedFile<ELFT>>(*SS->File); + if (SS->VerdefIndex == VER_NDX_GLOBAL) { SS->VersionId = VER_NDX_GLOBAL; return; } @@ -2303,7 +2690,9 @@ void VersionNeedSection<ELFT>::addSymbol(SharedSymbol *SS) { // for the soname. if (File.VerdefMap.empty()) Needed.push_back({&File, InX::DynStrTab->addString(File.SoName)}); + const typename ELFT::Verdef *Ver = File.Verdefs[SS->VerdefIndex]; typename SharedFile<ELFT>::NeededVer &NV = File.VerdefMap[Ver]; + // If we don't already know that we need an Elf_Vernaux for this Elf_Verdef, // prepare to create one by allocating a version identifier and creating a // dynstr entry for the version name. @@ -2429,10 +2818,8 @@ void MergeNoTailSection::finalizeContents() { parallelForEachN(0, Concurrency, [&](size_t ThreadId) { for (MergeInputSection *Sec : Sections) { for (size_t I = 0, E = Sec->Pieces.size(); I != E; ++I) { - if (!Sec->Pieces[I].Live) - continue; size_t ShardId = getShardId(Sec->Pieces[I].Hash); - if ((ShardId & (Concurrency - 1)) == ThreadId) + if ((ShardId & (Concurrency - 1)) == ThreadId && Sec->Pieces[I].Live) Sec->Pieces[I].OutputOff = Shards[ShardId].add(Sec->getData(I)); } } @@ -2469,11 +2856,20 @@ static MergeSyntheticSection *createMergeSynthetic(StringRef Name, return make<MergeNoTailSection>(Name, Type, Flags, Alignment); } -// Debug sections may be compressed by zlib. Uncompress if exists. +// Debug sections may be compressed by zlib. Decompress if exists. void elf::decompressSections() { + parallelForEach(InputSections, + [](InputSectionBase *Sec) { Sec->maybeDecompress(); }); +} + +template <class ELFT> void elf::splitSections() { + // splitIntoPieces needs to be called on each MergeInputSection + // before calling finalizeContents(). parallelForEach(InputSections, [](InputSectionBase *Sec) { - if (Sec->Live) - Sec->maybeUncompress(); + if (auto *S = dyn_cast<MergeInputSection>(Sec)) + S->splitIntoPieces(); + else if (auto *Eh = dyn_cast<EhInputSection>(Sec)) + Eh->split<ELFT>(); }); } @@ -2485,14 +2881,6 @@ void elf::decompressSections() { // that it replaces. It then finalizes each synthetic section in order // to compute an output offset for each piece of each input section. void elf::mergeSections() { - // splitIntoPieces needs to be called on each MergeInputSection - // before calling finalizeContents(). Do that first. - parallelForEach(InputSections, [](InputSectionBase *Sec) { - if (Sec->Live) - if (auto *S = dyn_cast<MergeInputSection>(Sec)) - S->splitIntoPieces(); - }); - std::vector<MergeSyntheticSection *> MergeSections; for (InputSectionBase *&S : InputSections) { MergeInputSection *MS = dyn_cast<MergeInputSection>(S); @@ -2554,8 +2942,7 @@ ARMExidxSentinelSection::ARMExidxSentinelSection() // address described by any other table entry. void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { assert(Highest); - uint64_t S = - Highest->getParent()->Addr + Highest->getOffset(Highest->getSize()); + uint64_t S = Highest->getVA(Highest->getSize()); uint64_t P = getVA(); Target->relocateOne(Buf, R_ARM_PREL31, S - P); write32le(Buf + 4, 1); @@ -2563,15 +2950,16 @@ void ARMExidxSentinelSection::writeTo(uint8_t *Buf) { // The sentinel has to be removed if there are no other .ARM.exidx entries. bool ARMExidxSentinelSection::empty() const { - OutputSection *OS = getParent(); - for (auto *B : OS->SectionCommands) - if (auto *ISD = dyn_cast<InputSectionDescription>(B)) - for (auto *S : ISD->Sections) - if (!isa<ARMExidxSentinelSection>(S)) - return false; + for (InputSection *IS : getInputSections(getParent())) + if (!isa<ARMExidxSentinelSection>(IS)) + return false; return true; } +bool ARMExidxSentinelSection::classof(const SectionBase *D) { + return D->kind() == InputSectionBase::Synthetic && D->Type == SHT_ARM_EXIDX; +} + ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, Config->Wordsize, ".text.thunk") { @@ -2580,16 +2968,13 @@ ThunkSection::ThunkSection(OutputSection *OS, uint64_t Off) } void ThunkSection::addThunk(Thunk *T) { - uint64_t Off = alignTo(Size, T->Alignment); - T->Offset = Off; Thunks.push_back(T); T->addSymbols(*this); - Size = Off + T->size(); } void ThunkSection::writeTo(uint8_t *Buf) { - for (const Thunk *T : Thunks) - T->writeTo(Buf + T->Offset, *this); + for (Thunk *T : Thunks) + T->writeTo(Buf + T->Offset); } InputSection *ThunkSection::getTargetInputSection() const { @@ -2599,6 +2984,20 @@ InputSection *ThunkSection::getTargetInputSection() const { return T->getTargetInputSection(); } +bool ThunkSection::assignOffsets() { + uint64_t Off = 0; + for (Thunk *T : Thunks) { + Off = alignTo(Off, T->Alignment); + T->setOffset(Off); + uint32_t Size = T->size(); + T->getThunkTargetSym()->Size = Size; + Off += Size; + } + bool Changed = Off != Size; + Size = Off; + return Changed; +} + InputSection *InX::ARMAttributes; BssSection *InX::Bss; BssSection *InX::BssRelRo; @@ -2620,16 +3019,22 @@ MipsRldMapSection *InX::MipsRldMap; PltSection *InX::Plt; PltSection *InX::Iplt; RelocationBaseSection *InX::RelaDyn; +RelrBaseSection *InX::RelrDyn; RelocationBaseSection *InX::RelaPlt; RelocationBaseSection *InX::RelaIplt; StringTableSection *InX::ShStrTab; StringTableSection *InX::StrTab; SymbolTableBaseSection *InX::SymTab; -template GdbIndexSection *elf::createGdbIndex<ELF32LE>(); -template GdbIndexSection *elf::createGdbIndex<ELF32BE>(); -template GdbIndexSection *elf::createGdbIndex<ELF64LE>(); -template GdbIndexSection *elf::createGdbIndex<ELF64BE>(); +template GdbIndexSection *GdbIndexSection::create<ELF32LE>(); +template GdbIndexSection *GdbIndexSection::create<ELF32BE>(); +template GdbIndexSection *GdbIndexSection::create<ELF64LE>(); +template GdbIndexSection *GdbIndexSection::create<ELF64BE>(); + +template void elf::splitSections<ELF32LE>(); +template void elf::splitSections<ELF32BE>(); +template void elf::splitSections<ELF64LE>(); +template void elf::splitSections<ELF64BE>(); template void EhFrameSection::addSection<ELF32LE>(InputSectionBase *); template void EhFrameSection::addSection<ELF32BE>(InputSectionBase *); @@ -2641,6 +3046,11 @@ template void PltSection::addEntry<ELF32BE>(Symbol &Sym); template void PltSection::addEntry<ELF64LE>(Symbol &Sym); template void PltSection::addEntry<ELF64BE>(Symbol &Sym); +template void MipsGotSection::build<ELF32LE>(); +template void MipsGotSection::build<ELF32BE>(); +template void MipsGotSection::build<ELF64LE>(); +template void MipsGotSection::build<ELF64BE>(); + template class elf::MipsAbiFlagsSection<ELF32LE>; template class elf::MipsAbiFlagsSection<ELF32BE>; template class elf::MipsAbiFlagsSection<ELF64LE>; @@ -2671,6 +3081,11 @@ template class elf::AndroidPackedRelocationSection<ELF32BE>; template class elf::AndroidPackedRelocationSection<ELF64LE>; template class elf::AndroidPackedRelocationSection<ELF64BE>; +template class elf::RelrSection<ELF32LE>; +template class elf::RelrSection<ELF32BE>; +template class elf::RelrSection<ELF64LE>; +template class elf::RelrSection<ELF64BE>; + template class elf::SymbolTableSection<ELF32LE>; template class elf::SymbolTableSection<ELF32BE>; template class elf::SymbolTableSection<ELF64LE>; diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index a990590513bb..0366c6c3f8c7 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -26,10 +26,12 @@ #include "InputSection.h" #include "llvm/ADT/MapVector.h" #include "llvm/MC/StringTableBuilder.h" +#include "llvm/Support/Endian.h" #include <functional> namespace lld { namespace elf { +class Defined; class SharedSymbol; class SyntheticSection : public InputSection { @@ -51,7 +53,6 @@ public: // If any additional finalization of contents are needed post thunk creation. virtual void postThunkContents() {} virtual bool empty() const { return false; } - uint64_t getVA() const; static bool classof(const SectionBase *D) { return D->kind() == InputSectionBase::Synthetic; @@ -78,13 +79,18 @@ public: size_t NumFdes = 0; struct FdeData { - uint32_t Pc; - uint32_t FdeVA; + uint32_t PcRel; + uint32_t FdeVARel; }; std::vector<FdeData> getFdeData() const; + ArrayRef<CieRecord *> getCieRecords() const { return CieRecords; } private: + // This is used only when parsing EhInputSection. We keep it here to avoid + // allocating one for each EhInputSection. + llvm::DenseMap<size_t, CieRecord *> OffsetToCie; + uint64_t Size = 0; template <class ELFT, class RelTy> @@ -173,12 +179,21 @@ public: bool updateAllocSize() override; void finalizeContents() override; bool empty() const override; - void addEntry(Symbol &Sym, int64_t Addend, RelExpr Expr); - bool addDynTlsEntry(Symbol &Sym); - bool addTlsIndex(); - uint64_t getPageEntryOffset(const Symbol &B, int64_t Addend) const; - uint64_t getSymEntryOffset(const Symbol &B, int64_t Addend) const; - uint64_t getGlobalDynOffset(const Symbol &B) const; + + // Join separate GOTs built for each input file to generate + // primary and optional multiple secondary GOTs. + template <class ELFT> void build(); + + void addEntry(InputFile &File, Symbol &Sym, int64_t Addend, RelExpr Expr); + void addDynTlsEntry(InputFile &File, Symbol &Sym); + void addTlsIndex(InputFile &File); + + uint64_t getPageEntryOffset(const InputFile *F, const Symbol &S, + int64_t Addend) const; + uint64_t getSymEntryOffset(const InputFile *F, const Symbol &S, + int64_t Addend) const; + uint64_t getGlobalDynOffset(const InputFile *F, const Symbol &S) const; + uint64_t getTlsIndexOffset(const InputFile *F) const; // Returns the symbol which corresponds to the first entry of the global part // of GOT on MIPS platform. It is required to fill up MIPS-specific dynamic @@ -190,13 +205,8 @@ public: // the number of reserved entries. unsigned getLocalEntriesNum() const; - // Returns offset of TLS part of the MIPS GOT table. This part goes - // after 'local' and 'global' entries. - uint64_t getTlsOffset() const; - - uint32_t getTlsIndexOff() const { return TlsIndexOff; } - - uint64_t getGp() const; + // Return _gp value for primary GOT (nullptr) or particular input file. + uint64_t getGp(const InputFile *F = nullptr) const; private: // MIPS GOT consists of three parts: local, global and tls. Each part @@ -235,32 +245,110 @@ private: // addressing, but MIPS ABI requires that these entries be present in GOT. // TLS entries: // Entries created by TLS relocations. + // + // If the sum of local, global and tls entries is less than 64K only single + // got is enough. Otherwise, multi-got is created. Series of primary and + // multiple secondary GOTs have the following layout: + // - Primary GOT + // Header + // Local entries + // Global entries + // Relocation only entries + // TLS entries + // + // - Secondary GOT + // Local entries + // Global entries + // TLS entries + // ... + // + // All GOT entries required by relocations from a single input file entirely + // belong to either primary or one of secondary GOTs. To reference GOT entries + // each GOT has its own _gp value points to the "middle" of the GOT. + // In the code this value loaded to the register which is used for GOT access. + // + // MIPS 32 function's prologue: + // lui v0,0x0 + // 0: R_MIPS_HI16 _gp_disp + // addiu v0,v0,0 + // 4: R_MIPS_LO16 _gp_disp + // + // MIPS 64: + // lui at,0x0 + // 14: R_MIPS_GPREL16 main + // + // Dynamic linker does not know anything about secondary GOTs and cannot + // use a regular MIPS mechanism for GOT entries initialization. So we have + // to use an approach accepted by other architectures and create dynamic + // relocations R_MIPS_REL32 to initialize global entries (and local in case + // of PIC code) in secondary GOTs. But ironically MIPS dynamic linker + // requires GOT entries and correspondingly ordered dynamic symbol table + // entries to deal with dynamic relocations. To handle this problem + // relocation-only section in the primary GOT contains entries for all + // symbols referenced in global parts of secondary GOTs. Although the sum + // of local and normal global entries of the primary got should be less + // than 64K, the size of the primary got (including relocation-only entries + // can be greater than 64K, because parts of the primary got that overflow + // the 64K limit are used only by the dynamic linker at dynamic link-time + // and not by 16-bit gp-relative addressing at run-time. + // + // For complete multi-GOT description see the following link + // https://dmz-portal.mips.com/wiki/MIPS_Multi_GOT // Number of "Header" entries. static const unsigned HeaderEntriesNum = 2; - // Number of allocated "Page" entries. - uint32_t PageEntriesNum = 0; - // Map output sections referenced by MIPS GOT relocations - // to the first index of "Page" entries allocated for this section. - llvm::SmallMapVector<const OutputSection *, size_t, 16> PageIndexMap; - - typedef std::pair<const Symbol *, uint64_t> GotEntry; - typedef std::vector<GotEntry> GotEntries; - // Map from Symbol-Addend pair to the GOT index. - llvm::DenseMap<GotEntry, size_t> EntryIndexMap; - // Local entries (16-bit access). - GotEntries LocalEntries; - // Local entries (32-bit access). - GotEntries LocalEntries32; - - // Normal and reloc-only global entries. - GotEntries GlobalEntries; - - // TLS entries. - std::vector<const Symbol *> TlsEntries; - uint32_t TlsIndexOff = -1; uint64_t Size = 0; + + size_t LocalEntriesNum = 0; + + // Symbol and addend. + typedef std::pair<Symbol *, int64_t> GotEntry; + + struct FileGot { + InputFile *File = nullptr; + size_t StartIndex = 0; + + struct PageBlock { + size_t FirstIndex = 0; + size_t Count = 0; + }; + + // Map output sections referenced by MIPS GOT relocations + // to the description (index/count) "page" entries allocated + // for this section. + llvm::SmallMapVector<const OutputSection *, PageBlock, 16> PagesMap; + // Maps from Symbol+Addend pair or just Symbol to the GOT entry index. + llvm::MapVector<GotEntry, size_t> Local16; + llvm::MapVector<GotEntry, size_t> Local32; + llvm::MapVector<Symbol *, size_t> Global; + llvm::MapVector<Symbol *, size_t> Relocs; + llvm::MapVector<Symbol *, size_t> Tls; + // Set of symbols referenced by dynamic TLS relocations. + llvm::MapVector<Symbol *, size_t> DynTlsSymbols; + + // Total number of all entries. + size_t getEntriesNum() const; + // Number of "page" entries. + size_t getPageEntriesNum() const; + // Number of entries require 16-bit index to access. + size_t getIndexedEntriesNum() const; + + bool isOverflow() const; + }; + + // Container of GOT created for each input file. + // After building a final series of GOTs this container + // holds primary and secondary GOT's. + std::vector<FileGot> Gots; + + // Return (and create if necessary) `FileGot`. + FileGot &getGot(InputFile &F); + + // Try to merge two GOTs. In case of success the `Dst` contains + // result of merging and the function returns true. In case of + // ovwerflow the `Dst` is unchanged and the function returns false. + bool tryMergeGots(FileGot & Dst, FileGot & Src, bool IsPrimary); }; class GotPltSection final : public SyntheticSection { @@ -269,7 +357,7 @@ public: void addEntry(Symbol &Sym); size_t getSize() const override; void writeTo(uint8_t *Buf) override; - bool empty() const override { return Entries.empty(); } + bool empty() const override; private: std::vector<const Symbol *> Entries; @@ -310,30 +398,48 @@ private: class DynamicReloc { public: - DynamicReloc(uint32_t Type, const InputSectionBase *InputSec, + DynamicReloc(RelType Type, const InputSectionBase *InputSec, uint64_t OffsetInSec, bool UseSymVA, Symbol *Sym, int64_t Addend) : Type(Type), Sym(Sym), InputSec(InputSec), OffsetInSec(OffsetInSec), - UseSymVA(UseSymVA), Addend(Addend) {} + UseSymVA(UseSymVA), Addend(Addend), OutputSec(nullptr) {} + // This constructor records dynamic relocation settings used by MIPS + // multi-GOT implementation. It's to relocate addresses of 64kb pages + // lie inside the output section. + DynamicReloc(RelType Type, const InputSectionBase *InputSec, + uint64_t OffsetInSec, const OutputSection *OutputSec, + int64_t Addend) + : Type(Type), Sym(nullptr), InputSec(InputSec), OffsetInSec(OffsetInSec), + UseSymVA(false), Addend(Addend), OutputSec(OutputSec) {} uint64_t getOffset() const; - int64_t getAddend() const; uint32_t getSymIndex() const; const InputSectionBase *getInputSec() const { return InputSec; } - uint32_t Type; + // Computes the addend of the dynamic relocation. Note that this is not the + // same as the Addend member variable as it also includes the symbol address + // if UseSymVA is true. + int64_t computeAddend() const; + + RelType Type; private: Symbol *Sym; const InputSectionBase *InputSec = nullptr; uint64_t OffsetInSec; + // If this member is true, the dynamic relocation will not be against the + // symbol but will instead be a relative relocation that simply adds the + // load address. This means we need to write the symbol virtual address + // plus the original addend as the final relocation addend. bool UseSymVA; int64_t Addend; + const OutputSection *OutputSec; }; template <class ELFT> class DynamicSection final : public SyntheticSection { typedef typename ELFT::Dyn Elf_Dyn; typedef typename ELFT::Rel Elf_Rel; typedef typename ELFT::Rela Elf_Rela; + typedef typename ELFT::Relr Elf_Relr; typedef typename ELFT::Shdr Elf_Shdr; typedef typename ELFT::Sym Elf_Sym; @@ -350,6 +456,7 @@ private: void add(int32_t Tag, std::function<uint64_t()> Fn); void addInt(int32_t Tag, uint64_t Val); void addInSec(int32_t Tag, InputSection *Sec); + void addInSecRelative(int32_t Tag, InputSection *Sec); void addOutSec(int32_t Tag, OutputSection *Sec); void addSize(int32_t Tag, OutputSection *Sec); void addSym(int32_t Tag, Symbol *Sym); @@ -361,6 +468,13 @@ class RelocationBaseSection : public SyntheticSection { public: RelocationBaseSection(StringRef Name, uint32_t Type, int32_t DynamicTag, int32_t SizeDynamicTag); + void addReloc(RelType DynType, InputSectionBase *IS, uint64_t OffsetInSec, + Symbol *Sym); + // Add a dynamic relocation that might need an addend. This takes care of + // writing the addend to the output section if needed. + void addReloc(RelType DynType, InputSectionBase *InputSec, + uint64_t OffsetInSec, Symbol *Sym, int64_t Addend, RelExpr Expr, + RelType Type); void addReloc(const DynamicReloc &Reloc); bool empty() const override { return Relocs.empty(); } size_t getSize() const override { return Relocs.size() * this->Entsize; } @@ -405,6 +519,39 @@ private: SmallVector<char, 0> RelocData; }; +struct RelativeReloc { + uint64_t getOffset() const { return InputSec->getVA(OffsetInSec); } + + const InputSectionBase *InputSec; + uint64_t OffsetInSec; +}; + +class RelrBaseSection : public SyntheticSection { +public: + RelrBaseSection(); + std::vector<RelativeReloc> Relocs; +}; + +// RelrSection is used to encode offsets for relative relocations. +// Proposal for adding SHT_RELR sections to generic-abi is here: +// https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg +// For more details, see the comment in RelrSection::updateAllocSize(). +template <class ELFT> class RelrSection final : public RelrBaseSection { + typedef typename ELFT::Relr Elf_Relr; + +public: + RelrSection(); + + bool updateAllocSize() override; + size_t getSize() const override { return RelrRelocs.size() * this->Entsize; } + void writeTo(uint8_t *Buf) override { + memcpy(Buf, RelrRelocs.data(), getSize()); + } + +private: + std::vector<Elf_Relr> RelrRelocs; +}; + struct SymbolTableEntry { Symbol *Sym; size_t StrTabOffset; @@ -455,7 +602,7 @@ public: void addSymbols(std::vector<SymbolTableEntry> &Symbols); private: - size_t getShift2() const { return Config->Is64 ? 6 : 5; } + enum { Shift2 = 6 }; void writeBloomFilter(uint8_t *Buf); void writeHashTable(uint8_t *Buf); @@ -484,13 +631,13 @@ private: size_t Size = 0; }; -// The PltSection is used for both the Plt and Iplt. The former always has a +// The PltSection is used for both the Plt and Iplt. The former usually has a // header as its first entry that is used at run-time to resolve lazy binding. // The latter is used for GNU Ifunc symbols, that will be subject to a // Target->IRelativeRel. class PltSection : public SyntheticSection { public: - PltSection(size_t HeaderSize); + PltSection(bool IsIplt); void writeTo(uint8_t *Buf) override; size_t getSize() const override; bool empty() const override { return Entries.empty(); } @@ -501,13 +648,12 @@ public: private: unsigned getPltRelocOff() const; std::vector<std::pair<const Symbol *, unsigned>> Entries; - // Iplt always has HeaderSize of 0, the Plt HeaderSize is always non-zero size_t HeaderSize; + bool IsIplt; }; -// GdbIndexChunk is created for each .debug_info section and contains -// information to create a part of .gdb_index for a given input section. -struct GdbIndexChunk { +class GdbIndexSection final : public SyntheticSection { +public: struct AddressEntry { InputSection *Section; uint64_t LowAddress; @@ -522,59 +668,51 @@ struct GdbIndexChunk { struct NameTypeEntry { llvm::CachedHashStringRef Name; - uint8_t Type; + uint32_t Type; }; - InputSection *DebugInfoSec; - std::vector<AddressEntry> AddressAreas; - std::vector<CuEntry> CompilationUnits; - std::vector<NameTypeEntry> NamesAndTypes; -}; + struct GdbChunk { + InputSection *Sec; + std::vector<AddressEntry> AddressAreas; + std::vector<CuEntry> CompilationUnits; + }; -// The symbol type for the .gdb_index section. -struct GdbSymbol { - uint32_t NameHash; - size_t NameOffset; - size_t CuVectorIndex; -}; + struct GdbSymbol { + llvm::CachedHashStringRef Name; + std::vector<uint32_t> CuVector; + uint32_t NameOff; + uint32_t CuVectorOff; + }; -class GdbIndexSection final : public SyntheticSection { -public: - GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks); + GdbIndexSection(); + template <typename ELFT> static GdbIndexSection *create(); void writeTo(uint8_t *Buf) override; - size_t getSize() const override; + size_t getSize() const override { return Size; } bool empty() const override; private: - void fixCuIndex(); - std::vector<std::vector<uint32_t>> createCuVectors(); - std::vector<GdbSymbol *> createGdbSymtab(); - - // A symbol table for this .gdb_index section. - std::vector<GdbSymbol *> GdbSymtab; - - // CU vector is a part of constant pool area of section. - std::vector<std::vector<uint32_t>> CuVectors; + struct GdbIndexHeader { + llvm::support::ulittle32_t Version; + llvm::support::ulittle32_t CuListOff; + llvm::support::ulittle32_t CuTypesOff; + llvm::support::ulittle32_t AddressAreaOff; + llvm::support::ulittle32_t SymtabOff; + llvm::support::ulittle32_t ConstantPoolOff; + }; - // Symbol table contents. - llvm::DenseMap<llvm::CachedHashStringRef, GdbSymbol *> Symbols; + void initOutputSize(); + size_t computeSymtabSize() const; - // Each chunk contains information gathered from a debug sections of single - // object and used to build different areas of gdb index. - std::vector<GdbIndexChunk> Chunks; + // Each chunk contains information gathered from debug sections of a + // single object file. + std::vector<GdbChunk> Chunks; - static constexpr uint32_t CuListOffset = 24; - uint32_t CuTypesOffset; - uint32_t SymtabOffset; - uint32_t ConstantPoolOffset; - uint32_t StringPoolOffset; - uint32_t StringPoolSize; + // A symbol table for this .gdb_index section. + std::vector<GdbSymbol> Symbols; - std::vector<size_t> CuVectorOffsets; + size_t Size; }; -template <class ELFT> GdbIndexSection *createGdbIndex(); - // --eh-frame-hdr option tells linker to construct a header for all the // .eh_frame sections. This header is placed to a section named .eh_frame_hdr // and also to a PT_GNU_EH_FRAME segment. @@ -653,7 +791,7 @@ template <class ELFT> class VersionNeedSection final : public SyntheticSection { public: VersionNeedSection(); - void addSymbol(SharedSymbol *SS); + void addSymbol(Symbol *Sym); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; @@ -668,13 +806,12 @@ public: class MergeSyntheticSection : public SyntheticSection { public: void addSection(MergeInputSection *MS); + std::vector<MergeInputSection *> Sections; protected: MergeSyntheticSection(StringRef Name, uint32_t Type, uint64_t Flags, uint32_t Alignment) : SyntheticSection(Flags, Type, Alignment, Name) {} - - std::vector<MergeInputSection *> Sections; }; class MergeTailSection final : public MergeSyntheticSection { @@ -787,7 +924,12 @@ public: void writeTo(uint8_t *Buf) override; bool empty() const override; - InputSection *Highest = 0; + static bool classof(const SectionBase *D); + + // The last section referenced by a regular .ARM.exidx section. + // It is found and filled in Writer<ELFT>::resolveShfLinkOrder(). + // The sentinel points at the end of that section. + InputSection *Highest = nullptr; }; // A container for one or more linker generated thunks. Instances of these @@ -805,19 +947,21 @@ public: size_t getSize() const override { return Size; } void writeTo(uint8_t *Buf) override; InputSection *getTargetInputSection() const; + bool assignOffsets(); private: - std::vector<const Thunk *> Thunks; + std::vector<Thunk *> Thunks; size_t Size = 0; }; InputSection *createInterpSection(); MergeInputSection *createCommentSection(); void decompressSections(); +template <class ELFT> void splitSections(); void mergeSections(); -Symbol *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, - uint64_t Size, InputSectionBase &Section); +Defined *addSyntheticLocal(StringRef Name, uint8_t Type, uint64_t Value, + uint64_t Size, InputSectionBase &Section); // Linker generated sections which can be used as inputs. struct InX { @@ -842,6 +986,7 @@ struct InX { static PltSection *Plt; static PltSection *Iplt; static RelocationBaseSection *RelaDyn; + static RelrBaseSection *RelrDyn; static RelocationBaseSection *RelaPlt; static RelocationBaseSection *RelaIplt; static StringTableSection *ShStrTab; diff --git a/ELF/Target.cpp b/ELF/Target.cpp index b528fd583c1a..815f3a045551 100644 --- a/ELF/Target.cpp +++ b/ELF/Target.cpp @@ -60,6 +60,8 @@ TargetInfo *elf::getTarget() { return getARMTargetInfo(); case EM_AVR: return getAVRTargetInfo(); + case EM_HEXAGON: + return getHexagonTargetInfo(); case EM_MIPS: switch (Config->EKind) { case ELF32LEKind: @@ -87,29 +89,29 @@ TargetInfo *elf::getTarget() { fatal("unknown target machine"); } -template <class ELFT> static std::string getErrorLoc(const uint8_t *Loc) { +template <class ELFT> static ErrorPlace getErrPlace(const uint8_t *Loc) { for (InputSectionBase *D : InputSections) { - auto *IS = dyn_cast<InputSection>(D); - if (!IS || !IS->getParent()) + auto *IS = cast<InputSection>(D); + if (!IS->getParent()) continue; uint8_t *ISLoc = IS->getParent()->Loc + IS->OutSecOff; if (ISLoc <= Loc && Loc < ISLoc + IS->getSize()) - return IS->template getLocation<ELFT>(Loc - ISLoc) + ": "; + return {IS, IS->template getLocation<ELFT>(Loc - ISLoc) + ": "}; } - return ""; + return {}; } -std::string elf::getErrorLocation(const uint8_t *Loc) { +ErrorPlace elf::getErrorPlace(const uint8_t *Loc) { switch (Config->EKind) { case ELF32LEKind: - return getErrorLoc<ELF32LE>(Loc); + return getErrPlace<ELF32LE>(Loc); case ELF32BEKind: - return getErrorLoc<ELF32BE>(Loc); + return getErrPlace<ELF32BE>(Loc); case ELF64LEKind: - return getErrorLoc<ELF64LE>(Loc); + return getErrPlace<ELF64LE>(Loc); case ELF64BEKind: - return getErrorLoc<ELF64BE>(Loc); + return getErrPlace<ELF64BE>(Loc); default: llvm_unreachable("unknown ELF type"); } @@ -128,6 +130,12 @@ bool TargetInfo::needsThunk(RelExpr Expr, RelType Type, const InputFile *File, return false; } +bool TargetInfo::adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const { + llvm_unreachable("Target doesn't support split stacks."); +} + + bool TargetInfo::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const { return true; } diff --git a/ELF/Target.h b/ELF/Target.h index 1f58adba1817..82c7b8f7b6c5 100644 --- a/ELF/Target.h +++ b/ELF/Target.h @@ -25,9 +25,9 @@ class Symbol; class TargetInfo { public: virtual uint32_t calcEFlags() const { return 0; } - virtual bool isPicRel(RelType Type) const { return true; } virtual RelType getDynRel(RelType Type) const { return Type; } virtual void writeGotPltHeader(uint8_t *Buf) const {} + virtual void writeGotHeader(uint8_t *Buf) const {} virtual void writeGotPlt(uint8_t *Buf, const Symbol &S) const {}; virtual void writeIgotPlt(uint8_t *Buf, const Symbol &S) const; virtual int64_t getImplicitAddend(const uint8_t *Buf, RelType Type) const; @@ -43,8 +43,12 @@ public: virtual void addPltHeaderSymbols(InputSection &IS) const {} virtual void addPltSymbols(InputSection &IS, uint64_t Off) const {} + unsigned getPltEntryOffset(unsigned Index) const { + return Index * PltEntrySize + PltHeaderSize; + } + // Returns true if a relocation only uses the low bits of a value such that - // all those bits are in in the same page. For example, if the relocation + // all those bits are in the same page. For example, if the relocation // only uses the low 12 bits in a system with 4k pages. If this is true, the // bits will always have the same value at runtime and we don't have to emit // a dynamic relocation. @@ -55,6 +59,13 @@ public: virtual bool needsThunk(RelExpr Expr, RelType RelocType, const InputFile *File, uint64_t BranchAddr, const Symbol &S) const; + + // The function with a prologue starting at Loc was compiled with + // -fsplit-stack and it calls a function compiled without. Adjust the prologue + // to do the right thing. See https://gcc.gnu.org/wiki/SplitStacks. + virtual bool adjustPrologueForCrossSplitStack(uint8_t *Loc, + uint8_t *End) const; + // Return true if we can reach Dst from Src with Relocation RelocType virtual bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const; @@ -71,9 +82,10 @@ public: uint64_t getImageBase(); - // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got section. Use -1 for - // end of .got + // Offset of _GLOBAL_OFFSET_TABLE_ from base of .got or .got.plt section. uint64_t GotBaseSymOff = 0; + // True if _GLOBAL_OFFSET_TABLE_ is relative to .got.plt, false if .got. + bool GotBaseSymInGotPlt = true; // On systems with range extensions we place collections of Thunks at // regular spacings that enable the majority of branches reach the Thunks. @@ -97,9 +109,18 @@ public: // to support lazy loading. unsigned GotPltHeaderEntriesNum = 3; - // Set to 0 for variant 2 + // On PPC ELF V2 abi, the first entry in the .got is the .TOC. + unsigned GotHeaderEntriesNum = 0; + + // For TLS variant 1, the TCB is a fixed size specified by the Target. + // For variant 2, the TCB is an unspecified size. + // Set to 0 for variant 2. unsigned TcbSize = 0; + // Set to the offset (in bytes) that the thread pointer is initialized to + // point to, relative to the start of the thread local storage. + unsigned TlsTpOffset = 0; + bool NeedsThunks = false; // A 4-byte field corresponding to one or more trap instructions, used to pad @@ -126,6 +147,7 @@ TargetInfo *getAArch64TargetInfo(); TargetInfo *getAMDGPUTargetInfo(); TargetInfo *getARMTargetInfo(); TargetInfo *getAVRTargetInfo(); +TargetInfo *getHexagonTargetInfo(); TargetInfo *getPPC64TargetInfo(); TargetInfo *getPPCTargetInfo(); TargetInfo *getSPARCV9TargetInfo(); @@ -134,7 +156,17 @@ TargetInfo *getX86TargetInfo(); TargetInfo *getX86_64TargetInfo(); template <class ELFT> TargetInfo *getMipsTargetInfo(); -std::string getErrorLocation(const uint8_t *Loc); +struct ErrorPlace { + InputSectionBase *IS; + std::string Loc; +}; + +// Returns input section and corresponding source string for the given location. +ErrorPlace getErrorPlace(const uint8_t *Loc); + +static inline std::string getErrorLocation(const uint8_t *Loc) { + return getErrorPlace(Loc).Loc; +} uint64_t getPPC64TocBase(); uint64_t getAArch64Page(uint64_t Expr); @@ -146,39 +178,74 @@ template <class ELFT> bool isMipsPIC(const Defined *Sym); static inline void reportRangeError(uint8_t *Loc, RelType Type, const Twine &V, int64_t Min, uint64_t Max) { - error(getErrorLocation(Loc) + "relocation " + lld::toString(Type) + - " out of range: " + V + " is not in [" + Twine(Min) + ", " + - Twine(Max) + "]"); + ErrorPlace ErrPlace = getErrorPlace(Loc); + StringRef Hint; + if (ErrPlace.IS && ErrPlace.IS->Name.startswith(".debug")) + Hint = "; consider recompiling with -fdebug-types-section to reduce size " + "of debug sections"; + + error(ErrPlace.Loc + "relocation " + lld::toString(Type) + + " out of range: " + V.str() + " is not in [" + Twine(Min).str() + ", " + + Twine(Max).str() + "]" + Hint); } -template <unsigned N> -static void checkInt(uint8_t *Loc, int64_t V, RelType Type) { - if (!llvm::isInt<N>(V)) +// Sign-extend Nth bit all the way to MSB. +inline int64_t signExtend(uint64_t V, int N) { + return int64_t(V << (64 - N)) >> (64 - N); +} + +// Make sure that V can be represented as an N bit signed integer. +inline void checkInt(uint8_t *Loc, int64_t V, int N, RelType Type) { + if (V != signExtend(V, N)) reportRangeError(Loc, Type, Twine(V), llvm::minIntN(N), llvm::maxIntN(N)); } -template <unsigned N> -static void checkUInt(uint8_t *Loc, uint64_t V, RelType Type) { - if (!llvm::isUInt<N>(V)) +// Make sure that V can be represented as an N bit unsigned integer. +inline void checkUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) { + if ((V >> N) != 0) reportRangeError(Loc, Type, Twine(V), 0, llvm::maxUIntN(N)); } -template <unsigned N> -static void checkIntUInt(uint8_t *Loc, uint64_t V, RelType Type) { - if (!llvm::isInt<N>(V) && !llvm::isUInt<N>(V)) - // For the error message we should cast V to a signed integer so that error - // messages show a small negative value rather than an extremely large one +// Make sure that V can be represented as an N bit signed or unsigned integer. +inline void checkIntUInt(uint8_t *Loc, uint64_t V, int N, RelType Type) { + // For the error message we should cast V to a signed integer so that error + // messages show a small negative value rather than an extremely large one + if (V != (uint64_t)signExtend(V, N) && (V >> N) != 0) reportRangeError(Loc, Type, Twine((int64_t)V), llvm::minIntN(N), - llvm::maxUIntN(N)); + llvm::maxIntN(N)); } -template <unsigned N> -static void checkAlignment(uint8_t *Loc, uint64_t V, RelType Type) { +inline void checkAlignment(uint8_t *Loc, uint64_t V, int N, RelType Type) { if ((V & (N - 1)) != 0) error(getErrorLocation(Loc) + "improper alignment for relocation " + lld::toString(Type) + ": 0x" + llvm::utohexstr(V) + " is not aligned to " + Twine(N) + " bytes"); } + +// Endianness-aware read/write. +inline uint16_t read16(const void *P) { + return llvm::support::endian::read16(P, Config->Endianness); +} + +inline uint32_t read32(const void *P) { + return llvm::support::endian::read32(P, Config->Endianness); +} + +inline uint64_t read64(const void *P) { + return llvm::support::endian::read64(P, Config->Endianness); +} + +inline void write16(void *P, uint16_t V) { + llvm::support::endian::write16(P, V, Config->Endianness); +} + +inline void write32(void *P, uint32_t V) { + llvm::support::endian::write32(P, V, Config->Endianness); +} + +inline void write64(void *P, uint64_t V) { + llvm::support::endian::write64(P, V, Config->Endianness); +} } // namespace elf } // namespace lld diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index b0bbf6da705a..2cd7e51ae357 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -40,7 +40,6 @@ using namespace llvm; using namespace llvm::object; -using namespace llvm::support::endian; using namespace llvm::ELF; namespace lld { @@ -52,59 +51,112 @@ namespace { class AArch64ABSLongThunk final : public Thunk { public: AArch64ABSLongThunk(Symbol &Dest) : Thunk(Dest) {} - uint32_t size() const override { return 16; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t size() override { return 16; } + void writeTo(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; }; class AArch64ADRPThunk final : public Thunk { public: AArch64ADRPThunk(Symbol &Dest) : Thunk(Dest) {} - uint32_t size() const override { return 12; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t size() override { return 12; } + void writeTo(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; }; +// Base class for ARM thunks. +// +// An ARM thunk may be either short or long. A short thunk is simply a branch +// (B) instruction, and it may be used to call ARM functions when the distance +// from the thunk to the target is less than 32MB. Long thunks can branch to any +// virtual address and can switch between ARM and Thumb, and they are +// implemented in the derived classes. This class tries to create a short thunk +// if the target is in range, otherwise it creates a long thunk. +class ARMThunk : public Thunk { +public: + ARMThunk(Symbol &Dest) : Thunk(Dest) {} + + bool mayUseShortThunk(); + uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } + void writeTo(uint8_t *Buf) override; + bool isCompatibleWith(RelType Type) const override; + + // Returns the size of a long thunk. + virtual uint32_t sizeLong() = 0; + + // Writes a long thunk to Buf. + virtual void writeLong(uint8_t *Buf) = 0; + +private: + // This field tracks whether all previously considered layouts would allow + // this thunk to be short. If we have ever needed a long thunk, we always + // create a long thunk, even if the thunk may be short given the current + // distance to the target. We do this because transitioning from long to short + // can create layout oscillations in certain corner cases which would prevent + // the layout from converging. + bool MayUseShortThunk = true; +}; + +// Base class for Thumb-2 thunks. +// +// This class is similar to ARMThunk, but it uses the Thumb-2 B.W instruction +// which has a range of 16MB. +class ThumbThunk : public Thunk { +public: + ThumbThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; } + + bool mayUseShortThunk(); + uint32_t size() override { return mayUseShortThunk() ? 4 : sizeLong(); } + void writeTo(uint8_t *Buf) override; + bool isCompatibleWith(RelType Type) const override; + + // Returns the size of a long thunk. + virtual uint32_t sizeLong() = 0; + + // Writes a long thunk to Buf. + virtual void writeLong(uint8_t *Buf) = 0; + +private: + // See comment in ARMThunk above. + bool MayUseShortThunk = true; +}; + // Specific ARM Thunk implementations. The naming convention is: // Source State, TargetState, Target Requirement, ABS or PI, Range -class ARMV7ABSLongThunk final : public Thunk { +class ARMV7ABSLongThunk final : public ARMThunk { public: - ARMV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) {} + ARMV7ABSLongThunk(Symbol &Dest) : ARMThunk(Dest) {} - uint32_t size() const override { return 12; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t sizeLong() override { return 12; } + void writeLong(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(RelType Type) const override; }; -class ARMV7PILongThunk final : public Thunk { +class ARMV7PILongThunk final : public ARMThunk { public: - ARMV7PILongThunk(Symbol &Dest) : Thunk(Dest) {} + ARMV7PILongThunk(Symbol &Dest) : ARMThunk(Dest) {} - uint32_t size() const override { return 16; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t sizeLong() override { return 16; } + void writeLong(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(RelType Type) const override; }; -class ThumbV7ABSLongThunk final : public Thunk { +class ThumbV7ABSLongThunk final : public ThumbThunk { public: - ThumbV7ABSLongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; } + ThumbV7ABSLongThunk(Symbol &Dest) : ThumbThunk(Dest) {} - uint32_t size() const override { return 10; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t sizeLong() override { return 10; } + void writeLong(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(RelType Type) const override; }; -class ThumbV7PILongThunk final : public Thunk { +class ThumbV7PILongThunk final : public ThumbThunk { public: - ThumbV7PILongThunk(Symbol &Dest) : Thunk(Dest) { Alignment = 2; } + ThumbV7PILongThunk(Symbol &Dest) : ThumbThunk(Dest) {} - uint32_t size() const override { return 12; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t sizeLong() override { return 12; } + void writeLong(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; - bool isCompatibleWith(RelType Type) const override; }; // MIPS LA25 thunk @@ -112,8 +164,8 @@ class MipsThunk final : public Thunk { public: MipsThunk(Symbol &Dest) : Thunk(Dest) {} - uint32_t size() const override { return 16; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t size() override { return 16; } + void writeTo(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; InputSection *getTargetInputSection() const override; }; @@ -123,8 +175,8 @@ class MicroMipsThunk final : public Thunk { public: MicroMipsThunk(Symbol &Dest) : Thunk(Dest) {} - uint32_t size() const override { return 14; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t size() override { return 14; } + void writeTo(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; InputSection *getTargetInputSection() const override; }; @@ -134,14 +186,44 @@ class MicroMipsR6Thunk final : public Thunk { public: MicroMipsR6Thunk(Symbol &Dest) : Thunk(Dest) {} - uint32_t size() const override { return 12; } - void writeTo(uint8_t *Buf, ThunkSection &IS) const override; + uint32_t size() override { return 12; } + void writeTo(uint8_t *Buf) override; void addSymbols(ThunkSection &IS) override; InputSection *getTargetInputSection() const override; }; + +// PPC64 Plt call stubs. +// Any call site that needs to call through a plt entry needs a call stub in +// the .text section. The call stub is responsible for: +// 1) Saving the toc-pointer to the stack. +// 2) Loading the target functions address from the procedure linkage table into +// r12 for use by the target functions global entry point, and into the count +// register. +// 3) Transfering control to the target function through an indirect branch. +class PPC64PltCallStub final : public Thunk { +public: + PPC64PltCallStub(Symbol &Dest) : Thunk(Dest) {} + uint32_t size() override { return 20; } + void writeTo(uint8_t *Buf) override; + void addSymbols(ThunkSection &IS) override; +}; + } // end anonymous namespace +Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value, + InputSectionBase &Section) { + Defined *D = addSyntheticLocal(Name, Type, Value, /*Size=*/0, Section); + Syms.push_back(D); + return D; +} + +void Thunk::setOffset(uint64_t NewOffset) { + for (Defined *D : Syms) + D->Value = D->Value - Offset + NewOffset; + Offset = NewOffset; +} + // AArch64 long range Thunks static uint64_t getAArch64ThunkDestVA(const Symbol &S) { @@ -149,7 +231,7 @@ static uint64_t getAArch64ThunkDestVA(const Symbol &S) { return V; } -void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { +void AArch64ABSLongThunk::writeTo(uint8_t *Buf) { const uint8_t Data[] = { 0x50, 0x00, 0x00, 0x58, // ldr x16, L0 0x00, 0x02, 0x1f, 0xd6, // br x16 @@ -162,11 +244,10 @@ void AArch64ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { } void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); - addSyntheticLocal("$d", STT_NOTYPE, Offset + 8, 0, IS); + addSymbol(Saver.save("__AArch64AbsLongThunk_" + Destination.getName()), + STT_FUNC, 0, IS); + addSymbol("$x", STT_NOTYPE, 0, IS); + addSymbol("$d", STT_NOTYPE, 8, IS); } // This Thunk has a maximum range of 4Gb, this is sufficient for all programs @@ -174,26 +255,24 @@ void AArch64ABSLongThunk::addSymbols(ThunkSection &IS) { // clang and gcc do not support the large code model for position independent // code so it is safe to use this for position independent thunks without // worrying about the destination being more than 4Gb away. -void AArch64ADRPThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { +void AArch64ADRPThunk::writeTo(uint8_t *Buf) { const uint8_t Data[] = { 0x10, 0x00, 0x00, 0x90, // adrp x16, Dest R_AARCH64_ADR_PREL_PG_HI21(Dest) 0x10, 0x02, 0x00, 0x91, // add x16, x16, R_AARCH64_ADD_ABS_LO12_NC(Dest) 0x00, 0x02, 0x1f, 0xd6, // br x16 }; uint64_t S = getAArch64ThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA(); + uint64_t P = getThunkTargetSym()->getVA(); memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_AARCH64_ADR_PREL_PG_HI21, getAArch64Page(S) - getAArch64Page(P)); Target->relocateOne(Buf + 4, R_AARCH64_ADD_ABS_LO12_NC, S); } -void AArch64ADRPThunk::addSymbols(ThunkSection &IS) -{ - ThunkSym = addSyntheticLocal( - Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$x", STT_NOTYPE, Offset, 0, IS); +void AArch64ADRPThunk::addSymbols(ThunkSection &IS) { + addSymbol(Saver.save("__AArch64ADRPThunk_" + Destination.getName()), STT_FUNC, + 0, IS); + addSymbol("$x", STT_NOTYPE, 0, IS); } // ARM Target Thunks @@ -202,7 +281,81 @@ static uint64_t getARMThunkDestVA(const Symbol &S) { return SignExtend64<32>(V); } -void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { +// This function returns true if the target is not Thumb and is within 2^26, and +// it has not previously returned false (see comment for MayUseShortThunk). +bool ARMThunk::mayUseShortThunk() { + if (!MayUseShortThunk) + return false; + uint64_t S = getARMThunkDestVA(Destination); + if (S & 1) { + MayUseShortThunk = false; + return false; + } + uint64_t P = getThunkTargetSym()->getVA(); + int64_t Offset = S - P - 8; + MayUseShortThunk = llvm::isInt<26>(Offset); + return MayUseShortThunk; +} + +void ARMThunk::writeTo(uint8_t *Buf) { + if (!mayUseShortThunk()) { + writeLong(Buf); + return; + } + + uint64_t S = getARMThunkDestVA(Destination); + uint64_t P = getThunkTargetSym()->getVA(); + int64_t Offset = S - P - 8; + const uint8_t Data[] = { + 0x00, 0x00, 0x00, 0xea, // b S + }; + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf, R_ARM_JUMP24, Offset); +} + +bool ARMThunk::isCompatibleWith(RelType Type) const { + // Thumb branch relocations can't use BLX + return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; +} + +// This function returns true if the target is Thumb and is within 2^25, and +// it has not previously returned false (see comment for MayUseShortThunk). +bool ThumbThunk::mayUseShortThunk() { + if (!MayUseShortThunk) + return false; + uint64_t S = getARMThunkDestVA(Destination); + if ((S & 1) == 0) { + MayUseShortThunk = false; + return false; + } + uint64_t P = getThunkTargetSym()->getVA() & ~1; + int64_t Offset = S - P - 4; + MayUseShortThunk = llvm::isInt<25>(Offset); + return MayUseShortThunk; +} + +void ThumbThunk::writeTo(uint8_t *Buf) { + if (!mayUseShortThunk()) { + writeLong(Buf); + return; + } + + uint64_t S = getARMThunkDestVA(Destination); + uint64_t P = getThunkTargetSym()->getVA(); + int64_t Offset = S - P - 4; + const uint8_t Data[] = { + 0x00, 0xf0, 0x00, 0xb0, // b.w S + }; + memcpy(Buf, Data, sizeof(Data)); + Target->relocateOne(Buf, R_ARM_THM_JUMP24, Offset); +} + +bool ThumbThunk::isCompatibleWith(RelType Type) const { + // ARM branch relocations can't use BLX + return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; +} + +void ARMV7ABSLongThunk::writeLong(uint8_t *Buf) { const uint8_t Data[] = { 0x00, 0xc0, 0x00, 0xe3, // movw ip,:lower16:S 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S @@ -215,18 +368,12 @@ void ARMV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { } void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); -} - -bool ARMV7ABSLongThunk::isCompatibleWith(RelType Type) const { - // Thumb branch relocations can't use BLX - return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; + addSymbol(Saver.save("__ARMv7ABSLongThunk_" + Destination.getName()), + STT_FUNC, 0, IS); + addSymbol("$a", STT_NOTYPE, 0, IS); } -void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { +void ThumbV7ABSLongThunk::writeLong(uint8_t *Buf) { const uint8_t Data[] = { 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S 0xc0, 0xf2, 0x00, 0x0c, // movt ip, :upper16:S @@ -239,18 +386,12 @@ void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { } void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); + addSymbol(Saver.save("__Thumbv7ABSLongThunk_" + Destination.getName()), + STT_FUNC, 1, IS); + addSymbol("$t", STT_NOTYPE, 0, IS); } -bool ThumbV7ABSLongThunk::isCompatibleWith(RelType Type) const { - // ARM branch relocations can't use BLX - return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; -} - -void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { +void ARMV7PILongThunk::writeLong(uint8_t *Buf) { const uint8_t Data[] = { 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) + 8) 0x00, 0xc0, 0x40, 0xe3, // movt ip,:upper16:S - (P + (L1-P) + 8) @@ -258,7 +399,7 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { 0x1c, 0xff, 0x2f, 0xe1, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA(); + uint64_t P = getThunkTargetSym()->getVA(); uint64_t Offset = S - P - 16; memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_MOVW_PREL_NC, Offset); @@ -266,18 +407,12 @@ void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { } void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset, size(), IS); - addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, IS); + addSymbol(Saver.save("__ARMV7PILongThunk_" + Destination.getName()), STT_FUNC, + 0, IS); + addSymbol("$a", STT_NOTYPE, 0, IS); } -bool ARMV7PILongThunk::isCompatibleWith(RelType Type) const { - // Thumb branch relocations can't use BLX - return Type != R_ARM_THM_JUMP19 && Type != R_ARM_THM_JUMP24; -} - -void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { +void ThumbV7PILongThunk::writeLong(uint8_t *Buf) { const uint8_t Data[] = { 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) 0xc0, 0xf2, 0x00, 0x0c, // movt ip,:upper16:S - (P + (L1-P) + 4) @@ -285,7 +420,7 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { 0x60, 0x47, // bx r12 }; uint64_t S = getARMThunkDestVA(Destination); - uint64_t P = ThunkSym->getVA() & ~0x1; + uint64_t P = getThunkTargetSym()->getVA() & ~0x1; uint64_t Offset = S - P - 12; memcpy(Buf, Data, sizeof(Data)); Target->relocateOne(Buf, R_ARM_THM_MOVW_PREL_NC, Offset); @@ -293,32 +428,25 @@ void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { } void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { - ThunkSym = addSyntheticLocal( - Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), STT_FUNC, - Offset | 0x1, size(), IS); - addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, IS); -} - -bool ThumbV7PILongThunk::isCompatibleWith(RelType Type) const { - // ARM branch relocations can't use BLX - return Type != R_ARM_JUMP24 && Type != R_ARM_PC24 && Type != R_ARM_PLT32; + addSymbol(Saver.save("__ThumbV7PILongThunk_" + Destination.getName()), + STT_FUNC, 1, IS); + addSymbol("$t", STT_NOTYPE, 0, IS); } // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. -void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { +void MipsThunk::writeTo(uint8_t *Buf) { uint64_t S = Destination.getVA(); - write32(Buf, 0x3c190000, Config->Endianness); // lui $25, %hi(func) - write32(Buf + 4, 0x08000000 | (S >> 2), Config->Endianness); // j func - write32(Buf + 8, 0x27390000, Config->Endianness); // addiu $25, $25, %lo(func) - write32(Buf + 12, 0x00000000, Config->Endianness); // nop + write32(Buf, 0x3c190000); // lui $25, %hi(func) + write32(Buf + 4, 0x08000000 | (S >> 2)); // j func + write32(Buf + 8, 0x27390000); // addiu $25, $25, %lo(func) + write32(Buf + 12, 0x00000000); // nop Target->relocateOne(Buf, R_MIPS_HI16, S); Target->relocateOne(Buf + 8, R_MIPS_LO16, S); } void MipsThunk::addSymbols(ThunkSection &IS) { - ThunkSym = - addSyntheticLocal(Saver.save("__LA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), IS); + addSymbol(Saver.save("__LA25Thunk_" + Destination.getName()), STT_FUNC, 0, + IS); } InputSection *MipsThunk::getTargetInputSection() const { @@ -328,22 +456,21 @@ InputSection *MipsThunk::getTargetInputSection() const { // Write microMIPS R2-R5 LA25 thunk code // to call PIC function from the non-PIC one. -void MicroMipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { +void MicroMipsThunk::writeTo(uint8_t *Buf) { uint64_t S = Destination.getVA() | 1; - write16(Buf, 0x41b9, Config->Endianness); // lui $25, %hi(func) - write16(Buf + 4, 0xd400, Config->Endianness); // j func - write16(Buf + 8, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func) - write16(Buf + 12, 0x0c00, Config->Endianness); // nop + write16(Buf, 0x41b9); // lui $25, %hi(func) + write16(Buf + 4, 0xd400); // j func + write16(Buf + 8, 0x3339); // addiu $25, $25, %lo(func) + write16(Buf + 12, 0x0c00); // nop Target->relocateOne(Buf, R_MICROMIPS_HI16, S); Target->relocateOne(Buf + 4, R_MICROMIPS_26_S1, S); Target->relocateOne(Buf + 8, R_MICROMIPS_LO16, S); } void MicroMipsThunk::addSymbols(ThunkSection &IS) { - ThunkSym = - addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), IS); - ThunkSym->StOther |= STO_MIPS_MICROMIPS; + Defined *D = addSymbol( + Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); + D->StOther |= STO_MIPS_MICROMIPS; } InputSection *MicroMipsThunk::getTargetInputSection() const { @@ -353,22 +480,21 @@ InputSection *MicroMipsThunk::getTargetInputSection() const { // Write microMIPS R6 LA25 thunk code // to call PIC function from the non-PIC one. -void MicroMipsR6Thunk::writeTo(uint8_t *Buf, ThunkSection &) const { +void MicroMipsR6Thunk::writeTo(uint8_t *Buf) { uint64_t S = Destination.getVA() | 1; - uint64_t P = ThunkSym->getVA(); - write16(Buf, 0x1320, Config->Endianness); // lui $25, %hi(func) - write16(Buf + 4, 0x3339, Config->Endianness); // addiu $25, $25, %lo(func) - write16(Buf + 8, 0x9400, Config->Endianness); // bc func + uint64_t P = getThunkTargetSym()->getVA(); + write16(Buf, 0x1320); // lui $25, %hi(func) + write16(Buf + 4, 0x3339); // addiu $25, $25, %lo(func) + write16(Buf + 8, 0x9400); // bc func Target->relocateOne(Buf, R_MICROMIPS_HI16, S); Target->relocateOne(Buf + 4, R_MICROMIPS_LO16, S); Target->relocateOne(Buf + 8, R_MICROMIPS_PC26_S1, S - P - 12); } void MicroMipsR6Thunk::addSymbols(ThunkSection &IS) { - ThunkSym = - addSyntheticLocal(Saver.save("__microLA25Thunk_" + Destination.getName()), - STT_FUNC, Offset, size(), IS); - ThunkSym->StOther |= STO_MIPS_MICROMIPS; + Defined *D = addSymbol( + Saver.save("__microLA25Thunk_" + Destination.getName()), STT_FUNC, 0, IS); + D->StOther |= STO_MIPS_MICROMIPS; } InputSection *MicroMipsR6Thunk::getTargetInputSection() const { @@ -376,6 +502,25 @@ InputSection *MicroMipsR6Thunk::getTargetInputSection() const { return dyn_cast<InputSection>(DR.Section); } +void PPC64PltCallStub::writeTo(uint8_t *Buf) { + int64_t Off = Destination.getGotPltVA() - getPPC64TocBase(); + // Need to add 0x8000 to offset to account for the low bits being signed. + uint16_t OffHa = (Off + 0x8000) >> 16; + uint16_t OffLo = Off; + + write32(Buf + 0, 0xf8410018); // std r2,24(r1) + write32(Buf + 4, 0x3d820000 | OffHa); // addis r12,r2, X@plt@to@ha + write32(Buf + 8, 0xe98c0000 | OffLo); // ld r12,X@plt@toc@l(r12) + write32(Buf + 12, 0x7d8903a6); // mtctr r12 + write32(Buf + 16, 0x4e800420); // bctr +} + +void PPC64PltCallStub::addSymbols(ThunkSection &IS) { + Defined *S = addSymbol(Saver.save("__plt_" + Destination.getName()), STT_FUNC, + 0, IS); + S->NeedsTocRestore = true; +} + Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {} Thunk::~Thunk() = default; @@ -419,15 +564,26 @@ static Thunk *addThunkMips(RelType Type, Symbol &S) { return make<MipsThunk>(S); } +static Thunk *addThunkPPC64(RelType Type, Symbol &S) { + if (Type == R_PPC64_REL24) + return make<PPC64PltCallStub>(S); + fatal("unexpected relocation type"); +} + Thunk *addThunk(RelType Type, Symbol &S) { if (Config->EMachine == EM_AARCH64) return addThunkAArch64(Type, S); - else if (Config->EMachine == EM_ARM) + + if (Config->EMachine == EM_ARM) return addThunkArm(Type, S); - else if (Config->EMachine == EM_MIPS) + + if (Config->EMachine == EM_MIPS) return addThunkMips(Type, S); - llvm_unreachable("add Thunk only supported for ARM and Mips"); - return nullptr; + + if (Config->EMachine == EM_PPC64) + return addThunkPPC64(Type, S); + + llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC"); } } // end namespace elf diff --git a/ELF/Thunks.h b/ELF/Thunks.h index 828fac0bf53b..ed82b4d946ac 100644 --- a/ELF/Thunks.h +++ b/ELF/Thunks.h @@ -14,6 +14,7 @@ namespace lld { namespace elf { +class Defined; class Symbol; class ThunkSection; // Class to describe an instance of a Thunk. @@ -30,12 +31,17 @@ public: Thunk(Symbol &Destination); virtual ~Thunk(); - virtual uint32_t size() const { return 0; } - virtual void writeTo(uint8_t *Buf, ThunkSection &IS) const {} + virtual uint32_t size() = 0; + virtual void writeTo(uint8_t *Buf) = 0; - // All Thunks must define at least one symbol ThunkSym so that we can - // redirect relocations to it. - virtual void addSymbols(ThunkSection &IS) {} + // All Thunks must define at least one symbol, known as the thunk target + // symbol, so that we can redirect relocations to it. The thunk may define + // additional symbols, but these are never targets for relocations. + virtual void addSymbols(ThunkSection &IS) = 0; + + void setOffset(uint64_t Offset); + Defined *addSymbol(StringRef Name, uint8_t Type, uint64_t Value, + InputSectionBase &Section); // Some Thunks must be placed immediately before their Target as they elide // a branch and fall through to the first Symbol in the Target. @@ -45,10 +51,12 @@ public: // compatible with it. virtual bool isCompatibleWith(RelType Type) const { return true; } + Defined *getThunkTargetSym() const { return Syms[0]; } + // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. Symbol &Destination; - Symbol *ThunkSym; + llvm::SmallVector<Defined *, 3> Syms; uint64_t Offset = 0; uint32_t Alignment = 4; }; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 15f382104756..533ac47f937f 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -9,18 +9,19 @@ #include "Writer.h" #include "AArch64ErrataFix.h" +#include "CallGraphSort.h" #include "Config.h" #include "Filesystem.h" #include "LinkerScript.h" #include "MapFile.h" #include "OutputSections.h" #include "Relocations.h" -#include "Strings.h" #include "SymbolTable.h" #include "Symbols.h" #include "SyntheticSections.h" #include "Target.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSwitch.h" @@ -49,7 +50,7 @@ public: private: void copyLocalSymbols(); void addSectionSymbols(); - void forEachRelSec(std::function<void(InputSectionBase &)> Fn); + void forEachRelSec(llvm::function_ref<void(InputSectionBase &)> Fn); void sortSections(); void resolveShfLinkOrder(); void sortInputSections(); @@ -62,6 +63,7 @@ private: void assignFileOffsets(); void assignFileOffsetsBinary(); void setPhdrs(); + void checkSections(); void fixSectionAlignments(); void openFile(); void writeTrapInstr(); @@ -81,39 +83,48 @@ private: uint64_t FileSize; uint64_t SectionHeaderOff; - - bool HasGotBaseSym = false; }; } // anonymous namespace -StringRef elf::getOutputSectionName(InputSectionBase *S) { - // ".zdebug_" is a prefix for ZLIB-compressed sections. - // Because we decompressed input sections, we want to remove 'z'. - if (S->Name.startswith(".zdebug_")) - return Saver.save("." + S->Name.substr(2)); +static bool isSectionPrefix(StringRef Prefix, StringRef Name) { + return Name.startswith(Prefix) || Name == Prefix.drop_back(); +} +StringRef elf::getOutputSectionName(const InputSectionBase *S) { if (Config->Relocatable) return S->Name; // This is for --emit-relocs. If .text.foo is emitted as .text.bar, we want // to emit .rela.text.foo as .rela.text.bar for consistency (this is not // technically required, but not doing it is odd). This code guarantees that. - if ((S->Type == SHT_REL || S->Type == SHT_RELA) && - !isa<SyntheticSection>(S)) { - OutputSection *Out = - cast<InputSection>(S)->getRelocatedSection()->getOutputSection(); - if (S->Type == SHT_RELA) - return Saver.save(".rela" + Out->Name); - return Saver.save(".rel" + Out->Name); + if (auto *IS = dyn_cast<InputSection>(S)) { + if (InputSectionBase *Rel = IS->getRelocatedSection()) { + OutputSection *Out = Rel->getOutputSection(); + if (S->Type == SHT_RELA) + return Saver.save(".rela" + Out->Name); + return Saver.save(".rel" + Out->Name); + } } + // This check is for -z keep-text-section-prefix. This option separates text + // sections with prefix ".text.hot", ".text.unlikely", ".text.startup" or + // ".text.exit". + // When enabled, this allows identifying the hot code region (.text.hot) in + // the final binary which can be selectively mapped to huge pages or mlocked, + // for instance. + if (Config->ZKeepTextSectionPrefix) + for (StringRef V : + {".text.hot.", ".text.unlikely.", ".text.startup.", ".text.exit."}) { + if (isSectionPrefix(V, S->Name)) + return V.drop_back(); + } + for (StringRef V : {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) { - StringRef Prefix = V.drop_back(); - if (S->Name.startswith(V) || S->Name == Prefix) - return Prefix; + if (isSectionPrefix(V, S->Name)) + return V.drop_back(); } // CommonSection is identified as "COMMON" in linker scripts. @@ -194,21 +205,30 @@ void elf::addReservedSymbols() { Symtab->addAbsolute("__gnu_local_gp", STV_HIDDEN, STB_GLOBAL); } + // The Power Architecture 64-bit v2 ABI defines a TableOfContents (TOC) which + // combines the typical ELF GOT with the small data sections. It commonly + // includes .got .toc .sdata .sbss. The .TOC. symbol replaces both + // _GLOBAL_OFFSET_TABLE_ and _SDA_BASE_ from the 32-bit ABI. It is used to + // represent the TOC base which is offset by 0x8000 bytes from the start of + // the .got section. ElfSym::GlobalOffsetTable = addOptionalRegular( - "_GLOBAL_OFFSET_TABLE_", Out::ElfHeader, Target->GotBaseSymOff); + (Config->EMachine == EM_PPC64) ? ".TOC." : "_GLOBAL_OFFSET_TABLE_", + Out::ElfHeader, Target->GotBaseSymOff); // __ehdr_start is the location of ELF file headers. Note that we define // this symbol unconditionally even when using a linker script, which // differs from the behavior implemented by GNU linker which only define // this symbol if ELF headers are in the memory mapped segment. + addOptionalRegular("__ehdr_start", Out::ElfHeader, 0, STV_HIDDEN); + // __executable_start is not documented, but the expectation of at - // least the android libc is that it points to the elf header too. + // least the Android libc is that it points to the ELF header. + addOptionalRegular("__executable_start", Out::ElfHeader, 0, STV_HIDDEN); + // __dso_handle symbol is passed to cxa_finalize as a marker to identify // each DSO. The address of the symbol doesn't matter as long as they are // different in different DSOs, so we chose the start address of the DSO. - for (const char *Name : - {"__ehdr_start", "__executable_start", "__dso_handle"}) - addOptionalRegular(Name, Out::ElfHeader, 0, STV_HIDDEN); + addOptionalRegular("__dso_handle", Out::ElfHeader, 0, STV_HIDDEN); // If linker script do layout we do not need to create any standart symbols. if (Script->HasSectionsCommand) @@ -280,10 +300,9 @@ template <class ELFT> static void createSyntheticSections() { // If there is a SECTIONS command and a .data.rel.ro section name use name // .data.rel.ro.bss so that we match in the .data.rel.ro output section. // This makes sure our relro is contiguous. - bool HasDataRelRo = - Script->HasSectionsCommand && findSection(".data.rel.ro"); - InX::BssRelRo = make<BssSection>( - HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); + bool HasDataRelRo = Script->HasSectionsCommand && findSection(".data.rel.ro"); + InX::BssRelRo = + make<BssSection>(HasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1); Add(InX::BssRelRo); // Add MIPS-specific sections. @@ -330,6 +349,11 @@ template <class ELFT> static void createSyntheticSections() { Add(InX::RelaDyn); } + if (Config->RelrPackDynRelocs) { + InX::RelrDyn = make<RelrSection<ELFT>>(); + Add(InX::RelrDyn); + } + // Add .got. MIPS' .got is so different from the other archs, // it has its own class. if (Config->EMachine == EM_MIPS) { @@ -346,7 +370,7 @@ template <class ELFT> static void createSyntheticSections() { Add(InX::IgotPlt); if (Config->GdbIndex) { - InX::GdbIndex = createGdbIndex<ELFT>(); + InX::GdbIndex = GdbIndexSection::create<ELFT>(); Add(InX::GdbIndex); } @@ -369,9 +393,9 @@ template <class ELFT> static void createSyntheticSections() { false /*Sort*/); Add(InX::RelaIplt); - InX::Plt = make<PltSection>(Target->PltHeaderSize); + InX::Plt = make<PltSection>(false); Add(InX::Plt); - InX::Iplt = make<PltSection>(0); + InX::Iplt = make<PltSection>(true); Add(InX::Iplt); if (!Config->Relocatable) { @@ -427,13 +451,14 @@ template <class ELFT> void Writer<ELFT>::run() { if (errorCount()) return; + Script->assignAddresses(); + // If -compressed-debug-sections is specified, we need to compress // .debug_* sections. Do it right now because it changes the size of // output sections. - parallelForEach(OutputSections, - [](OutputSection *Sec) { Sec->maybeCompress<ELFT>(); }); + for (OutputSection *Sec : OutputSections) + Sec->maybeCompress<ELFT>(); - Script->assignAddresses(); Script->allocateHeaders(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a @@ -453,6 +478,9 @@ template <class ELFT> void Writer<ELFT>::run() { Sec->Addr = 0; } + if (Config->CheckSections) + checkSections(); + // It does not make sense try to open the file if we have error already. if (errorCount()) return; @@ -475,8 +503,9 @@ template <class ELFT> void Writer<ELFT>::run() { if (errorCount()) return; - // Handle -Map option. + // Handle -Map and -cref options. writeMapFile(); + writeCrossReferenceTable(); if (errorCount()) return; @@ -486,12 +515,9 @@ template <class ELFT> void Writer<ELFT>::run() { static bool shouldKeepInSymtab(SectionBase *Sec, StringRef SymName, const Symbol &B) { - if (B.isFile() || B.isSection()) + if (B.isSection()) return false; - // If sym references a section in a discarded group, don't keep it. - if (Sec == &InputSection::Discarded) - return false; if (Config->Discard == DiscardPolicy::None) return true; @@ -637,6 +663,9 @@ static bool isRelroSection(const OutputSection *Sec) { if (InX::Got && Sec == InX::Got->getParent()) return true; + if (Sec->Name.equals(".toc")) + return true; + // .got.plt contains pointers to external function symbols. They are // by default resolved lazily, so we usually cannot put it into RELRO. // However, if "-z now" is given, the lazy symbol resolution is @@ -668,20 +697,22 @@ static bool isRelroSection(const OutputSection *Sec) { // * It is easy to check if a give branch was taken. // * It is easy two see how similar two ranks are (see getRankProximity). enum RankFlags { - RF_NOT_ADDR_SET = 1 << 16, - RF_NOT_INTERP = 1 << 15, - RF_NOT_ALLOC = 1 << 14, - RF_WRITE = 1 << 13, - RF_EXEC_WRITE = 1 << 12, - RF_EXEC = 1 << 11, - RF_NON_TLS_BSS = 1 << 10, - RF_NON_TLS_BSS_RO = 1 << 9, - RF_NOT_TLS = 1 << 8, - RF_BSS = 1 << 7, + RF_NOT_ADDR_SET = 1 << 18, + RF_NOT_INTERP = 1 << 17, + RF_NOT_ALLOC = 1 << 16, + RF_WRITE = 1 << 15, + RF_EXEC_WRITE = 1 << 14, + RF_EXEC = 1 << 13, + RF_RODATA = 1 << 12, + RF_NON_TLS_BSS = 1 << 11, + RF_NON_TLS_BSS_RO = 1 << 10, + RF_NOT_TLS = 1 << 9, + RF_BSS = 1 << 8, + RF_NOTE = 1 << 7, RF_PPC_NOT_TOCBSS = 1 << 6, - RF_PPC_OPD = 1 << 5, - RF_PPC_TOCL = 1 << 4, - RF_PPC_TOC = 1 << 3, + RF_PPC_TOCL = 1 << 5, + RF_PPC_TOC = 1 << 4, + RF_PPC_GOT = 1 << 3, RF_PPC_BRANCH_LT = 1 << 2, RF_MIPS_GPREL = 1 << 1, RF_MIPS_NOT_GOT = 1 << 0 @@ -712,8 +743,7 @@ static unsigned getSectionRank(const OutputSection *Sec) { // considerations: // * Read-only sections come first such that they go in the // PT_LOAD covering the program headers at the start of the file. - // * Read-only, executable sections come next, unless the - // -no-rosegment option is used. + // * Read-only, executable sections come next. // * Writable, executable sections follow such that .plt on // architectures where it needs to be writable will be placed // between .text and .data. @@ -725,11 +755,16 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (IsExec) { if (IsWrite) Rank |= RF_EXEC_WRITE; - else if (!Config->SingleRoRx) + else Rank |= RF_EXEC; - } else { - if (IsWrite) - Rank |= RF_WRITE; + } else if (IsWrite) { + Rank |= RF_WRITE; + } else if (Sec->Type == SHT_PROGBITS) { + // Make non-executable and non-writable PROGBITS sections (e.g .rodata + // .eh_frame) closer to .text. They likely contain PC or GOT relative + // relocations and there could be relocation overflow if other huge sections + // (.dynstr .dynsym) were placed in between. + Rank |= RF_RODATA; } // If we got here we know that both A and B are in the same PT_LOAD. @@ -765,6 +800,12 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (IsNoBits) Rank |= RF_BSS; + // We create a NOTE segment for contiguous .note sections, so make + // them contigous if there are more than one .note section with the + // same attributes. + if (Sec->Type == SHT_NOTE) + Rank |= RF_NOTE; + // Some architectures have additional ordering restrictions for sections // within the same PT_LOAD. if (Config->EMachine == EM_PPC64) { @@ -778,18 +819,19 @@ static unsigned getSectionRank(const OutputSection *Sec) { if (Name != ".tocbss") Rank |= RF_PPC_NOT_TOCBSS; - if (Name == ".opd") - Rank |= RF_PPC_OPD; - if (Name == ".toc1") Rank |= RF_PPC_TOCL; if (Name == ".toc") Rank |= RF_PPC_TOC; + if (Name == ".got") + Rank |= RF_PPC_GOT; + if (Name == ".branch_lt") Rank |= RF_PPC_BRANCH_LT; } + if (Config->EMachine == EM_MIPS) { // All sections with SHF_MIPS_GPREL flag should be grouped together // because data in these sections is addressable with a gp relative address. @@ -830,17 +872,19 @@ void PhdrEntry::add(OutputSection *Sec) { // need these symbols, since IRELATIVE relocs are resolved through GOT // and PLT. For details, see http://www.airs.com/blog/archives/403. template <class ELFT> void Writer<ELFT>::addRelIpltSymbols() { - if (!Config->Static) + if (needsInterpSection()) return; StringRef S = Config->IsRela ? "__rela_iplt_start" : "__rel_iplt_start"; addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); S = Config->IsRela ? "__rela_iplt_end" : "__rel_iplt_end"; - addOptionalRegular(S, InX::RelaIplt, -1, STV_HIDDEN, STB_WEAK); + ElfSym::RelaIpltEnd = + addOptionalRegular(S, InX::RelaIplt, 0, STV_HIDDEN, STB_WEAK); } template <class ELFT> -void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) { +void Writer<ELFT>::forEachRelSec( + llvm::function_ref<void(InputSectionBase &)> Fn) { // Scan all relocations. Each relocation goes through a series // of tests to determine if it needs special treatment, such as // creating GOT, PLT, copy relocations, etc. @@ -860,14 +904,18 @@ void Writer<ELFT>::forEachRelSec(std::function<void(InputSectionBase &)> Fn) { // defining these symbols explicitly in the linker script. template <class ELFT> void Writer<ELFT>::setReservedSymbolSections() { if (ElfSym::GlobalOffsetTable) { - // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention to - // be at some offset from the base of the .got section, usually 0 or the end - // of the .got - InputSection *GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) - : cast<InputSection>(InX::Got); + // The _GLOBAL_OFFSET_TABLE_ symbol is defined by target convention usually + // to the start of the .got or .got.plt section. + InputSection *GotSection = InX::GotPlt; + if (!Target->GotBaseSymInGotPlt) + GotSection = InX::MipsGot ? cast<InputSection>(InX::MipsGot) + : cast<InputSection>(InX::Got); ElfSym::GlobalOffsetTable->Section = GotSection; } + if (ElfSym::RelaIpltEnd) + ElfSym::RelaIpltEnd->Value = InX::RelaIplt->getSize(); + PhdrEntry *Last = nullptr; PhdrEntry *LastRO = nullptr; @@ -937,8 +985,7 @@ static int getRankProximityAux(OutputSection *A, OutputSection *B) { static int getRankProximity(OutputSection *A, BaseCommand *B) { if (auto *Sec = dyn_cast<OutputSection>(B)) - if (Sec->Live) - return getRankProximityAux(A, Sec); + return getRankProximityAux(A, Sec); return -1; } @@ -957,11 +1004,9 @@ static int getRankProximity(OutputSection *A, BaseCommand *B) { // rw_sec : { *(rw_sec) } // would mean that the RW PT_LOAD would become unaligned. static bool shouldSkip(BaseCommand *Cmd) { - if (isa<OutputSection>(Cmd)) - return false; if (auto *Assign = dyn_cast<SymbolAssignment>(Cmd)) return Assign->Name != "."; - return true; + return false; } // We want to place orphan sections so that they share as much @@ -984,20 +1029,16 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, int Proximity = getRankProximity(Sec, *I); for (; I != E; ++I) { auto *CurSec = dyn_cast<OutputSection>(*I); - if (!CurSec || !CurSec->Live) + if (!CurSec) continue; if (getRankProximity(Sec, CurSec) != Proximity || Sec->SortRank < CurSec->SortRank) break; } - auto IsLiveSection = [](BaseCommand *Cmd) { - auto *OS = dyn_cast<OutputSection>(Cmd); - return OS && OS->Live; - }; - + auto IsOutputSec = [](BaseCommand *Cmd) { return isa<OutputSection>(Cmd); }; auto J = std::find_if(llvm::make_reverse_iterator(I), - llvm::make_reverse_iterator(B), IsLiveSection); + llvm::make_reverse_iterator(B), IsOutputSec); I = J.base(); // As a special case, if the orphan section is the last section, put @@ -1005,7 +1046,7 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, // This matches bfd's behavior and is convenient when the linker script fully // specifies the start of the file, but doesn't care about the end (the non // alloc sections for example). - auto NextSec = std::find_if(I, E, IsLiveSection); + auto NextSec = std::find_if(I, E, IsOutputSec); if (NextSec == E) return E; @@ -1014,32 +1055,172 @@ findOrphanPos(std::vector<BaseCommand *>::iterator B, return I; } -// If no layout was provided by linker script, we want to apply default -// sorting for special input sections and handle --symbol-ordering-file. -template <class ELFT> void Writer<ELFT>::sortInputSections() { - assert(!Script->HasSectionsCommand); +// Builds section order for handling --symbol-ordering-file. +static DenseMap<const InputSectionBase *, int> buildSectionOrder() { + DenseMap<const InputSectionBase *, int> SectionOrder; + // Use the rarely used option -call-graph-ordering-file to sort sections. + if (!Config->CallGraphProfile.empty()) + return computeCallGraphProfileOrder(); - // Sort input sections by priority using the list provided - // by --symbol-ordering-file. - DenseMap<SectionBase *, int> Order = buildSectionOrder(); - if (!Order.empty()) - for (BaseCommand *Base : Script->SectionCommands) - if (auto *Sec = dyn_cast<OutputSection>(Base)) - if (Sec->Live) - Sec->sort([&](InputSectionBase *S) { return Order.lookup(S); }); + if (Config->SymbolOrderingFile.empty()) + return SectionOrder; + + struct SymbolOrderEntry { + int Priority; + bool Present; + }; + + // Build a map from symbols to their priorities. Symbols that didn't + // appear in the symbol ordering file have the lowest priority 0. + // All explicitly mentioned symbols have negative (higher) priorities. + DenseMap<StringRef, SymbolOrderEntry> SymbolOrder; + int Priority = -Config->SymbolOrderingFile.size(); + for (StringRef S : Config->SymbolOrderingFile) + SymbolOrder.insert({S, {Priority++, false}}); + + // Build a map from sections to their priorities. + auto AddSym = [&](Symbol &Sym) { + auto It = SymbolOrder.find(Sym.getName()); + if (It == SymbolOrder.end()) + return; + SymbolOrderEntry &Ent = It->second; + Ent.Present = true; + + warnUnorderableSymbol(&Sym); + + if (auto *D = dyn_cast<Defined>(&Sym)) { + if (auto *Sec = dyn_cast_or_null<InputSectionBase>(D->Section)) { + int &Priority = SectionOrder[cast<InputSectionBase>(Sec->Repl)]; + Priority = std::min(Priority, Ent.Priority); + } + } + }; + // We want both global and local symbols. We get the global ones from the + // symbol table and iterate the object files for the local ones. + for (Symbol *Sym : Symtab->getSymbols()) + if (!Sym->isLazy()) + AddSym(*Sym); + for (InputFile *File : ObjectFiles) + for (Symbol *Sym : File->getSymbols()) + if (Sym->isLocal()) + AddSym(*Sym); + + if (Config->WarnSymbolOrdering) + for (auto OrderEntry : SymbolOrder) + if (!OrderEntry.second.Present) + warn("symbol ordering file: no such symbol: " + OrderEntry.first); + + return SectionOrder; +} + +// Sorts the sections in ISD according to the provided section order. +static void +sortISDBySectionOrder(InputSectionDescription *ISD, + const DenseMap<const InputSectionBase *, int> &Order) { + std::vector<InputSection *> UnorderedSections; + std::vector<std::pair<InputSection *, int>> OrderedSections; + uint64_t UnorderedSize = 0; + + for (InputSection *IS : ISD->Sections) { + auto I = Order.find(IS); + if (I == Order.end()) { + UnorderedSections.push_back(IS); + UnorderedSize += IS->getSize(); + continue; + } + OrderedSections.push_back({IS, I->second}); + } + llvm::sort( + OrderedSections.begin(), OrderedSections.end(), + [&](std::pair<InputSection *, int> A, std::pair<InputSection *, int> B) { + return A.second < B.second; + }); + + // Find an insertion point for the ordered section list in the unordered + // section list. On targets with limited-range branches, this is the mid-point + // of the unordered section list. This decreases the likelihood that a range + // extension thunk will be needed to enter or exit the ordered region. If the + // ordered section list is a list of hot functions, we can generally expect + // the ordered functions to be called more often than the unordered functions, + // making it more likely that any particular call will be within range, and + // therefore reducing the number of thunks required. + // + // For example, imagine that you have 8MB of hot code and 32MB of cold code. + // If the layout is: + // + // 8MB hot + // 32MB cold + // + // only the first 8-16MB of the cold code (depending on which hot function it + // is actually calling) can call the hot code without a range extension thunk. + // However, if we use this layout: + // + // 16MB cold + // 8MB hot + // 16MB cold + // + // both the last 8-16MB of the first block of cold code and the first 8-16MB + // of the second block of cold code can call the hot code without a thunk. So + // we effectively double the amount of code that could potentially call into + // the hot code without a thunk. + size_t InsPt = 0; + if (Target->ThunkSectionSpacing && !OrderedSections.empty()) { + uint64_t UnorderedPos = 0; + for (; InsPt != UnorderedSections.size(); ++InsPt) { + UnorderedPos += UnorderedSections[InsPt]->getSize(); + if (UnorderedPos > UnorderedSize / 2) + break; + } + } + + ISD->Sections.clear(); + for (InputSection *IS : makeArrayRef(UnorderedSections).slice(0, InsPt)) + ISD->Sections.push_back(IS); + for (std::pair<InputSection *, int> P : OrderedSections) + ISD->Sections.push_back(P.first); + for (InputSection *IS : makeArrayRef(UnorderedSections).slice(InsPt)) + ISD->Sections.push_back(IS); +} + +static void sortSection(OutputSection *Sec, + const DenseMap<const InputSectionBase *, int> &Order) { + StringRef Name = Sec->Name; // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). - if (OutputSection *Sec = findSection(".init_array")) - Sec->sortInitFini(); - if (OutputSection *Sec = findSection(".fini_array")) - Sec->sortInitFini(); + if (Name == ".init_array" || Name == ".fini_array") { + if (!Script->HasSectionsCommand) + Sec->sortInitFini(); + return; + } // Sort input sections by the special rule for .ctors and .dtors. - if (OutputSection *Sec = findSection(".ctors")) - Sec->sortCtorsDtors(); - if (OutputSection *Sec = findSection(".dtors")) - Sec->sortCtorsDtors(); + if (Name == ".ctors" || Name == ".dtors") { + if (!Script->HasSectionsCommand) + Sec->sortCtorsDtors(); + return; + } + + // Never sort these. + if (Name == ".init" || Name == ".fini") + return; + + // Sort input sections by priority using the list provided + // by --symbol-ordering-file. + if (!Order.empty()) + for (BaseCommand *B : Sec->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) + sortISDBySectionOrder(ISD, Order); +} + +// If no layout was provided by linker script, we want to apply default +// sorting for special input sections. This also handles --symbol-ordering-file. +template <class ELFT> void Writer<ELFT>::sortInputSections() { + // Build the order once since it is expensive. + DenseMap<const InputSectionBase *, int> Order = buildSectionOrder(); + for (BaseCommand *Base : Script->SectionCommands) + if (auto *Sec = dyn_cast<OutputSection>(Base)) + sortSection(Sec, Order); } template <class ELFT> void Writer<ELFT>::sortSections() { @@ -1050,22 +1231,29 @@ template <class ELFT> void Writer<ELFT>::sortSections() { if (Config->Relocatable) return; - for (BaseCommand *Base : Script->SectionCommands) - if (auto *Sec = dyn_cast<OutputSection>(Base)) - Sec->SortRank = getSectionRank(Sec); + sortInputSections(); - if (!Script->HasSectionsCommand) { - sortInputSections(); + for (BaseCommand *Base : Script->SectionCommands) { + auto *OS = dyn_cast<OutputSection>(Base); + if (!OS) + continue; + OS->SortRank = getSectionRank(OS); + + // We want to assign rude approximation values to OutSecOff fields + // to know the relative order of the input sections. We use it for + // sorting SHF_LINK_ORDER sections. See resolveShfLinkOrder(). + uint64_t I = 0; + for (InputSection *Sec : getInputSections(OS)) + Sec->OutSecOff = I++; + } + if (!Script->HasSectionsCommand) { // We know that all the OutputSections are contiguous in this case. - auto E = Script->SectionCommands.end(); - auto I = Script->SectionCommands.begin(); auto IsSection = [](BaseCommand *Base) { return isa<OutputSection>(Base); }; - I = std::find_if(I, E, IsSection); - E = std::find_if(llvm::make_reverse_iterator(E), - llvm::make_reverse_iterator(I), IsSection) - .base(); - std::stable_sort(I, E, compareSections); + std::stable_sort( + llvm::find_if(Script->SectionCommands, IsSection), + llvm::find_if(llvm::reverse(Script->SectionCommands), IsSection).base(), + compareSections); return; } @@ -1096,7 +1284,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() { // The way we define an order then is: // * Sort only the orphan sections. They are in the end right now. // * Move each orphan section to its preferred position. We try - // to put each section in the last position where it it can share + // to put each section in the last position where it can share // a PT_LOAD. // // There is some ambiguity as to where exactly a new entry should be @@ -1112,7 +1300,7 @@ template <class ELFT> void Writer<ELFT>::sortSections() { auto E = Script->SectionCommands.end(); auto NonScriptI = std::find_if(I, E, [](BaseCommand *Base) { if (auto *Sec = dyn_cast<OutputSection>(Base)) - return Sec->Live && Sec->SectionIndex == INT_MAX; + return Sec->SectionIndex == UINT32_MAX; return false; }); @@ -1187,8 +1375,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { }; // Get the last table Entry from the previous .ARM.exidx section. - const ExidxEntry &PrevEntry = *reinterpret_cast<const ExidxEntry *>( - Prev->Data.data() + Prev->getSize() - sizeof(ExidxEntry)); + const ExidxEntry &PrevEntry = Prev->getDataAs<ExidxEntry>().back(); if (IsExtabRef(PrevEntry.Unwind)) return false; @@ -1200,14 +1387,7 @@ static bool isDuplicateArmExidxSec(InputSection *Prev, InputSection *Cur) { // consecutive identical entries are rare and the effort to check that they // are identical is high. - if (isa<SyntheticSection>(Cur)) - // Exidx sentinel section has implicit EXIDX_CANTUNWIND; - return PrevEntry.Unwind == 0x1; - - ArrayRef<const ExidxEntry> Entries( - reinterpret_cast<const ExidxEntry *>(Cur->Data.data()), - Cur->getSize() / sizeof(ExidxEntry)); - for (const ExidxEntry &Entry : Entries) + for (const ExidxEntry Entry : Cur->getDataAs<ExidxEntry>()) if (IsExtabRef(Entry.Unwind) || Entry.Unwind != PrevEntry.Unwind) return false; // All table entries in this .ARM.exidx Section can be merged into the @@ -1237,13 +1417,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { if (!Config->Relocatable && Config->EMachine == EM_ARM && Sec->Type == SHT_ARM_EXIDX) { - if (!Sections.empty() && isa<ARMExidxSentinelSection>(Sections.back())) { + if (auto *Sentinel = dyn_cast<ARMExidxSentinelSection>(Sections.back())) { assert(Sections.size() >= 2 && "We should create a sentinel section only if there are " "alive regular exidx sections."); // The last executable section is required to fill the sentinel. // Remember it here so that we don't have to find it again. - auto *Sentinel = cast<ARMExidxSentinelSection>(Sections.back()); Sentinel->Highest = Sections[Sections.size() - 2]->getLinkOrderDep(); } @@ -1254,16 +1433,13 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { // previous one. This does not require any rewriting of InputSection // contents but misses opportunities for fine grained deduplication // where only a subset of the InputSection contents can be merged. - int Cur = 1; - int Prev = 0; + size_t Prev = 0; // The last one is a sentinel entry which should not be removed. - int N = Sections.size() - 1; - while (Cur < N) { - if (isDuplicateArmExidxSec(Sections[Prev], Sections[Cur])) - Sections[Cur] = nullptr; + for (size_t I = 1; I < Sections.size() - 1; ++I) { + if (isDuplicateArmExidxSec(Sections[Prev], Sections[I])) + Sections[I] = nullptr; else - Prev = Cur; - ++Cur; + Prev = I; } } } @@ -1274,14 +1450,12 @@ template <class ELFT> void Writer<ELFT>::resolveShfLinkOrder() { // Remove the Sections we marked as duplicate earlier. for (BaseCommand *Base : Sec->SectionCommands) if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) - ISD->Sections.erase( - std::remove(ISD->Sections.begin(), ISD->Sections.end(), nullptr), - ISD->Sections.end()); + llvm::erase_if(ISD->Sections, [](InputSection *IS) { return !IS; }); } } static void applySynthetic(const std::vector<SyntheticSection *> &Sections, - std::function<void(SyntheticSection *)> Fn) { + llvm::function_ref<void(SyntheticSection *)> Fn) { for (SyntheticSection *SS : Sections) if (SS && SS->getParent() && !SS->empty()) Fn(SS); @@ -1308,27 +1482,15 @@ static void removeUnusedSyntheticSections() { if (!SS) return; OutputSection *OS = SS->getParent(); - if (!SS->empty() || !OS) + if (!OS || !SS->empty()) continue; - std::vector<BaseCommand *>::iterator Empty = OS->SectionCommands.end(); - for (auto I = OS->SectionCommands.begin(), E = OS->SectionCommands.end(); - I != E; ++I) { - BaseCommand *B = *I; - if (auto *ISD = dyn_cast<InputSectionDescription>(B)) { + // If we reach here, then SS is an unused synthetic section and we want to + // remove it from corresponding input section description of output section. + for (BaseCommand *B : OS->SectionCommands) + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) llvm::erase_if(ISD->Sections, [=](InputSection *IS) { return IS == SS; }); - if (ISD->Sections.empty()) - Empty = I; - } - } - if (Empty != OS->SectionCommands.end()) - OS->SectionCommands.erase(Empty); - - // If there are no other sections in the output section, remove it from the - // output. - if (OS->SectionCommands.empty()) - OS->Live = false; } } @@ -1420,9 +1582,9 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (InX::DynSymTab && Sym->includeInDynsym()) { InX::DynSymTab->addSymbol(Sym); - if (auto *SS = dyn_cast<SharedSymbol>(Sym)) - if (cast<SharedFile<ELFT>>(Sym->File)->IsNeeded) - In<ELFT>::VerNeed->addSymbol(SS); + if (auto *File = dyn_cast_or_null<SharedFile<ELFT>>(Sym->File)) + if (File->IsNeeded && !Sym->isUndefined()) + In<ELFT>::VerNeed->addSymbol(Sym); } } @@ -1430,10 +1592,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (errorCount()) return; + if (InX::MipsGot) + InX::MipsGot->build<ELFT>(); + removeUnusedSyntheticSections(); sortSections(); - Script->removeEmptyCommands(); // Now that we have the final list, create a list of all the // OutputSections for convenience. @@ -1449,7 +1613,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { } // This is a bit of a hack. A value of 0 means undef, so we set it - // to 1 t make __ehdr_start defined. The section number is not + // to 1 to make __ehdr_start defined. The section number is not // particularly relevant. Out::ElfHeader->SectionIndex = 1; @@ -1475,12 +1639,12 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Dynamic section must be the last one in this list and dynamic // symbol table section (DynSymTab) must be the first one. applySynthetic( - {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, - InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, - In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot, - InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelaIplt, - InX::RelaPlt, InX::Plt, InX::Iplt, InX::EhFrameHdr, - In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic}, + {InX::DynSymTab, InX::Bss, InX::BssRelRo, InX::GnuHashTab, + InX::HashTab, InX::SymTab, InX::ShStrTab, InX::StrTab, + In<ELFT>::VerDef, InX::DynStrTab, InX::Got, InX::MipsGot, + InX::IgotPlt, InX::GotPlt, InX::RelaDyn, InX::RelrDyn, + InX::RelaIplt, InX::RelaPlt, InX::Plt, InX::Iplt, + InX::EhFrameHdr, In<ELFT>::VerSym, In<ELFT>::VerNeed, InX::Dynamic}, [](SyntheticSection *SS) { SS->finalizeContents(); }); if (!Script->HasSectionsCommand && !Config->Relocatable) @@ -1492,10 +1656,11 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // Some architectures need to generate content that depends on the address // of InputSections. For example some architectures use small displacements - // for jump instructions that is is the linker's responsibility for creating + // for jump instructions that is the linker's responsibility for creating // range extension thunks for. As the generation of the content may also // alter InputSection addresses we must converge to a fixed point. - if (Target->NeedsThunks || Config->AndroidPackDynRelocs) { + if (Target->NeedsThunks || Config->AndroidPackDynRelocs || + Config->RelrPackDynRelocs) { ThunkCreator TC; AArch64Err843419Patcher A64P; bool Changed; @@ -1512,34 +1677,48 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { if (InX::MipsGot) InX::MipsGot->updateAllocSize(); Changed |= InX::RelaDyn->updateAllocSize(); + if (InX::RelrDyn) + Changed |= InX::RelrDyn->updateAllocSize(); } while (Changed); } + // createThunks may have added local symbols to the static symbol table + applySynthetic({InX::SymTab}, + [](SyntheticSection *SS) { SS->postThunkContents(); }); + // Fill other section headers. The dynamic table is finalized // at the end because some tags like RELSZ depend on result // of finalizing other sections. for (OutputSection *Sec : OutputSections) Sec->finalize<ELFT>(); - - // createThunks may have added local symbols to the static symbol table - applySynthetic({InX::SymTab}, - [](SyntheticSection *SS) { SS->postThunkContents(); }); } // The linker is expected to define SECNAME_start and SECNAME_end // symbols for a few sections. This function defines them. template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { - auto Define = [&](StringRef Start, StringRef End, OutputSection *OS) { - // These symbols resolve to the image base if the section does not exist. - // A special value -1 indicates end of the section. + // If a section does not exist, there's ambiguity as to how we + // define _start and _end symbols for an init/fini section. Since + // the loader assume that the symbols are always defined, we need to + // always define them. But what value? The loader iterates over all + // pointers between _start and _end to run global ctors/dtors, so if + // the section is empty, their symbol values don't actually matter + // as long as _start and _end point to the same location. + // + // That said, we don't want to set the symbols to 0 (which is + // probably the simplest value) because that could cause some + // program to fail to link due to relocation overflow, if their + // program text is above 2 GiB. We use the address of the .text + // section instead to prevent that failure. + OutputSection *Default = findSection(".text"); + if (!Default) + Default = Out::ElfHeader; + auto Define = [=](StringRef Start, StringRef End, OutputSection *OS) { if (OS) { addOptionalRegular(Start, OS, 0); addOptionalRegular(End, OS, -1); } else { - if (Config->Pic) - OS = Out::ElfHeader; - addOptionalRegular(Start, OS, 0); - addOptionalRegular(End, OS, 0); + addOptionalRegular(Start, Default, 0); + addOptionalRegular(End, Default, 0); } }; @@ -1561,12 +1740,12 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { StringRef S = Sec->Name; if (!isValidCIdentifier(S)) return; - addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_DEFAULT); - addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_DEFAULT); + addOptionalRegular(Saver.save("__start_" + S), Sec, 0, STV_PROTECTED); + addOptionalRegular(Saver.save("__stop_" + S), Sec, -1, STV_PROTECTED); } static bool needsPtLoad(OutputSection *Sec) { - if (!(Sec->Flags & SHF_ALLOC)) + if (!(Sec->Flags & SHF_ALLOC) || Sec->Noload) return false; // Don't allocate VA space for TLS NOBITS sections. The PT_TLS PHDR is @@ -1623,9 +1802,13 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { // (e.g. executable or writable). There is one phdr for each segment. // Therefore, we need to create a new phdr when the next section has // different flags or is loaded at a discontiguous address using AT linker - // script command. + // script command. At the same time, we don't want to create a separate + // load segment for the headers, even if the first output section has + // an AT attribute. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (Sec->LMAExpr || Flags != NewFlags) { + if ((Sec->LMAExpr && Load->LastSec != Out::ProgramHeaders) || + Sec->MemRegion != Load->FirstSec->MemRegion || Flags != NewFlags) { + Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } @@ -1686,11 +1869,9 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { // pages for the stack non-executable. If you really want an executable // stack, you can pass -z execstack, but that's not recommended for // security reasons. - unsigned Perm; + unsigned Perm = PF_R | PF_W; if (Config->ZExecstack) - Perm = PF_R | PF_W | PF_X; - else - Perm = PF_R | PF_W; + Perm |= PF_X; AddHdr(PT_GNU_STACK, Perm)->p_memsz = Config->ZStackSize; // PT_OPENBSD_WXNEEDED is a OpenBSD-specific header to mark the executable @@ -1703,7 +1884,7 @@ template <class ELFT> std::vector<PhdrEntry *> Writer<ELFT>::createPhdrs() { // Create one PT_NOTE per a group of contiguous .note sections. PhdrEntry *Note = nullptr; for (OutputSection *Sec : OutputSections) { - if (Sec->Type == SHT_NOTE) { + if (Sec->Type == SHT_NOTE && (Sec->Flags & SHF_ALLOC)) { if (!Note || Sec->LMAExpr) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); @@ -1767,30 +1948,36 @@ template <class ELFT> void Writer<ELFT>::fixSectionAlignments() { // virtual address (modulo the page size) so that the loader can load // executables without any address adjustment. static uint64_t getFileAlignment(uint64_t Off, OutputSection *Cmd) { - // If the section is not in a PT_LOAD, we just have to align it. - if (!Cmd->PtLoad) - return alignTo(Off, Cmd->Alignment); - - OutputSection *First = Cmd->PtLoad->FirstSec; + OutputSection *First = Cmd->PtLoad ? Cmd->PtLoad->FirstSec : nullptr; // The first section in a PT_LOAD has to have congruent offset and address // module the page size. if (Cmd == First) return alignTo(Off, std::max<uint64_t>(Cmd->Alignment, Config->MaxPageSize), Cmd->Addr); + // For SHT_NOBITS we don't want the alignment of the section to impact the + // offset of the sections that follow. Since nothing seems to care about the + // sh_offset of the SHT_NOBITS section itself, just ignore it. + if (Cmd->Type == SHT_NOBITS) + return Off; + + // If the section is not in a PT_LOAD, we just have to align it. + if (!Cmd->PtLoad) + return alignTo(Off, Cmd->Alignment); + // If two sections share the same PT_LOAD the file offset is calculated // using this formula: Off2 = Off1 + (VA2 - VA1). return First->Offset + Cmd->Addr - First->Addr; } static uint64_t setOffset(OutputSection *Cmd, uint64_t Off) { - if (Cmd->Type == SHT_NOBITS) { - Cmd->Offset = Off; - return Off; - } - Off = getFileAlignment(Off, Cmd); Cmd->Offset = Off; + + // For SHT_NOBITS we should not count the size. + if (Cmd->Type == SHT_NOBITS) + return Off; + return Off + Cmd->Size; } @@ -1802,6 +1989,12 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsetsBinary() { FileSize = alignTo(Off, Config->Wordsize); } +static std::string rangeToString(uint64_t Addr, uint64_t Len) { + if (Len == 0) + return "<empty range at 0x" + utohexstr(Addr) + ">"; + return "[0x" + utohexstr(Addr) + ", 0x" + utohexstr(Addr + Len - 1) + "]"; +} + // Assign file offsets to output sections. template <class ELFT> void Writer<ELFT>::assignFileOffsets() { uint64_t Off = 0; @@ -1826,6 +2019,24 @@ template <class ELFT> void Writer<ELFT>::assignFileOffsets() { SectionHeaderOff = alignTo(Off, Config->Wordsize); FileSize = SectionHeaderOff + (OutputSections.size() + 1) * sizeof(Elf_Shdr); + + // Our logic assumes that sections have rising VA within the same segment. + // With use of linker scripts it is possible to violate this rule and get file + // offset overlaps or overflows. That should never happen with a valid script + // which does not move the location counter backwards and usually scripts do + // not do that. Unfortunately, there are apps in the wild, for example, Linux + // kernel, which control segment distribution explicitly and move the counter + // backwards, so we have to allow doing that to support linking them. We + // perform non-critical checks for overlaps in checkSectionOverlap(), but here + // we want to prevent file size overflows because it would crash the linker. + for (OutputSection *Sec : OutputSections) { + if (Sec->Type == SHT_NOBITS) + continue; + if ((Sec->Offset > FileSize) || (Sec->Offset + Sec->Size > FileSize)) + error("unable to place section " + Sec->Name + " at file offset " + + rangeToString(Sec->Offset, Sec->Offset + Sec->Size) + + "; check your linker script for overflows"); + } } // Finalize the program headers. We call this function after we assign @@ -1864,6 +2075,97 @@ template <class ELFT> void Writer<ELFT>::setPhdrs() { } } +// A helper struct for checkSectionOverlap. +namespace { +struct SectionOffset { + OutputSection *Sec; + uint64_t Offset; +}; +} // namespace + +// Check whether sections overlap for a specific address range (file offsets, +// load and virtual adresses). +static void checkOverlap(StringRef Name, std::vector<SectionOffset> &Sections, + bool IsVirtualAddr) { + llvm::sort(Sections.begin(), Sections.end(), + [=](const SectionOffset &A, const SectionOffset &B) { + return A.Offset < B.Offset; + }); + + // Finding overlap is easy given a vector is sorted by start position. + // If an element starts before the end of the previous element, they overlap. + for (size_t I = 1, End = Sections.size(); I < End; ++I) { + SectionOffset A = Sections[I - 1]; + SectionOffset B = Sections[I]; + if (B.Offset >= A.Offset + A.Sec->Size) + continue; + + // If both sections are in OVERLAY we allow the overlapping of virtual + // addresses, because it is what OVERLAY was designed for. + if (IsVirtualAddr && A.Sec->InOverlay && B.Sec->InOverlay) + continue; + + errorOrWarn("section " + A.Sec->Name + " " + Name + + " range overlaps with " + B.Sec->Name + "\n>>> " + A.Sec->Name + + " range is " + rangeToString(A.Offset, A.Sec->Size) + "\n>>> " + + B.Sec->Name + " range is " + + rangeToString(B.Offset, B.Sec->Size)); + } +} + +// Check for overlapping sections and address overflows. +// +// In this function we check that none of the output sections have overlapping +// file offsets. For SHF_ALLOC sections we also check that the load address +// ranges and the virtual address ranges don't overlap +template <class ELFT> void Writer<ELFT>::checkSections() { + // First, check that section's VAs fit in available address space for target. + for (OutputSection *OS : OutputSections) + if ((OS->Addr + OS->Size < OS->Addr) || + (!ELFT::Is64Bits && OS->Addr + OS->Size > UINT32_MAX)) + errorOrWarn("section " + OS->Name + " at 0x" + utohexstr(OS->Addr) + + " of size 0x" + utohexstr(OS->Size) + + " exceeds available address space"); + + // Check for overlapping file offsets. In this case we need to skip any + // section marked as SHT_NOBITS. These sections don't actually occupy space in + // the file so Sec->Offset + Sec->Size can overlap with others. If --oformat + // binary is specified only add SHF_ALLOC sections are added to the output + // file so we skip any non-allocated sections in that case. + std::vector<SectionOffset> FileOffs; + for (OutputSection *Sec : OutputSections) + if (0 < Sec->Size && Sec->Type != SHT_NOBITS && + (!Config->OFormatBinary || (Sec->Flags & SHF_ALLOC))) + FileOffs.push_back({Sec, Sec->Offset}); + checkOverlap("file", FileOffs, false); + + // When linking with -r there is no need to check for overlapping virtual/load + // addresses since those addresses will only be assigned when the final + // executable/shared object is created. + if (Config->Relocatable) + return; + + // Checking for overlapping virtual and load addresses only needs to take + // into account SHF_ALLOC sections since others will not be loaded. + // Furthermore, we also need to skip SHF_TLS sections since these will be + // mapped to other addresses at runtime and can therefore have overlapping + // ranges in the file. + std::vector<SectionOffset> VMAs; + for (OutputSection *Sec : OutputSections) + if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) + VMAs.push_back({Sec, Sec->Addr}); + checkOverlap("virtual address", VMAs, true); + + // Finally, check that the load addresses don't overlap. This will usually be + // the same as the virtual addresses but can be different when using a linker + // script with AT(). + std::vector<SectionOffset> LMAs; + for (OutputSection *Sec : OutputSections) + if (0 < Sec->Size && (Sec->Flags & SHF_ALLOC) && !(Sec->Flags & SHF_TLS)) + LMAs.push_back({Sec, Sec->getLMA()}); + checkOverlap("load address", LMAs, false); +} + // The entry point address is chosen in the following ways. // // 1. the '-e' entry command-line option; @@ -1905,8 +2207,20 @@ static uint16_t getELFType() { return ET_EXEC; } +static uint8_t getAbiVersion() { + // MIPS non-PIC executable gets ABI version 1. + if (Config->EMachine == EM_MIPS && getELFType() == ET_EXEC && + (Config->EFlags & (EF_MIPS_PIC | EF_MIPS_CPIC)) == EF_MIPS_CPIC) + return 1; + return 0; +} + template <class ELFT> void Writer<ELFT>::writeHeader() { uint8_t *Buf = Buffer->getBufferStart(); + // For executable segments, the trap instructions are written before writing + // the header. Setting Elf header bytes to zero ensures that any unused bytes + // in header are zero-cleared, instead of having trap instructions. + memset(Buf, 0, sizeof(Elf_Ehdr)); memcpy(Buf, "\177ELF", 4); // Write the ELF header. @@ -1915,6 +2229,7 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { EHdr->e_ident[EI_DATA] = Config->IsLE ? ELFDATA2LSB : ELFDATA2MSB; EHdr->e_ident[EI_VERSION] = EV_CURRENT; EHdr->e_ident[EI_OSABI] = Config->OSABI; + EHdr->e_ident[EI_ABIVERSION] = getAbiVersion(); EHdr->e_type = getELFType(); EHdr->e_machine = Config->EMachine; EHdr->e_version = EV_CURRENT; @@ -1924,8 +2239,6 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { EHdr->e_ehsize = sizeof(Elf_Ehdr); EHdr->e_phnum = Phdrs.size(); EHdr->e_shentsize = sizeof(Elf_Shdr); - EHdr->e_shnum = OutputSections.size() + 1; - EHdr->e_shstrndx = InX::ShStrTab->getParent()->SectionIndex; if (!Config->Relocatable) { EHdr->e_phoff = sizeof(Elf_Ehdr); @@ -1946,8 +2259,30 @@ template <class ELFT> void Writer<ELFT>::writeHeader() { ++HBuf; } - // Write the section header table. Note that the first table entry is null. + // Write the section header table. + // + // The ELF header can only store numbers up to SHN_LORESERVE in the e_shnum + // and e_shstrndx fields. When the value of one of these fields exceeds + // SHN_LORESERVE ELF requires us to put sentinel values in the ELF header and + // use fields in the section header at index 0 to store + // the value. The sentinel values and fields are: + // e_shnum = 0, SHdrs[0].sh_size = number of sections. + // e_shstrndx = SHN_XINDEX, SHdrs[0].sh_link = .shstrtab section index. auto *SHdrs = reinterpret_cast<Elf_Shdr *>(Buf + EHdr->e_shoff); + size_t Num = OutputSections.size() + 1; + if (Num >= SHN_LORESERVE) + SHdrs->sh_size = Num; + else + EHdr->e_shnum = Num; + + uint32_t StrTabIndex = InX::ShStrTab->getParent()->SectionIndex; + if (StrTabIndex >= SHN_LORESERVE) { + SHdrs->sh_link = StrTabIndex; + EHdr->e_shstrndx = SHN_XINDEX; + } else { + EHdr->e_shstrndx = StrTabIndex; + } + for (OutputSection *Sec : OutputSections) Sec->writeHeaderTo<ELFT>(++SHdrs); } @@ -2018,14 +2353,6 @@ template <class ELFT> void Writer<ELFT>::writeTrapInstr() { template <class ELFT> void Writer<ELFT>::writeSections() { uint8_t *Buf = Buffer->getBufferStart(); - // PPC64 needs to process relocations in the .opd section - // before processing relocations in code-containing sections. - if (auto *OpdCmd = findSection(".opd")) { - Out::Opd = OpdCmd; - Out::OpdBuf = Buf + Out::Opd->Offset; - OpdCmd->template writeTo<ELFT>(Buf + Out::Opd->Offset); - } - OutputSection *EhFrameHdr = nullptr; if (InX::EhFrameHdr && !InX::EhFrameHdr->empty()) EhFrameHdr = InX::EhFrameHdr->getParent(); @@ -2038,8 +2365,7 @@ template <class ELFT> void Writer<ELFT>::writeSections() { Sec->writeTo<ELFT>(Buf + Sec->Offset); for (OutputSection *Sec : OutputSections) - if (Sec != Out::Opd && Sec != EhFrameHdr && Sec->Type != SHT_REL && - Sec->Type != SHT_RELA) + if (Sec != EhFrameHdr && Sec->Type != SHT_REL && Sec->Type != SHT_RELA) Sec->writeTo<ELFT>(Buf + Sec->Offset); // The .eh_frame_hdr depends on .eh_frame section contents, therefore diff --git a/ELF/Writer.h b/ELF/Writer.h index d247068bab23..7806f824c58f 100644 --- a/ELF/Writer.h +++ b/ELF/Writer.h @@ -23,7 +23,6 @@ class InputSectionBase; template <class ELFT> class ObjFile; class SymbolTable; template <class ELFT> void writeResult(); -template <class ELFT> void markLive(); // This describes a program header entry. // Each contains type, access flags and range of output sections that will be @@ -44,10 +43,12 @@ struct PhdrEntry { OutputSection *FirstSec = nullptr; OutputSection *LastSec = nullptr; bool HasLMA = false; + + uint64_t LMAOffset = 0; }; void addReservedSymbols(); -llvm::StringRef getOutputSectionName(InputSectionBase *S); +llvm::StringRef getOutputSectionName(const InputSectionBase *S); template <class ELFT> uint32_t calcMipsEFlags(); diff --git a/LICENSE.TXT b/LICENSE.TXT index ec97986c86ba..e05e1845766e 100644 --- a/LICENSE.TXT +++ b/LICENSE.TXT @@ -4,7 +4,7 @@ lld License University of Illinois/NCSA Open Source License -Copyright (c) 2011-2016 by the contributors listed in CREDITS.TXT +Copyright (c) 2011-2018 by the contributors listed in CREDITS.TXT All rights reserved. Developed by: diff --git a/MinGW/Driver.cpp b/MinGW/Driver.cpp index 6d3bea5d9040..27a5550ec9c7 100644 --- a/MinGW/Driver.cpp +++ b/MinGW/Driver.cpp @@ -136,6 +136,8 @@ bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) { Add("-output-def:" + StringRef(A->getValue())); if (auto *A = Args.getLastArg(OPT_image_base)) Add("-base:" + StringRef(A->getValue())); + if (auto *A = Args.getLastArg(OPT_map)) + Add("-lldmap:" + StringRef(A->getValue())); if (auto *A = Args.getLastArg(OPT_o)) Add("-out:" + StringRef(A->getValue())); @@ -144,16 +146,25 @@ bool mingw::link(ArrayRef<const char *> ArgsArr, raw_ostream &Diag) { else Add("-out:a.exe"); + if (auto *A = Args.getLastArg(OPT_pdb)) { + Add("-debug"); + Add("-pdb:" + StringRef(A->getValue())); + } else if (Args.hasArg(OPT_strip_debug)) { + Add("-debug:symtab"); + } else if (!Args.hasArg(OPT_strip_all)) { + Add("-debug:dwarf"); + } + if (Args.hasArg(OPT_shared)) Add("-dll"); if (Args.hasArg(OPT_verbose)) Add("-verbose"); if (Args.hasArg(OPT_export_all_symbols)) Add("-export-all-symbols"); - if (!Args.hasArg(OPT_strip_all)) - Add("-debug:dwarf"); if (Args.hasArg(OPT_large_address_aware)) Add("-largeaddressaware"); + if (Args.hasArg(OPT_kill_at)) + Add("-kill-at"); if (Args.getLastArgValue(OPT_m) != "thumb2pe" && Args.getLastArgValue(OPT_m) != "arm64pe" && !Args.hasArg(OPT_dynamicbase)) diff --git a/MinGW/Options.td b/MinGW/Options.td index f3bf25a2258b..ad699f71134a 100644 --- a/MinGW/Options.td +++ b/MinGW/Options.td @@ -14,9 +14,12 @@ def export_all_symbols: F<"export-all-symbols">, def gc_sections: F<"gc-sections">, HelpText<"Remove unused sections">; def icf: J<"icf=">, HelpText<"Identical code folding">; def image_base: S<"image-base">, HelpText<"Base address of the program">; +def kill_at: F<"kill-at">, HelpText<"Remove @n from exported symbols">; def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">, HelpText<"Root name of library to use">; def m: JoinedOrSeparate<["-"], "m">, HelpText<"Set target emulation">; +def map: S<"Map">, HelpText<"Output a linker map">; +def map_eq: J<"Map=">, Alias<map>; def no_whole_archive: F<"no-whole-archive">, HelpText<"No longer include all object files for following archives">; def large_address_aware: Flag<["--"], "large-address-aware">, @@ -32,6 +35,8 @@ def subs: S<"subsystem">, HelpText<"Specify subsystem">; def stack: S<"stack">; def strip_all: F<"strip-all">, HelpText<"Omit all symbol information from the output binary">; +def strip_debug: F<"strip-debug">, + HelpText<"Omit all debug information, but keep symbol information">; def whole_archive: F<"whole-archive">, HelpText<"Include all object files for following archives">; def verbose: F<"verbose">, HelpText<"Verbose mode">; @@ -40,6 +45,7 @@ def verbose: F<"verbose">, HelpText<"Verbose mode">; def _HASH_HASH_HASH : Flag<["-"], "###">, HelpText<"Print (but do not run) the commands to run for this compilation">; def mllvm: S<"mllvm">; +def pdb: S<"pdb">, HelpText<"Specify output PDB debug information file">; def Xlink : J<"Xlink=">, MetaVarName<"<arg>">, HelpText<"Pass <arg> to the COFF linker">; @@ -51,6 +57,7 @@ def build_id: F<"build-id">; def disable_auto_image_base: F<"disable-auto-image-base">; def enable_auto_image_base: F<"enable-auto-image-base">; def enable_auto_import: F<"enable-auto-import">; +def end_group: F<"end-group">; def full_shutdown: Flag<["--"], "full-shutdown">; def high_entropy_va: F<"high-entropy-va">, HelpText<"Enable 64-bit ASLR">; def major_image_version: S<"major-image-version">; @@ -59,6 +66,7 @@ def no_seh: F<"no-seh">; def nxcompat: F<"nxcompat">, HelpText<"Enable data execution prevention">; def pic_executable: F<"pic-executable">; def sysroot: J<"sysroot">, HelpText<"Sysroot">; +def start_group: F<"start-group">; def tsaware: F<"tsaware">, HelpText<"Create Terminal Server aware executable">; def v: Flag<["-"], "v">, HelpText<"Display the version number">; def version: F<"version">, HelpText<"Display the version number and exit">; @@ -66,3 +74,4 @@ def version: F<"version">, HelpText<"Display the version number and exit">; // Alias def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; def alias_strip_s: Flag<["-"], "s">, Alias<strip_all>; +def alias_strip_S: Flag<["-"], "S">, Alias<strip_debug>; diff --git a/cmake/modules/AddLLD.cmake b/cmake/modules/AddLLD.cmake index 0d951799cdfe..fa48b428d26b 100644 --- a/cmake/modules/AddLLD.cmake +++ b/cmake/modules/AddLLD.cmake @@ -10,7 +10,7 @@ macro(add_lld_library name) llvm_add_library(${name} ${ARG_ENABLE_SHARED} ${ARG_UNPARSED_ARGUMENTS}) set_target_properties(${name} PROPERTIES FOLDER "lld libraries") - if (LLD_BUILD_TOOLS) + if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR NOT LLVM_DISTRIBUTION_COMPONENTS) set(export_to_lldtargets EXPORT lldTargets) diff --git a/docs/ReleaseNotes.rst b/docs/ReleaseNotes.rst index dcd6ac0602d3..7ac1f9ce565b 100644 --- a/docs/ReleaseNotes.rst +++ b/docs/ReleaseNotes.rst @@ -1,21 +1,21 @@ ======================= -LLD 6.0.0 Release Notes +LLD 7.0.0 Release Notes ======================= .. contents:: :local: .. warning:: - These are in-progress notes for the upcoming LLVM 6.0.0 release. + These are in-progress notes for the upcoming LLVM 7.0.0 release. Release notes for previous releases can be found on `the Download Page <http://releases.llvm.org/download.html>`_. Introduction ============ -This document contains the release notes for the LLD linker, release 6.0.0. -Here we describe the status of LLD, including major improvements -from the previous release. All LLD releases may be downloaded +This document contains the release notes for the lld linker, release 7.0.0. +Here we describe the status of lld, including major improvements +from the previous release. All lld releases may be downloaded from the `LLVM releases web site <http://llvm.org/releases/>`_. Non-comprehensive list of changes in this release diff --git a/docs/WebAssembly.rst b/docs/WebAssembly.rst index 1df8fa3a82b0..264d221970b1 100644 --- a/docs/WebAssembly.rst +++ b/docs/WebAssembly.rst @@ -18,7 +18,7 @@ the WebAssembly tool conventions https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md. This is object format that the llvm will produce when run with the -``wasm32-unknown-unknown-wasm`` target. To build llvm with WebAssembly support +``wasm32-unknown-unknown`` target. To build llvm with WebAssembly support currently requires enabling the experimental backed using ``-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly``. diff --git a/docs/conf.py b/docs/conf.py index 28e16f5b8856..3598fbf50f0d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -48,9 +48,9 @@ copyright = u'2011-%d, LLVM Project' % date.today().year # built documents. # # The short version. -version = '6' +version = '7' # The full version, including alpha/beta/rc tags. -release = '6' +release = '7' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/ld.lld.1 b/docs/ld.lld.1 new file mode 100644 index 000000000000..c9662856b891 --- /dev/null +++ b/docs/ld.lld.1 @@ -0,0 +1,547 @@ +.\" This file is distributed under the University of Illinois Open Source +.\" License. See LICENSE.TXT for details. +.\" +.\" This man page documents only lld's ELF linking support, obtained originally +.\" from FreeBSD. +.Dd April 28, 2018 +.Dt LD.LLD 1 +.Os +.Sh NAME +.Nm ld.lld +.Nd ELF linker from the LLVM project +.Sh SYNOPSIS +.Nm ld.lld +.Op Ar options +.Ar objfile ... +.Sh DESCRIPTION +A linker takes one or more object, archive, and library files, and combines +them into an output file (an executable, a shared library, or another object +file). +It relocates code and data from the input files and resolves symbol +references between them. +.Pp +.Nm +is a drop-in replacement for the GNU BFD and gold linkers. +It accepts most of the same command line arguments and linker scripts +as GNU linkers. +.Pp +These options are available: +.Bl -tag -width indent +.It Fl -allow-multiple-definition +Do not error if a symbol is defined multiple times. +The first definition will be used. +.It Fl -as-needed +Only set +.Dv DT_NEEDED +for shared libraries if used. +.It Fl -auxiliary Ns = Ns Ar value +Set the +.Dv DT_AUXILIARY +field to the specified name. +.It Fl -Bdynamic +Link against shared libraries. +.It Fl -Bstatic +Do not link against shared libraries. +.It Fl -Bsymbolic-functions +Bind defined function symbols locally. +.It Fl -Bsymbolic +Bind defined symbols locally. +.It Fl -build-id Ns = Ns Ar value +Generate a build ID note. +.Ar value +may be one of +.Cm fast , +.Cm md5 , +.Cm sha1 , +.Cm tree , +.Cm uuid , +.Cm 0x Ns Ar hex-string , +and +.Cm none . +.Cm tree +is an alias for +.Cm sha1 . +Build-IDs of type +.Cm fast , +.Cm md5 , +.Cm sha1 , +and +.Cm tree +are calculated from the object contents. +.Cm fast +is not intended to be cryptographically secure. +.It Fl -build-id +Synonym for +.Fl -build-id Ns = Ns Cm fast . +.It Fl -color-diagnostics Ns = Ns Ar value +Use colors in diagnostics. +.Ar value +may be one of +.Cm always , +.Cm auto , +and +.Cm never . +.Cm auto +enables color if and only if output is to a terminal. +.It Fl -color-diagnostics +Alias for +.Fl -color-diagnostics Ns = Ns Cm auto . +.It Fl -compress-debug-sections Ns = Ns Ar value +Compress DWARF debug sections. +.Ar value +may be +.Cm none +or +.Cm zlib . +.It Fl -define-common +Assign space to common symbols. +.It Fl -defsym Ns = Ns Ar symbol Ns = Ns Ar expression +Define a symbol alias. +.Ar expression +may be another symbol or a linker script expression. +For example, +.Ql --defsym=foo=bar +or +.Ql --defsym=foo=bar+0x100 . +.It Fl -demangle +Demangle symbol names. +.It Fl -disable-new-dtags +Disable new dynamic tags. +.It Fl -discard-all +Delete all local symbols. +.It Fl -discard-locals +Delete temporary local symbols. +.It Fl -discard-none +Keep all symbols in the symbol table. +.It Fl -dynamic-linker Ns = Ns Ar value +Specify the dynamic linker to be used for a dynamically linked executable. +This is recorded in an ELF segment of type +.Dv PT_INTERP . +.It Fl -dynamic-list Ns = Ns Ar file +Read a list of dynamic symbols from +.Ar file . +.It Fl -eh-frame-hdr +Request creation of +.Li .eh_frame_hdr +section and +.Dv PT_GNU_EH_FRAME +segment header. +.It Fl -emit-relocs +Generate relocations in the output. +.It Fl -enable-new-dtags +Enable new dynamic tags. +.It Fl -end-lib +End a grouping of objects that should be treated as if they were together +in an archive. +.It Fl -entry Ns = Ns Ar entry +Name of entry point symbol. +.It Fl -error-limit Ns = Ns Ar value +Maximum number of errors to emit before stopping. +A value of zero indicates that there is no limit. +.It Fl -error-unresolved-symbols +Report unresolved symbols as errors. +.It Fl -exclude-libs Ns = Ns Ar value +Exclude static libraries from automatic export. +.It Fl -export-dynamic-symbol Ns = Ns Ar symbol +Include +.Ar symbol +in the dynamic symbol table. +.It Fl -export-dynamic +Put symbols in the dynamic symbol table. +.It Fl -fatal-warnings +Treat warnings as errors. +.It Fl -filter Ns = Ns Ar value +Set the +.Dv DT_FILTER +field to the specified value. +.It Fl -fini Ns = Ns Ar symbol +Specify a finalizer function. +.It Fl -format Ns = Ns Ar input-format +Specify the format of the inputs following this option. +.Ar input-format +may be one of +.Cm binary , +.Cm elf , +and +.Cm default . +.Cm default +is a synonym for +.Cm elf . +.It Fl -gc-sections +Enable garbage collection of unused sections. +.It Fl -gdb-index +Generate +.Li .gdb_index +section. +.It Fl -hash-style Ns = Ns Ar value +Specify hash style. +.Ar value +may be +.Cm sysv , +.Cm gnu , +or +.Cm both . +.Cm both +is the default. +.It Fl -help +Print a help message. +.It Fl -icf Ns = Ns Cm all +Enable identical code folding. +.It Fl -icf Ns = Ns Cm safe +Enable safe identical code folding. +.It Fl -icf Ns = Ns Cm none +Disable identical code folding. +.It Fl -image-base Ns = Ns Ar value +Set the base address to +.Ar value . +.It Fl -init Ns = Ns Ar symbol +Specify an initializer function. +.It Fl -lto-aa-pipeline Ns = Ns Ar value +AA pipeline to run during LTO. +Used in conjunction with +.Fl -lto-newpm-passes . +.It Fl -lto-newpm-passes Ns = Ns Ar value +Passes to run during LTO. +.It Fl -lto-O Ns Ar opt-level +Optimization level for LTO. +.It Fl -lto-partitions Ns = Ns Ar value +Number of LTO codegen partitions. +.It Fl L Ar dir +Add a directory to the library search path. +.It Fl l Ar libName +Root name of library to use. +.It Fl -Map Ns = Ns Ar file +Print a link map to +.Ar file . +.It Fl m Ar value +Set target emulation. +.It Fl -no-as-needed +Always set +.Dv DT_NEEDED +for shared libraries. +.It Fl -no-color-diagnostics +Do not use colors in diagnostics. +.It Fl -no-define-common +Do not assign space to common symbols. +.It Fl -no-demangle +Do not demangle symbol names. +.It Fl -no-dynamic-linker +Inhibit output of an +.Li .interp +section. +.It Fl -no-gc-sections +Disable garbage collection of unused sections. +.It Fl -no-gnu-unique +Disable STB_GNU_UNIQUE symbol binding. +.It Fl -no-rosegment +Do not put read-only non-executable sections in their own segment. +.It Fl -no-threads +Do not run the linker multi-threaded. +.It Fl -no-undefined-version +Report version scripts that refer undefined symbols. +.It Fl -no-undefined +Report unresolved symbols even if the linker is creating a shared library. +.It Fl -no-whole-archive +Restores the default behavior of loading archive members. +.It Fl -noinhibit-exec +Retain the executable output file whenever it is still usable. +.It Fl -no-pie +Do not create a position independent executable. +.It Fl -nostdlib +Only search directories specified on the command line. +.It Fl -oformat Ns = Ns Ar format +Specify the format for the output object file. +The only supported +.Ar format +is +.Cm binary , +which produces output with no ELF header. +.It Fl -omagic +Set the text and data sections to be readable and writable. +.It Fl -opt-remarks-filename Ar file +Write optimization remarks in YAML format to +.Ar file . +.It Fl -opt-remarks-with-hotness +Include hotness information in the optimization remarks file. +.It Fl O Ns Ar value +Optimize output file size. +.Ar value +may be: +.Pp +.Bl -tag -width 2n -compact +.It Cm 0 +Disable string merging. +.It Cm 1 +Enable string merging. +.It Cm 2 +Enable string tail merging. +.El +.Pp +.Fl O Ns Cm 1 +is the default. +.It Fl o Ar path +Write the output executable, library, or object to +.Ar path . +If not specified, +.Dv a.out +is used as a default. +.It Fl -pie +Create a position independent executable. +.It Fl -print-gc-sections +List removed unused sections. +.It Fl -print-map +Print a link map to the standard output. +.It Fl -push-state +Save the current state of +.Fl -as-needed , +.Fl -static , +and +.Fl -while-archive. +.It Fl -pop-state +Undo the effect of +.Fl -push-state. +.It Fl -relocatable +Create relocatable object file. +.It Fl -reproduce Ns = Ns Ar value +Dump linker invocation and input files for debugging. +.It Fl -retain-symbols-file Ns = Ns Ar file +Retain only the symbols listed in the file. +.It Fl -rpath Ns = Ns Ar value +Add a +.Dv DT_RUNPATH +to the output. +.It Fl -rsp-quoting Ns = Ns Ar value +Quoting style for response files. +The supported values are +.Cm windows +and +.Cm posix . +.It Fl -script Ns = Ns Ar file +Read linker script from +.Ar file . +.It Fl -section-start Ns = Ar section Ns = Ns Ar address +Set address of section. +.It Fl -shared +Build a shared object. +.It Fl -soname Ns = Ns Ar value +Set +.Dv DT_SONAME +to +.Ar value . +.It Fl -sort-section Ns = Ns Ar value +Specifies sections sorting rule when linkerscript is used. +.It Fl -start-lib +Start a grouping of objects that should be treated as if they were together +in an archive. +.It Fl -strip-all +Strip all symbols. +.It Fl -strip-debug +Strip debugging information. +.It Fl -symbol-ordering-file Ns = Ns Ar file +Lay out sections in the order specified by +.Ar file . +.It Fl -sysroot Ns = Ns Ar value +Set the system root. +.It Fl -target1-abs +Interpret +.Dv R_ARM_TARGET1 +as +.Dv R_ARM_ABS32 . +.It Fl -target1-rel +Interpret +.Dv R_ARM_TARGET1 +as +.Dv R_ARM_REL32 . +.It Fl -target2 Ns = Ns Ar type +Interpret +.Dv R_ARM_TARGET2 +as +.Ar type , +where +.Ar type +is one of +.Cm rel , +.Cm abs , +or +.Cm got-rel . +.It Fl -Tbss Ns = Ns Ar value +Same as +.Fl -section-start +with +.Li .bss +as the sectionname. +.It Fl -Tdata Ns = Ns Ar value +Same as +.Fl -section-start +with +.Li .data +as the sectionname. +.It Fl -thinlto-cache-dir Ns = Ns Ar value +Path to ThinLTO cached object file directory. +.It Fl -thinlto-cache-policy Ns = Ns Ar value +Pruning policy for the ThinLTO cache. +.It Fl -thinlto-jobs Ns = Ns Ar value +Number of ThinLTO jobs. +.It Fl -threads +Run the linker multi-threaded. +This option is enabled by default. +.It Fl -trace-symbol Ns = Ns Ar symbol +Trace references to +.Ar symbol . +.It Fl -trace +Print the names of the input files. +.It Fl -Ttext Ns = Ns Ar value +Same as +.Fl -section-start +with +.Li .text +as the sectionname. +.It Fl -undefined Ns = Ns Ar symbol +Force +.Ar symbol +to be an undefined symbol during linking. +.It Fl -unresolved-symbols Ns = Ns Ar value +Determine how to handle unresolved symbols. +.It Fl -verbose +Verbose mode. +.It Fl -version-script Ns = Ns Ar file +Read version script from +.Ar file . +.It Fl V , Fl -version +Display the version number and exit. +.It Fl v +Display the version number and proceed with linking if object files are +specified. +.It Fl -warn-backrefs +Warn about reverse or cyclic dependencies to or between static archives. +This can be used to ensure linker invocation remains compatible with +traditional Unix-like linkers. +.It Fl -warn-common +Warn about duplicate common symbols. +.It Fl -warn-unresolved-symbols +Report unresolved symbols as warnings. +.It Fl -whole-archive +Force load of all members in a static library. +.It Fl -wrap Ns = Ns Ar symbol +Use wrapper functions for symbol. +.It Fl z Ar option +Linker option extensions. +.Bl -tag -width indent +.It Cm execstack +Make the main stack executable. +Stack permissions are recorded in the +.Dv PT_GNU_STACK +segment. +.It Cm muldefs +Do not error if a symbol is defined multiple times. +The first definition will be used. +This is a synonym for +.Fl -allow-multiple-definition. +.It Cm nocombreloc +Disable combining and sorting multiple relocation sections. +.It Cm nocopyreloc +Disable the creation of copy relocations. +.It Cm nodelete +Set the +.Dv DF_1_NODELETE +flag to indicate that the object cannot be unloaded from a process. +.It Cm nodlopen +Set the +.Dv DF_1_NOOPEN +flag to indcate that the object may not be opened by +.Xr dlopen 3 . +.It Cm norelro +Do not indicate that portions of the object shold be mapped read-only +after initial relocation processing. +The object will omit the +.Dv PT_GNU_RELRO +segment. +.It Cm notext +Allow relocations against read-only segments. +Sets the +.Dv DT_TEXTREL flag in the +.Dv DYNAMIC +section. +.It Cm now +Set the +.Dv DF_BIND_NOW +flag to indicate that the run-time loader should perform all relocation +processing as part of object initialization. +By default relocations may be performed on demand. +.It Cm origin +Set the +.Dv DF_ORIGIN +flag to indicate that the object requires +$ORIGIN +processing. +.It Cm retpolineplt +Emit retpoline format PLT entries as a mitigation for CVE-2017-5715. +.It Cm rodynamic +Make the +.Li .dynamic +section read-only. +The +.Dv DT_DEBUG +tag will not be emitted. +.It Cm stack-size Ns = Ns Ar size +Set the main thread's stack size to +.Ar size . +The stack size is recorded as the size of the +.Ar size . +.Dv PT_GNU_STACK +program segment. +.It Cm text +Do not allow relocations against read-only segments. +This is the default. +.It Cm wxneeded +Create a +.Dv PT_OPENBSD_WXNEEDED +segment. +.El +.El +.Sh IMPLEMENTATION NOTES +.Nm Ap s +handing of archive files (those with a +.Pa .a +file extension) is different from traditional linkers used on Unix-like +systems. +.Pp +Traditional linkers maintain a set of undefined symbols during linking. +The linker processes each file in the order in which it appears on the +command line, until the set of undefined symbols becomes empty. +An object file is linked into the output object when it is encountered, +with its undefined symbols added to the set. +Upon encountering an archive file a traditional linker searches the objects +contained therein, and processes those that satisfy symbols in the unresolved +set. +.Pp +Handling mutually dependent archives may be awkward when using a traditional +linker. +Archive files may have to be specified multiple times, or the special command +line options +.Fl -start-group +and +.Fl -end-group +may be used to have the linker loop over the files in the group until no new +symbols are added to the set. +.Pp +.Nm +records all symbols found in objects and archives as it iterates over +command line arguments. +When +.Nm +encounters an undefined symbol that can be resolved by an object file +contained in a previously processed archive file, it immediately extracts +and links it into the output object. +.Pp +With certain archive inputs +.Nm +may produce different results compared to traditional linkers. +In practice, large bodies of third party software have been linked with +.Nm +without material issues. +.Pp +The +.Fl -warn-backrefs +option may be used to identify a linker invocation that may be incompatible +with traditional Unix-like linker behavior. diff --git a/docs/windows_support.rst b/docs/windows_support.rst index 6b06d29afafd..780c663a5379 100644 --- a/docs/windows_support.rst +++ b/docs/windows_support.rst @@ -56,9 +56,8 @@ Module-definition file ``EXPORTS``, ``HEAPSIZE``, ``STACKSIZE``, ``NAME``, and ``VERSION``. Debug info - :none:`No progress has been made`. Microsoft linker can interpret the CodeGen - debug info (old-style debug info) and PDB to emit an .pdb file. LLD doesn't - support neither. + :good:`Done`. LLD can emit PDBs that are at parity with those generated by + link.exe. However, LLD does not support /DEBUG:FASTLINK. Building LLD diff --git a/include/lld/Common/Driver.h b/include/lld/Common/Driver.h index 15ec3cd44cb5..f6d92933af62 100644 --- a/include/lld/Common/Driver.h +++ b/include/lld/Common/Driver.h @@ -30,7 +30,7 @@ bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, } namespace mach_o { -bool link(llvm::ArrayRef<const char *> Args, +bool link(llvm::ArrayRef<const char *> Args, bool CanExitEarly, llvm::raw_ostream &Diag = llvm::errs()); } diff --git a/include/lld/Common/ErrorHandler.h b/include/lld/Common/ErrorHandler.h index 8ae6f46ac59e..f17f7cc99035 100644 --- a/include/lld/Common/ErrorHandler.h +++ b/include/lld/Common/ErrorHandler.h @@ -7,21 +7,62 @@ // //===----------------------------------------------------------------------===// // -// In LLD, we have three levels of errors: fatal, error or warn. +// We designed lld's error handlers with the following goals in mind: // -// Fatal makes the program exit immediately with an error message. -// You shouldn't use it except for reporting a corrupted input file. +// - Errors can occur at any place where we handle user input, but we don't +// want them to affect the normal execution path too much. Ideally, +// handling errors should be as simple as reporting them and exit (but +// without actually doing exit). // -// Error prints out an error message and increment a global variable -// ErrorCount to record the fact that we met an error condition. It does -// not exit, so it is safe for a lld-as-a-library use case. It is generally -// useful because it can report more than one error in a single run. +// In particular, the design to wrap all functions that could fail with +// ErrorOr<T> is rejected because otherwise we would have to wrap a large +// number of functions in lld with ErrorOr. With that approach, if some +// function F can fail, not only F but all functions that transitively call +// F have to be wrapped with ErrorOr. That seemed too much. // -// Warn doesn't do anything but printing out a given message. +// - Finding only one error at a time is not sufficient. We want to find as +// many errors as possible with one execution of the linker. That means the +// linker needs to keep running after a first error and give up at some +// checkpoint (beyond which it would find cascading, false errors caused by +// the previous errors). // -// It is not recommended to use llvm::outs() or llvm::errs() directly -// in LLD because they are not thread-safe. The functions declared in -// this file are mutually excluded, so you want to use them instead. +// - We want a simple interface to report errors. Unlike Clang, the data we +// handle is compiled binary, so we don't need an error reporting mechanism +// that's as sophisticated as the one that Clang has. +// +// The current lld's error handling mechanism is simple: +// +// - When you find an error, report it using error() and continue as far as +// you can. An internal error counter is incremented by one every time you +// call error(). +// +// A common idiom to handle an error is calling error() and then returning +// a reasonable default value. For example, if your function handles a +// user-supplied alignment value, and if you find an invalid alignment +// (e.g. 17 which is not 2^n), you may report it using error() and continue +// as if it were alignment 1 (which is the simplest reasonable value). +// +// Note that you should not continue with an invalid value; that breaks the +// internal consistency. You need to maintain all variables have some sane +// value even after an error occurred. So, when you have to continue with +// some value, always use a dummy value. +// +// - Find a reasonable checkpoint at where you want to stop the linker, and +// add code to return from the function if errorCount() > 0. In most cases, +// a checkpoint already exists, so you don't need to do anything for this. +// +// This interface satisfies all the goals that we mentioned above. +// +// You should never call fatal() except for reporting a corrupted input file. +// fatal() immediately terminates the linker, so the function is not desirable +// if you are using lld as a subroutine in other program, and with that you +// can find only one error at a time. +// +// warn() doesn't do anything but printing out a given message. +// +// It is not recommended to use llvm::outs() or llvm::errs() directly in lld +// because they are not thread-safe. The functions declared in this file are +// thread-safe. // //===----------------------------------------------------------------------===// @@ -34,6 +75,10 @@ #include "llvm/Support/Error.h" #include "llvm/Support/FileOutputBuffer.h" +namespace llvm { +class DiagnosticInfo; +} + namespace lld { class ErrorHandler { @@ -74,6 +119,9 @@ inline uint64_t errorCount() { return errorHandler().ErrorCount; } LLVM_ATTRIBUTE_NORETURN void exitLld(int Val); +void diagnosticHandler(const llvm::DiagnosticInfo &DI); +void checkError(Error E); + // check functions are convenient functions to strip errors // from error-or-value objects. template <class T> T check(ErrorOr<T> E) { diff --git a/include/lld/Common/Strings.h b/include/lld/Common/Strings.h index 1a63f75f9ecf..e17b25763781 100644 --- a/include/lld/Common/Strings.h +++ b/include/lld/Common/Strings.h @@ -10,14 +10,40 @@ #ifndef LLD_STRINGS_H #define LLD_STRINGS_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/GlobPattern.h" #include <string> +#include <vector> namespace lld { // Returns a demangled C++ symbol name. If Name is not a mangled // name, it returns Optional::None. llvm::Optional<std::string> demangleItanium(llvm::StringRef Name); +llvm::Optional<std::string> demangleMSVC(llvm::StringRef S); + +std::vector<uint8_t> parseHex(llvm::StringRef S); +bool isValidCIdentifier(llvm::StringRef S); + +// Write the contents of the a buffer to a file +void saveBuffer(llvm::StringRef Buffer, const llvm::Twine &Path); + +// This class represents multiple glob patterns. +class StringMatcher { +public: + StringMatcher() = default; + explicit StringMatcher(llvm::ArrayRef<llvm::StringRef> Pat); + + bool match(llvm::StringRef S) const; + +private: + std::vector<llvm::GlobPattern> Patterns; +}; + +inline llvm::ArrayRef<uint8_t> toArrayRef(llvm::StringRef S) { + return {reinterpret_cast<const uint8_t *>(S.data()), S.size()}; } +} // namespace lld #endif diff --git a/include/lld/Common/TargetOptionsCommandFlags.h b/include/lld/Common/TargetOptionsCommandFlags.h index 9c4ff7cea3fb..8443b184aa70 100644 --- a/include/lld/Common/TargetOptionsCommandFlags.h +++ b/include/lld/Common/TargetOptionsCommandFlags.h @@ -18,4 +18,5 @@ namespace lld { llvm::TargetOptions InitTargetOptionsFromCodeGenFlags(); llvm::Optional<llvm::CodeModel::Model> GetCodeModelFromCMModel(); +std::string GetCPUStr(); } diff --git a/include/lld/Common/Timer.h b/include/lld/Common/Timer.h new file mode 100644 index 000000000000..6654af626919 --- /dev/null +++ b/include/lld/Common/Timer.h @@ -0,0 +1,59 @@ +//===- Timer.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_COMMON_TIMER_H +#define LLD_COMMON_TIMER_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringRef.h" +#include <assert.h> +#include <chrono> +#include <map> +#include <memory> + +namespace lld { + +class Timer; + +struct ScopedTimer { + explicit ScopedTimer(Timer &T); + + ~ScopedTimer(); + + void stop(); + + Timer *T = nullptr; +}; + +class Timer { +public: + Timer(llvm::StringRef Name, Timer &Parent); + + static Timer &root(); + + void start(); + void stop(); + void print(); + + double millis() const; + +private: + explicit Timer(llvm::StringRef Name); + void print(int Depth, double TotalDuration, bool Recurse = true) const; + + std::chrono::time_point<std::chrono::high_resolution_clock> StartTime; + std::chrono::nanoseconds Total; + std::vector<Timer *> Children; + std::string Name; + Timer *Parent; +}; + +} // namespace lld + +#endif diff --git a/include/lld/Common/Version.h b/include/lld/Common/Version.h index 93de77df5804..23a10ed6dbf3 100644 --- a/include/lld/Common/Version.h +++ b/include/lld/Common/Version.h @@ -18,7 +18,7 @@ #include "llvm/ADT/StringRef.h" namespace lld { -/// \brief Retrieves a string representing the complete lld version. +/// Retrieves a string representing the complete lld version. std::string getLLDVersion(); } diff --git a/include/lld/Core/DefinedAtom.h b/include/lld/Core/DefinedAtom.h index 6229d67e25a5..ba10b45411f1 100644 --- a/include/lld/Core/DefinedAtom.h +++ b/include/lld/Core/DefinedAtom.h @@ -18,7 +18,7 @@ namespace lld { class File; -/// \brief The fundamental unit of linking. +/// The fundamental unit of linking. /// /// A C function or global variable is an atom. An atom has content and /// attributes. The content of a function atom is the instructions that @@ -179,10 +179,10 @@ public: }; enum DynamicExport { - /// \brief The linker may or may not export this atom dynamically depending + /// The linker may or may not export this atom dynamically depending /// on the output type and other context of the link. dynamicExportNormal, - /// \brief The linker will always export this atom dynamically. + /// The linker will always export this atom dynamically. dynamicExportAlways, }; @@ -212,26 +212,26 @@ public: } }; - /// \brief returns a value for the order of this Atom within its file. + /// returns a value for the order of this Atom within its file. /// /// This is used by the linker to order the layout of Atoms so that the /// resulting image is stable and reproducible. virtual uint64_t ordinal() const = 0; - /// \brief the number of bytes of space this atom's content will occupy in the + /// the number of bytes of space this atom's content will occupy in the /// final linked image. /// /// For a function atom, it is the number of bytes of code in the function. virtual uint64_t size() const = 0; - /// \brief The size of the section from which the atom is instantiated. + /// The size of the section from which the atom is instantiated. /// /// Merge::mergeByLargestSection is defined in terms of section size /// and not in terms of atom size, so we need this function separate /// from size(). virtual uint64_t sectionSize() const { return 0; } - /// \brief The visibility of this atom to other atoms. + /// The visibility of this atom to other atoms. /// /// C static functions have scope scopeTranslationUnit. Regular C functions /// have scope scopeGlobal. Functions compiled with visibility=hidden have @@ -239,48 +239,48 @@ public: /// not by the OS loader. virtual Scope scope() const = 0; - /// \brief Whether the linker should use direct or indirect access to this + /// Whether the linker should use direct or indirect access to this /// atom. virtual Interposable interposable() const = 0; - /// \brief how the linker should handle if multiple atoms have the same name. + /// how the linker should handle if multiple atoms have the same name. virtual Merge merge() const = 0; - /// \brief The type of this atom, such as code or data. + /// The type of this atom, such as code or data. virtual ContentType contentType() const = 0; - /// \brief The alignment constraints on how this atom must be laid out in the + /// The alignment constraints on how this atom must be laid out in the /// final linked image (e.g. 16-byte aligned). virtual Alignment alignment() const = 0; - /// \brief Whether this atom must be in a specially named section in the final + /// Whether this atom must be in a specially named section in the final /// linked image, or if the linker can infer the section based on the /// contentType(). virtual SectionChoice sectionChoice() const = 0; - /// \brief If sectionChoice() != sectionBasedOnContent, then this return the + /// If sectionChoice() != sectionBasedOnContent, then this return the /// name of the section the atom should be placed into. virtual StringRef customSectionName() const = 0; - /// \brief constraints on whether the linker may dead strip away this atom. + /// constraints on whether the linker may dead strip away this atom. virtual DeadStripKind deadStrip() const = 0; - /// \brief Under which conditions should this atom be dynamically exported. + /// Under which conditions should this atom be dynamically exported. virtual DynamicExport dynamicExport() const { return dynamicExportNormal; } - /// \brief Code model used by the atom. + /// Code model used by the atom. virtual CodeModel codeModel() const { return codeNA; } - /// \brief Returns the OS memory protections required for this atom's content + /// Returns the OS memory protections required for this atom's content /// at runtime. /// /// A function atom is R_X, a global variable is RW_, and a read-only constant /// is R__. virtual ContentPermissions permissions() const; - /// \brief returns a reference to the raw (unrelocated) bytes of this Atom's + /// returns a reference to the raw (unrelocated) bytes of this Atom's /// content. virtual ArrayRef<uint8_t> rawContent() const = 0; @@ -317,10 +317,10 @@ public: const void *_it; }; - /// \brief Returns an iterator to the beginning of this Atom's References. + /// Returns an iterator to the beginning of this Atom's References. virtual reference_iterator begin() const = 0; - /// \brief Returns an iterator to the end of this Atom's References. + /// Returns an iterator to the end of this Atom's References. virtual reference_iterator end() const = 0; /// Adds a reference to this atom. @@ -361,11 +361,11 @@ protected: ~DefinedAtom() override = default; - /// \brief Returns a pointer to the Reference object that the abstract + /// Returns a pointer to the Reference object that the abstract /// iterator "points" to. virtual const Reference *derefIterator(const void *iter) const = 0; - /// \brief Adjusts the abstract iterator to "point" to the next Reference + /// Adjusts the abstract iterator to "point" to the next Reference /// object for this Atom. virtual void incrementIterator(const void *&iter) const = 0; }; diff --git a/include/lld/Core/File.h b/include/lld/Core/File.h index 20418688dfa0..54f533576a4b 100644 --- a/include/lld/Core/File.h +++ b/include/lld/Core/File.h @@ -43,7 +43,7 @@ class File { public: virtual ~File(); - /// \brief Kinds of files that are supported. + /// Kinds of files that are supported. enum Kind { kindErrorObject, ///< a error object file (.o) kindNormalizedObject, ///< a normalized file (.o) @@ -59,7 +59,7 @@ public: kindArchiveLibrary ///< archive (.a) }; - /// \brief Returns file kind. Need for dyn_cast<> on File objects. + /// Returns file kind. Need for dyn_cast<> on File objects. Kind kind() const { return _kind; } @@ -114,10 +114,8 @@ public: AtomRange(AtomVector<T> &v) : _v(v) {} AtomRange(const AtomVector<T> &v) : _v(const_cast<AtomVector<T> &>(v)) {} - typedef std::pointer_to_unary_function<const OwningAtomPtr<T>&, - const T*> ConstDerefFn; - - typedef std::pointer_to_unary_function<OwningAtomPtr<T>&, T*> DerefFn; + using ConstDerefFn = const T* (*)(const OwningAtomPtr<T>&); + using DerefFn = T* (*)(OwningAtomPtr<T>&); typedef llvm::mapped_iterator<typename AtomVector<T>::const_iterator, ConstDerefFn> ConstItTy; @@ -174,19 +172,19 @@ public: AtomVector<T> &_v; }; - /// \brief Must be implemented to return the AtomVector object for + /// Must be implemented to return the AtomVector object for /// all DefinedAtoms in this File. virtual const AtomRange<DefinedAtom> defined() const = 0; - /// \brief Must be implemented to return the AtomVector object for + /// Must be implemented to return the AtomVector object for /// all UndefinedAtomw in this File. virtual const AtomRange<UndefinedAtom> undefined() const = 0; - /// \brief Must be implemented to return the AtomVector object for + /// Must be implemented to return the AtomVector object for /// all SharedLibraryAtoms in this File. virtual const AtomRange<SharedLibraryAtom> sharedLibrary() const = 0; - /// \brief Must be implemented to return the AtomVector object for + /// Must be implemented to return the AtomVector object for /// all AbsoluteAtoms in this File. virtual const AtomRange<AbsoluteAtom> absolute() const = 0; @@ -196,7 +194,7 @@ public: /// of a different file. We need to destruct all atoms before any files. virtual void clearAtoms() = 0; - /// \brief If a file is parsed using a different method than doParse(), + /// If a file is parsed using a different method than doParse(), /// one must use this method to set the last error status, so that /// doParse will not be called twice. Only YAML reader uses this /// (because YAML reader does not read blobs but structured data). @@ -214,12 +212,12 @@ public: } protected: - /// \brief only subclasses of File can be instantiated + /// only subclasses of File can be instantiated File(StringRef p, Kind kind) : _path(p), _kind(kind), _ordinal(UINT64_MAX), _nextAtomOrdinal(0) {} - /// \brief Subclasses should override this method to parse the + /// Subclasses should override this method to parse the /// memory buffer passed to this file's constructor. virtual std::error_code doParse() { return std::error_code(); } diff --git a/include/lld/Core/Instrumentation.h b/include/lld/Core/Instrumentation.h index 162375905e17..939d64557587 100644 --- a/include/lld/Core/Instrumentation.h +++ b/include/lld/Core/Instrumentation.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Provide an Instrumentation API that optionally uses VTune interfaces. +/// Provide an Instrumentation API that optionally uses VTune interfaces. /// //===----------------------------------------------------------------------===// @@ -24,7 +24,7 @@ namespace lld { #ifdef LLD_HAS_VTUNE -/// \brief A unique global scope for instrumentation data. +/// A unique global scope for instrumentation data. /// /// Domains last for the lifetime of the application and cannot be destroyed. /// Multiple Domains created with the same name represent the same domain. @@ -38,7 +38,7 @@ public: __itt_domain *operator->() const { return _domain; } }; -/// \brief A global reference to a string constant. +/// A global reference to a string constant. /// /// These are uniqued by the ITT runtime and cannot be deleted. They are not /// specific to a domain. @@ -54,7 +54,7 @@ public: operator __itt_string_handle *() const { return _handle; } }; -/// \brief A task on a single thread. Nests within other tasks. +/// A task on a single thread. Nests within other tasks. /// /// Each thread has its own task stack and tasks nest recursively on that stack. /// A task cannot transfer threads. @@ -68,7 +68,7 @@ class ScopedTask { ScopedTask &operator=(const ScopedTask &) = delete; public: - /// \brief Create a task in Domain \p d named \p s. + /// Create a task in Domain \p d named \p s. ScopedTask(const Domain &d, const StringHandle &s) : _domain(d) { __itt_task_begin(d, __itt_null, __itt_null, s); } @@ -83,7 +83,7 @@ public: return *this; } - /// \brief Prematurely end this task. + /// Prematurely end this task. void end() { if (_domain) __itt_task_end(_domain); @@ -93,7 +93,7 @@ public: ~ScopedTask() { end(); } }; -/// \brief A specific point in time. Allows metadata to be associated. +/// A specific point in time. Allows metadata to be associated. class Marker { public: Marker(const Domain &d, const StringHandle &s) { diff --git a/include/lld/Core/LinkingContext.h b/include/lld/Core/LinkingContext.h index eb9510cbd215..52ab1a2480e8 100644 --- a/include/lld/Core/LinkingContext.h +++ b/include/lld/Core/LinkingContext.h @@ -16,7 +16,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdint> #include <memory> @@ -31,7 +30,7 @@ class Writer; class Node; class SharedLibraryFile; -/// \brief The LinkingContext class encapsulates "what and how" to link. +/// The LinkingContext class encapsulates "what and how" to link. /// /// The base class LinkingContext contains the options needed by core linking. /// Subclasses of LinkingContext have additional options needed by specific @@ -167,10 +166,10 @@ public: /// After all set* methods are called, the Driver calls this method /// to validate that there are no missing options or invalid combinations /// of options. If there is a problem, a description of the problem - /// is written to the supplied stream. + /// is written to the global error handler. /// /// \returns true if there is an error with the current settings. - bool validate(raw_ostream &diagnostics); + bool validate(); /// Formats symbol name for use in error messages. virtual std::string demangle(StringRef symbolName) const = 0; @@ -250,7 +249,7 @@ protected: private: /// Validate the subclass bits. Only called by validate. - virtual bool validateImpl(raw_ostream &diagnostics) = 0; + virtual bool validateImpl() = 0; }; } // end namespace lld diff --git a/include/lld/Core/PassManager.h b/include/lld/Core/PassManager.h index 2ea65ae13ace..f2ef10f406f2 100644 --- a/include/lld/Core/PassManager.h +++ b/include/lld/Core/PassManager.h @@ -20,7 +20,7 @@ namespace lld { class SimpleFile; class Pass; -/// \brief Owns and runs a collection of passes. +/// Owns and runs a collection of passes. /// /// This class is currently just a container for passes and a way to run them. /// @@ -40,7 +40,7 @@ public: } private: - /// \brief Passes in the order they should run. + /// Passes in the order they should run. std::vector<std::unique_ptr<Pass>> _passes; }; } // end namespace lld diff --git a/include/lld/Core/Reader.h b/include/lld/Core/Reader.h index c7baf86af61f..6cf6282ff39c 100644 --- a/include/lld/Core/Reader.h +++ b/include/lld/Core/Reader.h @@ -32,7 +32,7 @@ class File; class LinkingContext; class MachOLinkingContext; -/// \brief An abstract class for reading object files, library files, and +/// An abstract class for reading object files, library files, and /// executable files. /// /// Each file format (e.g. mach-o, etc) has a concrete subclass of Reader. @@ -46,14 +46,14 @@ public: /// 2) the whole file content buffer if the above is not enough. virtual bool canParse(llvm::file_magic magic, MemoryBufferRef mb) const = 0; - /// \brief Parse a supplied buffer (already filled with the contents of a + /// Parse a supplied buffer (already filled with the contents of a /// file) and create a File object. /// The resulting File object takes ownership of the MemoryBuffer. virtual ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb, const class Registry &) const = 0; }; -/// \brief An abstract class for handling alternate yaml representations +/// An abstract class for handling alternate yaml representations /// of object files. /// /// The YAML syntax allows "tags" which are used to specify the type of diff --git a/include/lld/Core/Resolver.h b/include/lld/Core/Resolver.h index fb62a779c0a5..5157c9fddc1a 100644 --- a/include/lld/Core/Resolver.h +++ b/include/lld/Core/Resolver.h @@ -28,7 +28,7 @@ namespace lld { class Atom; class LinkingContext; -/// \brief The Resolver is responsible for merging all input object files +/// The Resolver is responsible for merging all input object files /// and producing a merged graph. class Resolver { public: @@ -50,7 +50,7 @@ public: // Handle a shared library file. llvm::Error handleSharedLibrary(File &); - /// @brief do work of merging and resolving and return list + /// do work of merging and resolving and return list bool resolve(); std::unique_ptr<SimpleFile> resultFile() { return std::move(_result); } @@ -61,7 +61,7 @@ private: bool undefinesAdded(int begin, int end); File *getFile(int &index); - /// \brief The main function that iterates over the files to resolve + /// The main function that iterates over the files to resolve bool resolveUndefines(); void updateReferences(); void deadStripOptimize(); diff --git a/include/lld/Core/Simple.h b/include/lld/Core/Simple.h index 3aa7abf5d12b..feeed6ae473b 100644 --- a/include/lld/Core/Simple.h +++ b/include/lld/Core/Simple.h @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Provide simple implementations for Atoms and File. +/// Provide simple implementations for Atoms and File. /// //===----------------------------------------------------------------------===// diff --git a/include/lld/Core/SymbolTable.h b/include/lld/Core/SymbolTable.h index 9c39a6ed507c..156c56eafbf7 100644 --- a/include/lld/Core/SymbolTable.h +++ b/include/lld/Core/SymbolTable.h @@ -12,7 +12,7 @@ #include "lld/Common/LLVM.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/DJB.h" #include <cstring> #include <map> #include <vector> @@ -27,35 +27,35 @@ class ResolverOptions; class SharedLibraryAtom; class UndefinedAtom; -/// \brief The SymbolTable class is responsible for coalescing atoms. +/// The SymbolTable class is responsible for coalescing atoms. /// /// All atoms coalescable by-name or by-content should be added. /// The method replacement() can be used to find the replacement atom /// if an atom has been coalesced away. class SymbolTable { public: - /// @brief add atom to symbol table + /// add atom to symbol table bool add(const DefinedAtom &); - /// @brief add atom to symbol table + /// add atom to symbol table bool add(const UndefinedAtom &); - /// @brief add atom to symbol table + /// add atom to symbol table bool add(const SharedLibraryAtom &); - /// @brief add atom to symbol table + /// add atom to symbol table bool add(const AbsoluteAtom &); - /// @brief returns atom in symbol table for specified name (or nullptr) + /// returns atom in symbol table for specified name (or nullptr) const Atom *findByName(StringRef sym); - /// @brief returns vector of remaining UndefinedAtoms + /// returns vector of remaining UndefinedAtoms std::vector<const UndefinedAtom *> undefines(); - /// @brief if atom has been coalesced away, return replacement, else return atom + /// if atom has been coalesced away, return replacement, else return atom const Atom *replacement(const Atom *); - /// @brief if atom has been coalesced away, return true + /// if atom has been coalesced away, return true bool isCoalescedAway(const Atom *); private: @@ -65,7 +65,7 @@ private: static StringRef getEmptyKey() { return StringRef(); } static StringRef getTombstoneKey() { return StringRef(" ", 1); } static unsigned getHashValue(StringRef const val) { - return llvm::HashString(val); + return llvm::djbHash(val, 0); } static bool isEqual(StringRef const lhs, StringRef const rhs) { return lhs.equals(rhs); diff --git a/include/lld/Core/TODO.txt b/include/lld/Core/TODO.txt index 8b523045de75..2aa61ff8612d 100644 --- a/include/lld/Core/TODO.txt +++ b/include/lld/Core/TODO.txt @@ -6,9 +6,6 @@ include/lld/Core abstraction only works for returning low level OS errors. It does not work for describing formatting issues. -* We need to design a diagnostics interface. It would be nice to share code - with Clang_ where possible. - * We need to add more attributes to File. In particular, we need cpu and OS information (like target triples). We should also provide explicit support for `LLVM IR module flags metadata`__. diff --git a/include/lld/Core/Writer.h b/include/lld/Core/Writer.h index 1f0ca4cda41f..1cdfabefebd7 100644 --- a/include/lld/Core/Writer.h +++ b/include/lld/Core/Writer.h @@ -20,17 +20,17 @@ class File; class LinkingContext; class MachOLinkingContext; -/// \brief The Writer is an abstract class for writing object files, shared +/// The Writer is an abstract class for writing object files, shared /// library files, and executable files. Each file format (e.g. mach-o, etc) /// has a concrete subclass of Writer. class Writer { public: virtual ~Writer(); - /// \brief Write a file from the supplied File object + /// Write a file from the supplied File object virtual llvm::Error writeFile(const File &linkedFile, StringRef path) = 0; - /// \brief This method is called by Core Linking to give the Writer a chance + /// This method is called by Core Linking to give the Writer a chance /// to add file format specific "files" to set of files to be linked. This is /// how file format specific atoms can be added to the link. virtual void createImplicitFiles(std::vector<std::unique_ptr<File>> &) {} diff --git a/include/lld/ReaderWriter/MachOLinkingContext.h b/include/lld/ReaderWriter/MachOLinkingContext.h index 9eefa8c4d944..fde65880c3e3 100644 --- a/include/lld/ReaderWriter/MachOLinkingContext.h +++ b/include/lld/ReaderWriter/MachOLinkingContext.h @@ -89,7 +89,7 @@ public: bool exportDynamicSymbols); void addPasses(PassManager &pm) override; - bool validateImpl(raw_ostream &diagnostics) override; + bool validateImpl() override; std::string demangle(StringRef symbolName) const override; void createImplicitFiles(std::vector<std::unique_ptr<File>> &) override; @@ -201,7 +201,7 @@ public: uint32_t swiftVersion() const { return _swiftVersion; } - /// \brief Checks whether a given path on the filesystem exists. + /// Checks whether a given path on the filesystem exists. /// /// When running in -test_file_usage mode, this method consults an /// internally maintained list of files that exist (provided by -path_exists) @@ -211,7 +211,7 @@ public: /// Like pathExists() but only used on files - not directories. bool fileExists(StringRef path) const; - /// \brief Adds any library search paths derived from the given base, possibly + /// Adds any library search paths derived from the given base, possibly /// modified by -syslibroots. /// /// The set of paths added consists of approximately all syslibroot-prepended @@ -219,7 +219,7 @@ public: /// for whatever reason. With various edge-cases for compatibility. void addModifiedSearchDir(StringRef libPath, bool isSystemPath = false); - /// \brief Determine whether -lFoo can be resolve within the given path, and + /// Determine whether -lFoo can be resolve within the given path, and /// return the filename if so. /// /// The -lFoo option is documented to search for libFoo.dylib and libFoo.a in @@ -228,7 +228,7 @@ public: llvm::Optional<StringRef> searchDirForLibrary(StringRef path, StringRef libName) const; - /// \brief Iterates through all search path entries looking for libName (as + /// Iterates through all search path entries looking for libName (as /// specified by -lFoo). llvm::Optional<StringRef> searchLibrary(StringRef libName) const; @@ -236,11 +236,11 @@ public: /// the path with syslibroot. void addFrameworkSearchDir(StringRef fwPath, bool isSystemPath = false); - /// \brief Iterates through all framework directories looking for + /// Iterates through all framework directories looking for /// Foo.framework/Foo (when fwName = "Foo"). llvm::Optional<StringRef> findPathForFramework(StringRef fwName) const; - /// \brief The dylib's binary compatibility version, in the raw uint32 format. + /// The dylib's binary compatibility version, in the raw uint32 format. /// /// When building a dynamic library, this is the compatibility version that /// gets embedded into the result. Other Mach-O binaries that link against @@ -249,28 +249,28 @@ public: /// installed dynamic library. uint32_t compatibilityVersion() const { return _compatibilityVersion; } - /// \brief The dylib's current version, in the the raw uint32 format. + /// The dylib's current version, in the the raw uint32 format. /// /// When building a dynamic library, this is the current version that gets /// embedded into the result. Other Mach-O binaries that link against /// this library will store the compatibility version in its load command. uint32_t currentVersion() const { return _currentVersion; } - /// \brief The dylib's install name. + /// The dylib's install name. /// /// Binaries that link against the dylib will embed this path into the dylib /// load command. When loading the binaries at runtime, this is the location /// on disk that the loader will look for the dylib. StringRef installName() const { return _installName; } - /// \brief Whether or not the dylib has side effects during initialization. + /// Whether or not the dylib has side effects during initialization. /// /// Dylibs marked as being dead strippable provide the guarantee that loading /// the dylib has no side effects, allowing the linker to strip out the dylib /// when linking a binary that does not use any of its symbols. bool deadStrippableDylib() const { return _deadStrippableDylib; } - /// \brief Whether or not to use flat namespace. + /// Whether or not to use flat namespace. /// /// MachO usually uses a two-level namespace, where each external symbol /// referenced by the target is associated with the dylib that will provide @@ -282,7 +282,7 @@ public: /// loaded flat_namespace dylibs must be resolvable at build time. bool useFlatNamespace() const { return _flatNamespace; } - /// \brief How to handle undefined symbols. + /// How to handle undefined symbols. /// /// Options are: /// * error: Report an error and terminate linking. @@ -294,7 +294,7 @@ public: /// runtime. UndefinedMode undefinedMode() const { return _undefinedMode; } - /// \brief The path to the executable that will load the bundle at runtime. + /// The path to the executable that will load the bundle at runtime. /// /// When building a Mach-O bundle, this executable will be examined if there /// are undefined symbols after the main link phase. It is expected that this @@ -331,7 +331,7 @@ public: /// Add section alignment constraint on final layout. void addSectionAlignment(StringRef seg, StringRef sect, uint16_t align); - /// \brief Add a section based on a command-line sectcreate option. + /// Add a section based on a command-line sectcreate option. void addSectCreateSection(StringRef seg, StringRef sect, std::unique_ptr<MemoryBuffer> content); diff --git a/lib/Core/LinkingContext.cpp b/lib/Core/LinkingContext.cpp index 5de863aa7f37..0f225c322122 100644 --- a/lib/Core/LinkingContext.cpp +++ b/lib/Core/LinkingContext.cpp @@ -20,8 +20,8 @@ LinkingContext::LinkingContext() = default; LinkingContext::~LinkingContext() = default; -bool LinkingContext::validate(raw_ostream &diagnostics) { - return validateImpl(diagnostics); +bool LinkingContext::validate() { + return validateImpl(); } llvm::Error LinkingContext::writeFile(const File &linkedFile) const { diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 097a8177ea1f..ff67c282f47e 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -13,6 +13,7 @@ add_lld_library(lldDriver Support LINK_LIBS + lldCommon lldCore lldMachO lldReaderWriter diff --git a/lib/Driver/DarwinLdDriver.cpp b/lib/Driver/DarwinLdDriver.cpp index a019e9c32800..ad22845207e1 100644 --- a/lib/Driver/DarwinLdDriver.cpp +++ b/lib/Driver/DarwinLdDriver.cpp @@ -13,6 +13,8 @@ /// //===----------------------------------------------------------------------===// +#include "lld/Common/Args.h" +#include "lld/Common/ErrorHandler.h" #include "lld/Common/LLVM.h" #include "lld/Core/ArchiveLibraryFile.h" #include "lld/Core/Error.h" @@ -110,11 +112,11 @@ parseMemberFiles(std::unique_ptr<File> file) { return members; } -std::vector<std::unique_ptr<File>> -loadFile(MachOLinkingContext &ctx, StringRef path, - raw_ostream &diag, bool wholeArchive, bool upwardDylib) { +std::vector<std::unique_ptr<File>> loadFile(MachOLinkingContext &ctx, + StringRef path, bool wholeArchive, + bool upwardDylib) { if (ctx.logInputFiles()) - diag << path << "\n"; + message(path); ErrorOr<std::unique_ptr<MemoryBuffer>> mbOrErr = ctx.getMemoryBuffer(path); if (std::error_code ec = mbOrErr.getError()) @@ -155,10 +157,9 @@ static std::string canonicalizePath(StringRef path) { } static void addFile(StringRef path, MachOLinkingContext &ctx, - bool loadWholeArchive, - bool upwardDylib, raw_ostream &diag) { + bool loadWholeArchive, bool upwardDylib) { std::vector<std::unique_ptr<File>> files = - loadFile(ctx, path, diag, loadWholeArchive, upwardDylib); + loadFile(ctx, path, loadWholeArchive, upwardDylib); for (std::unique_ptr<File> &file : files) ctx.getNodes().push_back(llvm::make_unique<FileNode>(std::move(file))); } @@ -166,8 +167,7 @@ static void addFile(StringRef path, MachOLinkingContext &ctx, // Export lists are one symbol per line. Blank lines are ignored. // Trailing comments start with #. static std::error_code parseExportsList(StringRef exportFilePath, - MachOLinkingContext &ctx, - raw_ostream &diagnostics) { + MachOLinkingContext &ctx) { // Map in export list file. ErrorOr<std::unique_ptr<MemoryBuffer>> mb = MemoryBuffer::getFileOrSTDIN(exportFilePath); @@ -197,8 +197,7 @@ static std::error_code parseExportsList(StringRef exportFilePath, /// libfrob.a(bar.o):_bar /// x86_64:_foo64 static std::error_code parseOrderFile(StringRef orderFilePath, - MachOLinkingContext &ctx, - raw_ostream &diagnostics) { + MachOLinkingContext &ctx) { // Map in order file. ErrorOr<std::unique_ptr<MemoryBuffer>> mb = MemoryBuffer::getFileOrSTDIN(orderFilePath); @@ -252,8 +251,7 @@ static std::error_code parseOrderFile(StringRef orderFilePath, // per line. The <dir> prefix is prepended to each partial path. // static llvm::Error loadFileList(StringRef fileListPath, - MachOLinkingContext &ctx, bool forceLoad, - raw_ostream &diagnostics) { + MachOLinkingContext &ctx, bool forceLoad) { // If there is a comma, split off <dir>. std::pair<StringRef, StringRef> opt = fileListPath.split(','); StringRef filePath = opt.first; @@ -286,9 +284,9 @@ static llvm::Error loadFileList(StringRef fileListPath, + "'"); } if (ctx.testingFileUsage()) { - diagnostics << "Found filelist entry " << canonicalizePath(path) << '\n'; + message("Found filelist entry " + canonicalizePath(path)); } - addFile(path, ctx, forceLoad, false, diagnostics); + addFile(path, ctx, forceLoad, false); buffer = lineAndRest.second; } return llvm::Error::success(); @@ -317,8 +315,7 @@ static void parseLLVMOptions(const LinkingContext &ctx) { namespace lld { namespace mach_o { -bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, - raw_ostream &diagnostics) { +bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx) { // Parse command line options using DarwinLdOptions.td DarwinLdOptTable table; unsigned missingIndex; @@ -326,17 +323,20 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, llvm::opt::InputArgList parsedArgs = table.ParseArgs(args.slice(1), missingIndex, missingCount); if (missingCount) { - diagnostics << "error: missing arg value for '" - << parsedArgs.getArgString(missingIndex) << "' expected " - << missingCount << " argument(s).\n"; + error("missing arg value for '" + + Twine(parsedArgs.getArgString(missingIndex)) + "' expected " + + Twine(missingCount) + " argument(s)."); return false; } for (auto unknownArg : parsedArgs.filtered(OPT_UNKNOWN)) { - diagnostics << "warning: ignoring unknown argument: " - << unknownArg->getAsString(parsedArgs) << "\n"; + warn("ignoring unknown argument: " + + Twine(unknownArg->getAsString(parsedArgs))); } + errorHandler().Verbose = parsedArgs.hasArg(OPT_v); + errorHandler().ErrorLimit = args::getInteger(parsedArgs, OPT_error_limit, 20); + // Figure out output kind ( -dylib, -r, -bundle, -preload, or -static ) llvm::MachO::HeaderFileType fileType = llvm::MachO::MH_EXECUTE; bool isStaticExecutable = false; @@ -367,8 +367,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, if (llvm::opt::Arg *archStr = parsedArgs.getLastArg(OPT_arch)) { arch = MachOLinkingContext::archFromName(archStr->getValue()); if (arch == MachOLinkingContext::arch_unknown) { - diagnostics << "error: unknown arch named '" << archStr->getValue() - << "'\n"; + error("unknown arch named '" + Twine(archStr->getValue()) + "'"); return false; } } @@ -386,7 +385,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, if (parsedArgs.size() == 0) table.PrintHelp(llvm::outs(), args[0], "LLVM Linker", false); else - diagnostics << "error: -arch not specified and could not be inferred\n"; + error("-arch not specified and could not be inferred"); return false; } } @@ -402,7 +401,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, os = MachOLinkingContext::OS::macOSX; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { - diagnostics << "error: malformed macosx_version_min value\n"; + error("malformed macosx_version_min value"); return false; } break; @@ -410,7 +409,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, os = MachOLinkingContext::OS::iOS; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { - diagnostics << "error: malformed ios_version_min value\n"; + error("malformed ios_version_min value"); return false; } break; @@ -418,7 +417,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, os = MachOLinkingContext::OS::iOS_simulator; if (MachOLinkingContext::parsePackedVersion(minOS->getValue(), minOSVersion)) { - diagnostics << "error: malformed ios_simulator_version_min value\n"; + error("malformed ios_simulator_version_min value"); return false; } break; @@ -452,14 +451,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, if (llvm::opt::Arg *imageBase = parsedArgs.getLastArg(OPT_image_base)) { uint64_t baseAddress; if (parseNumberBase16(imageBase->getValue(), baseAddress)) { - diagnostics << "error: image_base expects a hex number\n"; + error("image_base expects a hex number"); return false; } else if (baseAddress < ctx.pageZeroSize()) { - diagnostics << "error: image_base overlaps with __PAGEZERO\n"; + error("image_base overlaps with __PAGEZERO"); return false; } else if (baseAddress % ctx.pageSize()) { - diagnostics << "error: image_base must be a multiple of page size (" - << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n"; + error("image_base must be a multiple of page size (0x" + + llvm::utohexstr(ctx.pageSize()) + ")"); return false; } @@ -488,13 +487,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // Handle -compatibility_version and -current_version if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_compatibility_version)) { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { - diagnostics - << "error: -compatibility_version can only be used with -dylib\n"; + error("-compatibility_version can only be used with -dylib"); return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { - diagnostics << "error: -compatibility_version value is malformed\n"; + error("-compatibility_version value is malformed"); return false; } ctx.setCompatibilityVersion(parsedVers); @@ -502,12 +500,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, if (llvm::opt::Arg *vers = parsedArgs.getLastArg(OPT_current_version)) { if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { - diagnostics << "-current_version can only be used with -dylib\n"; + error("-current_version can only be used with -dylib"); return false; } uint32_t parsedVers; if (MachOLinkingContext::parsePackedVersion(vers->getValue(), parsedVers)) { - diagnostics << "error: -current_version value is malformed\n"; + error("-current_version value is malformed"); return false; } ctx.setCurrentVersion(parsedVers); @@ -526,17 +524,19 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, alignStr += 2; unsigned long long alignValue; if (llvm::getAsUnsignedInteger(alignStr, 16, alignValue)) { - diagnostics << "error: -sectalign alignment value '" - << alignStr << "' not a valid number\n"; + error("-sectalign alignment value '" + Twine(alignStr) + + "' not a valid number"); return false; } uint16_t align = 1 << llvm::countTrailingZeros(alignValue); if (!llvm::isPowerOf2_64(alignValue)) { - diagnostics << "warning: alignment for '-sectalign " - << segName << " " << sectName - << llvm::format(" 0x%llX", alignValue) - << "' is not a power of two, using " - << llvm::format("0x%08X", align) << "\n"; + std::string Msg; + llvm::raw_string_ostream OS(Msg); + OS << "alignment for '-sectalign " << segName << " " << sectName + << llvm::format(" 0x%llX", alignValue) + << "' is not a power of two, using " << llvm::format("0x%08X", align); + OS.flush(); + warn(Msg); } ctx.addSectionAlignment(segName, sectName, align); } @@ -562,18 +562,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, if (parsedArgs.getLastArg(OPT_keep_private_externs)) { ctx.setKeepPrivateExterns(true); if (ctx.outputMachOType() != llvm::MachO::MH_OBJECT) - diagnostics << "warning: -keep_private_externs only used in -r mode\n"; + warn("-keep_private_externs only used in -r mode"); } // Handle -dependency_info <path> used by Xcode. - if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) { - if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) { - diagnostics << "warning: " << ec.message() - << ", processing '-dependency_info " - << depInfo->getValue() - << "'\n"; - } - } + if (llvm::opt::Arg *depInfo = parsedArgs.getLastArg(OPT_dependency_info)) + if (std::error_code ec = ctx.createDependencyFile(depInfo->getValue())) + warn(ec.message() + ", processing '-dependency_info " + + depInfo->getValue()); // In -test_file_usage mode, we'll be given an explicit list of paths that // exist. We'll also be expected to print out information about how we located @@ -639,31 +635,28 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // Now that we've constructed the final set of search paths, print out those // search paths in verbose mode. - if (parsedArgs.getLastArg(OPT_v)) { - diagnostics << "Library search paths:\n"; + if (errorHandler().Verbose) { + message("Library search paths:"); for (auto path : ctx.searchDirs()) { - diagnostics << " " << path << '\n'; + message(" " + path); } - diagnostics << "Framework search paths:\n"; + message("Framework search paths:"); for (auto path : ctx.frameworkDirs()) { - diagnostics << " " << path << '\n'; + message(" " + path); } } // Handle -exported_symbols_list <file> for (auto expFile : parsedArgs.filtered(OPT_exported_symbols_list)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { - diagnostics << "error: -exported_symbols_list cannot be combined " - << "with -unexported_symbol[s_list]\n"; - return false; + error("-exported_symbols_list cannot be combined with " + "-unexported_symbol[s_list]"); + return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); - if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, - diagnostics)) { - diagnostics << "error: " << ec.message() - << ", processing '-exported_symbols_list " - << expFile->getValue() - << "'\n"; + if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) { + error(ec.message() + ", processing '-exported_symbols_list " + + expFile->getValue()); return false; } } @@ -671,9 +664,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // Handle -exported_symbol <symbol> for (auto symbol : parsedArgs.filtered(OPT_exported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::blackList) { - diagnostics << "error: -exported_symbol cannot be combined " - << "with -unexported_symbol[s_list]\n"; - return false; + error("-exported_symbol cannot be combined with " + "-unexported_symbol[s_list]"); + return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::whiteList); ctx.addExportSymbol(symbol->getValue()); @@ -682,17 +675,14 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // Handle -unexported_symbols_list <file> for (auto expFile : parsedArgs.filtered(OPT_unexported_symbols_list)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { - diagnostics << "error: -unexported_symbols_list cannot be combined " - << "with -exported_symbol[s_list]\n"; - return false; + error("-unexported_symbols_list cannot be combined with " + "-exported_symbol[s_list]"); + return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); - if (std::error_code ec = parseExportsList(expFile->getValue(), ctx, - diagnostics)) { - diagnostics << "error: " << ec.message() - << ", processing '-unexported_symbols_list " - << expFile->getValue() - << "'\n"; + if (std::error_code ec = parseExportsList(expFile->getValue(), ctx)) { + error(ec.message() + ", processing '-unexported_symbols_list " + + expFile->getValue()); return false; } } @@ -700,9 +690,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // Handle -unexported_symbol <symbol> for (auto symbol : parsedArgs.filtered(OPT_unexported_symbol)) { if (ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) { - diagnostics << "error: -unexported_symbol cannot be combined " - << "with -exported_symbol[s_list]\n"; - return false; + error("-unexported_symbol cannot be combined with " + "-exported_symbol[s_list]"); + return false; } ctx.setExportMode(MachOLinkingContext::ExportMode::blackList); ctx.addExportSymbol(symbol->getValue()); @@ -711,30 +701,26 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // Handle obosolete -multi_module and -single_module if (llvm::opt::Arg *mod = parsedArgs.getLastArg(OPT_multi_module, OPT_single_module)) { - if (mod->getOption().getID() == OPT_multi_module) { - diagnostics << "warning: -multi_module is obsolete and being ignored\n"; - } - else { - if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) { - diagnostics << "warning: -single_module being ignored. " - "It is only for use when producing a dylib\n"; - } - } + if (mod->getOption().getID() == OPT_multi_module) + warn("-multi_module is obsolete and being ignored"); + else if (ctx.outputMachOType() != llvm::MachO::MH_DYLIB) + warn("-single_module being ignored. It is only for use when producing a " + "dylib"); } // Handle obsolete ObjC options: -objc_gc_compaction, -objc_gc, -objc_gc_only if (parsedArgs.getLastArg(OPT_objc_gc_compaction)) { - diagnostics << "error: -objc_gc_compaction is not supported\n"; + error("-objc_gc_compaction is not supported"); return false; } if (parsedArgs.getLastArg(OPT_objc_gc)) { - diagnostics << "error: -objc_gc is not supported\n"; + error("-objc_gc is not supported"); return false; } if (parsedArgs.getLastArg(OPT_objc_gc_only)) { - diagnostics << "error: -objc_gc_only is not supported\n"; + error("-objc_gc_only is not supported"); return false; } @@ -746,22 +732,20 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, case MachOLinkingContext::OS::macOSX: if ((minOSVersion < 0x000A0500) && (pie->getOption().getID() == OPT_pie)) { - diagnostics << "-pie can only be used when targeting " - "Mac OS X 10.5 or later\n"; + error("-pie can only be used when targeting Mac OS X 10.5 or later"); return false; } break; case MachOLinkingContext::OS::iOS: if ((minOSVersion < 0x00040200) && (pie->getOption().getID() == OPT_pie)) { - diagnostics << "-pie can only be used when targeting " - "iOS 4.2 or later\n"; + error("-pie can only be used when targeting iOS 4.2 or later"); return false; } break; case MachOLinkingContext::OS::iOS_simulator: if (pie->getOption().getID() == OPT_no_pie) { - diagnostics << "iOS simulator programs must be built PIE\n"; + error("iOS simulator programs must be built PIE"); return false; } break; @@ -774,12 +758,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, break; case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: - diagnostics << "warning: " << pie->getSpelling() << " being ignored. " - << "It is only used when linking main executables\n"; + warn(pie->getSpelling() + + " being ignored. It is only used when linking main executables"); break; default: - diagnostics << pie->getSpelling() - << " can only used when linking main executables\n"; + error(pie->getSpelling() + + " can only used when linking main executables"); return false; } } @@ -934,7 +918,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, uint32_t sdkVersion = 0; if (MachOLinkingContext::parsePackedVersion(arg->getValue(), sdkVersion)) { - diagnostics << "error: malformed sdkVersion value\n"; + error("malformed sdkVersion value"); return false; } ctx.setSdkVersion(sdkVersion); @@ -943,9 +927,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // with min_version, then we need to give an warning as we have no sdk // version to put in that command. // FIXME: We need to decide whether to make this an error. - diagnostics << "warning: -sdk_version is required when emitting " - "min version load command. " - "Setting sdk version to match provided min version\n"; + warn("-sdk_version is required when emitting min version load command. " + "Setting sdk version to match provided min version"); ctx.setSdkVersion(ctx.osMinVersion()); } @@ -954,7 +937,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, uint64_t version = 0; if (MachOLinkingContext::parsePackedVersion(arg->getValue(), version)) { - diagnostics << "error: malformed source_version value\n"; + error("malformed source_version value"); return false; } ctx.setSourceVersion(version); @@ -964,12 +947,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, if (llvm::opt::Arg *stackSize = parsedArgs.getLastArg(OPT_stack_size)) { uint64_t stackSizeVal; if (parseNumberBase16(stackSize->getValue(), stackSizeVal)) { - diagnostics << "error: stack_size expects a hex number\n"; + error("stack_size expects a hex number"); return false; } if ((stackSizeVal % ctx.pageSize()) != 0) { - diagnostics << "error: stack_size must be a multiple of page size (" - << "0x" << llvm::utohexstr(ctx.pageSize()) << ")\n"; + error("stack_size must be a multiple of page size (0x" + + llvm::utohexstr(ctx.pageSize()) + ")"); return false; } @@ -982,12 +965,9 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // Handle -order_file <file> for (auto orderFile : parsedArgs.filtered(OPT_order_file)) { - if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx, - diagnostics)) { - diagnostics << "error: " << ec.message() - << ", processing '-order_file " - << orderFile->getValue() - << "'\n"; + if (std::error_code ec = parseOrderFile(orderFile->getValue(), ctx)) { + error(ec.message() + ", processing '-order_file " + orderFile->getValue() + + "'"); return false; } } @@ -1011,8 +991,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, else if (StringRef(undef->getValue()).equals("dynamic_lookup")) UndefMode = MachOLinkingContext::UndefinedMode::dynamicLookup; else { - diagnostics << "error: invalid option to -undefined " - "[ warning | error | suppress | dynamic_lookup ]\n"; + error("invalid option to -undefined [ warning | error | suppress | " + "dynamic_lookup ]"); return false; } @@ -1026,8 +1006,8 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, // illegal. Emit a diagnostic if they've been (mis)used. if (UndefMode == MachOLinkingContext::UndefinedMode::warning || UndefMode == MachOLinkingContext::UndefinedMode::suppress) { - diagnostics << "error: can't use -undefined warning or suppress with " - "-twolevel_namespace\n"; + error("can't use -undefined warning or suppress with " + "-twolevel_namespace"); return false; } } @@ -1046,19 +1026,16 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, case llvm::MachO::MH_DYLIB: case llvm::MachO::MH_BUNDLE: if (!ctx.minOS("10.5", "2.0")) { - if (ctx.os() == MachOLinkingContext::OS::macOSX) { - diagnostics << "error: -rpath can only be used when targeting " - "OS X 10.5 or later\n"; - } else { - diagnostics << "error: -rpath can only be used when targeting " - "iOS 2.0 or later\n"; - } + if (ctx.os() == MachOLinkingContext::OS::macOSX) + error("-rpath can only be used when targeting OS X 10.5 or later"); + else + error("-rpath can only be used when targeting iOS 2.0 or later"); return false; } break; default: - diagnostics << "error: -rpath can only be used when creating " - "a dynamic final linked image\n"; + error("-rpath can only be used when creating a dynamic final linked " + "image"); return false; } @@ -1068,7 +1045,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, } // Parse the LLVM options before we process files in case the file handling - // makes use of things like DEBUG(). + // makes use of things like LLVM_DEBUG(). parseLLVMOptions(ctx); // Handle input files and sectcreate. @@ -1079,52 +1056,46 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, default: continue; case OPT_INPUT: - addFile(arg->getValue(), ctx, globalWholeArchive, false, diagnostics); + addFile(arg->getValue(), ctx, globalWholeArchive, false); break; case OPT_upward_library: - addFile(arg->getValue(), ctx, false, true, diagnostics); + addFile(arg->getValue(), ctx, false, true); break; case OPT_force_load: - addFile(arg->getValue(), ctx, true, false, diagnostics); + addFile(arg->getValue(), ctx, true, false); break; case OPT_l: case OPT_upward_l: upward = (arg->getOption().getID() == OPT_upward_l); resolvedPath = ctx.searchLibrary(arg->getValue()); if (!resolvedPath) { - diagnostics << "Unable to find library for " << arg->getSpelling() - << arg->getValue() << "\n"; + error("Unable to find library for " + arg->getSpelling() + + arg->getValue()); return false; } else if (ctx.testingFileUsage()) { - diagnostics << "Found " << (upward ? "upward " : " ") << "library " - << canonicalizePath(resolvedPath.getValue()) << '\n'; + message(Twine("Found ") + (upward ? "upward " : " ") + "library " + + canonicalizePath(resolvedPath.getValue())); } - addFile(resolvedPath.getValue(), ctx, globalWholeArchive, - upward, diagnostics); + addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward); break; case OPT_framework: case OPT_upward_framework: upward = (arg->getOption().getID() == OPT_upward_framework); resolvedPath = ctx.findPathForFramework(arg->getValue()); if (!resolvedPath) { - diagnostics << "Unable to find framework for " - << arg->getSpelling() << " " << arg->getValue() << "\n"; + error("Unable to find framework for " + arg->getSpelling() + " " + + arg->getValue()); return false; } else if (ctx.testingFileUsage()) { - diagnostics << "Found " << (upward ? "upward " : " ") << "framework " - << canonicalizePath(resolvedPath.getValue()) << '\n'; + message(Twine("Found ") + (upward ? "upward " : " ") + "framework " + + canonicalizePath(resolvedPath.getValue())); } - addFile(resolvedPath.getValue(), ctx, globalWholeArchive, - upward, diagnostics); + addFile(resolvedPath.getValue(), ctx, globalWholeArchive, upward); break; case OPT_filelist: - if (auto ec = loadFileList(arg->getValue(), - ctx, globalWholeArchive, - diagnostics)) { + if (auto ec = loadFileList(arg->getValue(), ctx, globalWholeArchive)) { handleAllErrors(std::move(ec), [&](const llvm::ErrorInfoBase &EI) { - diagnostics << "error: "; - EI.log(diagnostics); - diagnostics << ", processing '-filelist " << arg->getValue() << "'\n"; + error(EI.message() + ", processing '-filelist " + arg->getValue()); }); return false; } @@ -1138,7 +1109,7 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, MemoryBuffer::getFile(fileName); if (!contentOrErr) { - diagnostics << "error: can't open -sectcreate file " << fileName << "\n"; + error("can't open -sectcreate file " + Twine(fileName)); return false; } @@ -1149,12 +1120,12 @@ bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, } if (ctx.getNodes().empty()) { - diagnostics << "No input files\n"; + error("No input files"); return false; } // Validate the combination of options used. - return ctx.validate(diagnostics); + return ctx.validate(); } static void createFiles(MachOLinkingContext &ctx, bool Implicit) { @@ -1170,9 +1141,18 @@ static void createFiles(MachOLinkingContext &ctx, bool Implicit) { } /// This is where the link is actually performed. -bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { +bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly, + raw_ostream &Error) { + errorHandler().LogName = llvm::sys::path::filename(args[0]); + errorHandler().ErrorLimitExceededMsg = + "too many errors emitted, stopping now (use " + "'-error-limit 0' to see all errors)"; + errorHandler().ErrorOS = &Error; + errorHandler().ExitEarly = CanExitEarly; + errorHandler().ColorDiagnostics = Error.has_colors(); + MachOLinkingContext ctx; - if (!parse(args, ctx, diagnostics)) + if (!parse(args, ctx)) return false; if (ctx.doNothing()) return true; @@ -1214,9 +1194,10 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { if (auto ec = pm.runOnFile(*merged)) { // FIXME: This should be passed to logAllUnhandledErrors but it needs // to be passed a Twine instead of a string. - diagnostics << "Failed to run passes on file '" << ctx.outputPath() - << "': "; - logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); + *errorHandler().ErrorOS << "Failed to run passes on file '" + << ctx.outputPath() << "': "; + logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS, + std::string()); return false; } @@ -1227,11 +1208,18 @@ bool link(llvm::ArrayRef<const char *> args, raw_ostream &diagnostics) { if (auto ec = ctx.writeFile(*merged)) { // FIXME: This should be passed to logAllUnhandledErrors but it needs // to be passed a Twine instead of a string. - diagnostics << "Failed to write file '" << ctx.outputPath() << "': "; - logAllUnhandledErrors(std::move(ec), diagnostics, std::string()); + *errorHandler().ErrorOS << "Failed to write file '" << ctx.outputPath() + << "': "; + logAllUnhandledErrors(std::move(ec), *errorHandler().ErrorOS, + std::string()); return false; } + // Call exit() if we can to avoid calling destructors. + if (CanExitEarly) + exitLld(errorCount() ? 1 : 0); + + return true; } diff --git a/lib/Driver/DarwinLdOptions.td b/lib/Driver/DarwinLdOptions.td index fa07f33646e7..3bbde8bf1c1c 100644 --- a/lib/Driver/DarwinLdOptions.td +++ b/lib/Driver/DarwinLdOptions.td @@ -227,6 +227,14 @@ def t : Flag<["-"], "t">, HelpText<"Print the names of the input files as ld processes them">; def v : Flag<["-"], "v">, HelpText<"Print linker information">; +def error_limit : Separate<["-", "--"], "error-limit">, + MetaVarName<"<number>">, + HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">; + +// Ignored options +def lto_library : Separate<["-"], "lto_library">, + MetaVarName<"<path>">, + HelpText<"Ignored for compatibility with other linkers">; // Obsolete options def grp_obsolete : OptionGroup<"obsolete">, HelpText<"OBSOLETE OPTIONS">; diff --git a/lib/ReaderWriter/FileArchive.cpp b/lib/ReaderWriter/FileArchive.cpp index 04c0bee76989..2f52d9d34312 100644 --- a/lib/ReaderWriter/FileArchive.cpp +++ b/lib/ReaderWriter/FileArchive.cpp @@ -38,7 +38,7 @@ namespace lld { namespace { -/// \brief The FileArchive class represents an Archive Library file +/// The FileArchive class represents an Archive Library file class FileArchive : public lld::ArchiveLibraryFile { public: FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry ®, @@ -46,7 +46,7 @@ public: : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())), _registry(reg), _logLoading(logLoading) {} - /// \brief Check if any member of the archive contains an Atom with the + /// Check if any member of the archive contains an Atom with the /// specified name and return the File object for that member, or nullptr. File *find(StringRef name) override { auto member = _symbolMemberMap.find(name); @@ -77,7 +77,7 @@ public: return file; } - /// \brief parse each member + /// parse each member std::error_code parseAllMembers(std::vector<std::unique_ptr<File>> &result) override { if (std::error_code ec = parse()) diff --git a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp index aee9959ca6b8..8cb6710857e3 100644 --- a/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp +++ b/lib/ReaderWriter/MachO/ArchHandler_x86_64.cpp @@ -674,7 +674,7 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, *loc32 = ref.addend() + inAtomAddress - fixupAddress; return; case delta32Anon: - // The value we write here should be the the delta to the target + // The value we write here should be the delta to the target // after taking in to account the difference from the fixup back to the // last defined label // ie, if we have: @@ -690,7 +690,7 @@ void ArchHandler_x86_64::applyFixupRelocatable(const Reference &ref, *loc64 = ref.addend() + inAtomAddress - fixupAddress; return; case delta64Anon: - // The value we write here should be the the delta to the target + // The value we write here should be the delta to the target // after taking in to account the difference from the fixup back to the // last defined label // ie, if we have: diff --git a/lib/ReaderWriter/MachO/CMakeLists.txt b/lib/ReaderWriter/MachO/CMakeLists.txt index f2fc34772496..37d1de432c0f 100644 --- a/lib/ReaderWriter/MachO/CMakeLists.txt +++ b/lib/ReaderWriter/MachO/CMakeLists.txt @@ -26,6 +26,7 @@ add_lld_library(lldMachO Support LINK_LIBS + lldCommon lldCore lldYAML ${LLVM_PTHREAD_LIB} diff --git a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp index 1e210409237f..fa0aaa103eeb 100644 --- a/lib/ReaderWriter/MachO/CompactUnwindPass.cpp +++ b/lib/ReaderWriter/MachO/CompactUnwindPass.cpp @@ -282,7 +282,7 @@ public: private: llvm::Error perform(SimpleFile &mergedFile) override { - DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n"); + LLVM_DEBUG(llvm::dbgs() << "MachO Compact Unwind pass\n"); std::map<const Atom *, CompactUnwindEntry> unwindLocs; std::map<const Atom *, const Atom *> dwarfFrames; @@ -319,7 +319,7 @@ private: // Finally, we can start creating pages based on these entries. - DEBUG(llvm::dbgs() << " Splitting entries into pages\n"); + LLVM_DEBUG(llvm::dbgs() << " Splitting entries into pages\n"); // FIXME: we split the entries into pages naively: lots of 4k pages followed // by a small one. ld64 tried to minimize space and align them to real 4k // boundaries. That might be worth doing, or perhaps we could perform some @@ -336,11 +336,13 @@ private: pages.back().entries = remainingInfos.slice(0, entriesInPage); remainingInfos = remainingInfos.slice(entriesInPage); - DEBUG(llvm::dbgs() - << " Page from " << pages.back().entries[0].rangeStart->name() - << " to " << pages.back().entries.back().rangeStart->name() << " + " - << llvm::format("0x%x", pages.back().entries.back().rangeLength) - << " has " << entriesInPage << " entries\n"); + LLVM_DEBUG(llvm::dbgs() + << " Page from " + << pages.back().entries[0].rangeStart->name() << " to " + << pages.back().entries.back().rangeStart->name() << " + " + << llvm::format("0x%x", + pages.back().entries.back().rangeLength) + << " has " << entriesInPage << " entries\n"); } while (!remainingInfos.empty()); auto *unwind = new (_file.allocator()) @@ -360,7 +362,7 @@ private: const SimpleFile &mergedFile, std::map<const Atom *, CompactUnwindEntry> &unwindLocs, std::vector<const Atom *> &personalities, uint32_t &numLSDAs) { - DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n"); + LLVM_DEBUG(llvm::dbgs() << " Collecting __compact_unwind entries\n"); for (const DefinedAtom *atom : mergedFile.defined()) { if (atom->contentType() != DefinedAtom::typeCompactUnwindInfo) @@ -369,14 +371,15 @@ private: auto unwindEntry = extractCompactUnwindEntry(atom); unwindLocs.insert(std::make_pair(unwindEntry.rangeStart, unwindEntry)); - DEBUG(llvm::dbgs() << " Entry for " << unwindEntry.rangeStart->name() - << ", encoding=" - << llvm::format("0x%08x", unwindEntry.encoding)); + LLVM_DEBUG(llvm::dbgs() << " Entry for " + << unwindEntry.rangeStart->name() << ", encoding=" + << llvm::format("0x%08x", unwindEntry.encoding)); if (unwindEntry.personalityFunction) - DEBUG(llvm::dbgs() << ", personality=" - << unwindEntry.personalityFunction->name() - << ", lsdaLoc=" << unwindEntry.lsdaLocation->name()); - DEBUG(llvm::dbgs() << '\n'); + LLVM_DEBUG(llvm::dbgs() + << ", personality=" + << unwindEntry.personalityFunction->name() + << ", lsdaLoc=" << unwindEntry.lsdaLocation->name()); + LLVM_DEBUG(llvm::dbgs() << '\n'); // Count number of LSDAs we see, since we need to know how big the index // will be while laying out the section. @@ -454,7 +457,7 @@ private: const std::map<const Atom *, const Atom *> &dwarfFrames) { std::vector<CompactUnwindEntry> unwindInfos; - DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n"); + LLVM_DEBUG(llvm::dbgs() << " Creating __unwind_info entries\n"); // The final order in the __unwind_info section must be derived from the // order of typeCode atoms, since that's how they'll be put into the object // file eventually (yuck!). @@ -465,10 +468,10 @@ private: unwindInfos.push_back(finalizeUnwindInfoEntryForAtom( atom, unwindLocs, personalities, dwarfFrames)); - DEBUG(llvm::dbgs() << " Entry for " << atom->name() - << ", final encoding=" - << llvm::format("0x%08x", unwindInfos.back().encoding) - << '\n'); + LLVM_DEBUG(llvm::dbgs() + << " Entry for " << atom->name() << ", final encoding=" + << llvm::format("0x%08x", unwindInfos.back().encoding) + << '\n'); } return unwindInfos; diff --git a/lib/ReaderWriter/MachO/LayoutPass.cpp b/lib/ReaderWriter/MachO/LayoutPass.cpp index 7bca07eb16d6..9058e4f562e2 100644 --- a/lib/ReaderWriter/MachO/LayoutPass.cpp +++ b/lib/ReaderWriter/MachO/LayoutPass.cpp @@ -191,7 +191,7 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc, // Sort atoms by their ordinal overrides only if they fall in the same // chain. if (leftRoot == rightRoot) { - DEBUG(reason = formatReason("override", lc._override, rc._override)); + LLVM_DEBUG(reason = formatReason("override", lc._override, rc._override)); return lc._override < rc._override; } @@ -200,8 +200,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc, DefinedAtom::ContentPermissions rightPerms = rightRoot->permissions(); if (leftPerms != rightPerms) { - DEBUG(reason = - formatReason("contentPerms", (int)leftPerms, (int)rightPerms)); + LLVM_DEBUG( + reason = formatReason("contentPerms", (int)leftPerms, (int)rightPerms)); return leftPerms < rightPerms; } @@ -210,7 +210,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc, DefinedAtom::ContentType rightType = rightRoot->contentType(); if (leftType != rightType) { - DEBUG(reason = formatReason("contentType", (int)leftType, (int)rightType)); + LLVM_DEBUG(reason = + formatReason("contentType", (int)leftType, (int)rightType)); return leftType < rightType; } @@ -226,8 +227,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc, const File *rightFile = &rightRoot->file(); if (leftFile != rightFile) { - DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(), - (int)rightFile->ordinal())); + LLVM_DEBUG(reason = formatReason(".o order", (int)leftFile->ordinal(), + (int)rightFile->ordinal())); return leftFile->ordinal() < rightFile->ordinal(); } @@ -236,8 +237,8 @@ static bool compareAtomsSub(const LayoutPass::SortKey &lc, uint64_t rightOrdinal = rightRoot->ordinal(); if (leftOrdinal != rightOrdinal) { - DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(), - (int)rightRoot->ordinal())); + LLVM_DEBUG(reason = formatReason("ordinal", (int)leftRoot->ordinal(), + (int)rightRoot->ordinal())); return leftOrdinal < rightOrdinal; } @@ -251,7 +252,7 @@ static bool compareAtoms(const LayoutPass::SortKey &lc, LayoutPass::SortOverride customSorter) { std::string reason; bool result = compareAtomsSub(lc, rc, customSorter, reason); - DEBUG({ + LLVM_DEBUG({ StringRef comp = result ? "<" : ">="; llvm::dbgs() << "Layout: '" << lc._atom.get()->name() << "' " << comp << " '" @@ -441,7 +442,7 @@ void LayoutPass::undecorate(File::AtomRange<DefinedAtom> &atomRange, /// Perform the actual pass llvm::Error LayoutPass::perform(SimpleFile &mergedFile) { - DEBUG(llvm::dbgs() << "******** Laying out atoms:\n"); + LLVM_DEBUG(llvm::dbgs() << "******** Laying out atoms:\n"); // sort the atoms ScopedTask task(getDefaultDomain(), "LayoutPass"); File::AtomRange<DefinedAtom> atomRange = mergedFile.defined(); @@ -450,12 +451,12 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) { buildFollowOnTable(atomRange); // Check the structure of followon graph if running in debug mode. - DEBUG(checkFollowonChain(atomRange)); + LLVM_DEBUG(checkFollowonChain(atomRange)); // Build override maps buildOrdinalOverrideMap(atomRange); - DEBUG({ + LLVM_DEBUG({ llvm::dbgs() << "unsorted atoms:\n"; printDefinedAtoms(atomRange); }); @@ -465,15 +466,15 @@ llvm::Error LayoutPass::perform(SimpleFile &mergedFile) { [&](const LayoutPass::SortKey &l, const LayoutPass::SortKey &r) -> bool { return compareAtoms(l, r, _customSorter); }); - DEBUG(checkTransitivity(vec, _customSorter)); + LLVM_DEBUG(checkTransitivity(vec, _customSorter)); undecorate(atomRange, vec); - DEBUG({ + LLVM_DEBUG({ llvm::dbgs() << "sorted atoms:\n"; printDefinedAtoms(atomRange); }); - DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n"); + LLVM_DEBUG(llvm::dbgs() << "******** Finished laying out atoms\n"); return llvm::Error::success(); } diff --git a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp index 4ef7a62a8297..ce423d03aae3 100644 --- a/lib/ReaderWriter/MachO/MachOLinkingContext.cpp +++ b/lib/ReaderWriter/MachO/MachOLinkingContext.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "lld/Common/ErrorHandler.h" #include "lld/ReaderWriter/MachOLinkingContext.h" #include "ArchHandler.h" #include "File.h" @@ -579,29 +580,26 @@ MachOLinkingContext::findPathForFramework(StringRef fwName) const{ return llvm::None; } -bool MachOLinkingContext::validateImpl(raw_ostream &diagnostics) { +bool MachOLinkingContext::validateImpl() { // TODO: if -arch not specified, look at arch of first .o file. if (_currentVersion && _outputMachOType != MH_DYLIB) { - diagnostics << "error: -current_version can only be used with dylibs\n"; + error("-current_version can only be used with dylibs"); return false; } if (_compatibilityVersion && _outputMachOType != MH_DYLIB) { - diagnostics - << "error: -compatibility_version can only be used with dylibs\n"; + error("-compatibility_version can only be used with dylibs"); return false; } if (_deadStrippableDylib && _outputMachOType != MH_DYLIB) { - diagnostics - << "error: -mark_dead_strippable_dylib can only be used with dylibs.\n"; + error("-mark_dead_strippable_dylib can only be used with dylibs"); return false; } if (!_bundleLoader.empty() && outputMachOType() != MH_BUNDLE) { - diagnostics - << "error: -bundle_loader can only be used with Mach-O bundles\n"; + error("-bundle_loader can only be used with Mach-O bundles"); return false; } diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp index 3b07a40f9bf2..473de894894e 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileToAtoms.cpp @@ -906,7 +906,7 @@ readCompUnit(const NormalizedFile &normalizedFile, abbrevData.getU8(&abbrevOffset); uint32_t name; llvm::dwarf::Form form; - llvm::DWARFFormParams formParams = {version, addrSize, Format}; + llvm::dwarf::FormParams formParams = {version, addrSize, Format}; TranslationUnitSource tu; while ((name = abbrevData.getULEB128(&abbrevOffset)) | (form = static_cast<llvm::dwarf::Form>( @@ -1431,8 +1431,8 @@ llvm::Error normalizedObjectToAtoms(MachOFile *file, const NormalizedFile &normalizedFile, bool copyRefs) { - DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: " - << file->path() << "\n"); + LLVM_DEBUG(llvm::dbgs() << "******** Normalizing file to atoms: " + << file->path() << "\n"); bool scatterable = ((normalizedFile.flags & MH_SUBSECTIONS_VIA_SYMBOLS) != 0); // Create atoms from each section. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index eb8475881de8..12fb7c3c1e99 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -32,9 +32,9 @@ configure_lit_site_cfg( set(LLD_TEST_DEPS lld) if (NOT LLD_BUILT_STANDALONE) list(APPEND LLD_TEST_DEPS - FileCheck count not llvm-ar llvm-as llvm-dis llvm-dwarfdump llvm-nm - llc llvm-config llvm-objdump llvm-readelf llvm-readobj yaml2obj obj2yaml - llvm-mc llvm-lib llvm-pdbutil opt + FileCheck count llc llvm-ar llvm-as llvm-bcanalyzer llvm-config llvm-dis + llvm-dwarfdump llvm-lib llvm-mc llvm-nm llvm-objcopy llvm-objdump + llvm-pdbutil llvm-readelf llvm-readobj not obj2yaml opt yaml2obj ) endif() @@ -53,6 +53,12 @@ add_lit_testsuite(check-lld "Running lld test suite" DEPENDS ${LLD_TEST_DEPS} ) +add_lit_testsuites(LLD ${CMAKE_CURRENT_SOURCE_DIR} + PARAMS lld_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + lld_unit_site_config=${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg + DEPENDS ${LLD_TEST_DEPS} + ) + set_target_properties(check-lld PROPERTIES FOLDER "lld tests") # Add a legacy target spelling: lld-test diff --git a/test/COFF/Inputs/far-arm64-abs.s b/test/COFF/Inputs/far-arm64-abs.s new file mode 100644 index 000000000000..98ccbac5e751 --- /dev/null +++ b/test/COFF/Inputs/far-arm64-abs.s @@ -0,0 +1,6 @@ +.global too_far26 +.global too_far19 +.global too_far14 +too_far26 = 0x08011000 +too_far19 = 0x00111000 +too_far14 = 0x00021000 diff --git a/test/COFF/Inputs/generic.yaml b/test/COFF/Inputs/generic.yaml new file mode 100644 index 000000000000..88c87655cf47 --- /dev/null +++ b/test/COFF/Inputs/generic.yaml @@ -0,0 +1,282 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC1831C0C7442414000000004889542408894C24044883C418C3 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004220000' + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 04000000F10000002F0000002D003C1101000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F1000000760000002A0047110000000000000000000000001C000000000000000000000003100000000000000000006D61696E000D003E117400000001006172676300120045114F0100000400000017000000000005000D003E110010000001006172677600120045114F01000008000000170000000000050002004F110000F20000002800000000000000000000001C00000000000000020000001C00000000000000020000001700000003000000F40000001800000001000000100139E9A066A1995A99DD01F5A392F26D7C0000F30000003000000000443A5C7372635C6C6C766D6275696C645C636C5C52656C656173655C7836345C67656E657269632E63707000000000 + Subsections: + - !Symbols + Records: + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ ] + Machine: X64 + FrontendMajor: 7 + FrontendMinor: 0 + FrontendBuild: 0 + FrontendQFE: 0 + BackendMajor: 7000 + BackendMinor: 0 + BackendBuild: 0 + BackendQFE: 0 + Version: 'clang version 7.0.0 ' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 28 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4099 + Flags: [ ] + DisplayName: main + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: argc + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 335 + Flags: 0 + BasePointerOffset: 4 + Range: + OffsetStart: 23 + ISectStart: 0 + Range: 5 + Gaps: + - Kind: S_LOCAL + LocalSym: + Type: 4096 + Flags: [ IsParameter ] + VarName: argv + - Kind: S_DEFRANGE_REGISTER_REL + DefRangeRegisterRelSym: + Register: 335 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 23 + ISectStart: 0 + Range: 5 + Gaps: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 28 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'D:\src\llvmbuild\cl\Release\x64\generic.cpp' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: false + EndDelta: 0 + - Offset: 23 + LineStart: 3 + IsStatement: false + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'D:\src\llvmbuild\cl\Release\x64\generic.cpp' + Kind: MD5 + Checksum: 39E9A066A1995A99DD01F5A392F26D7C + - !StringTable + Strings: + - 'D:\src\llvmbuild\cl\Release\x64\generic.cpp' + - '' + - '' + - '' + Relocations: + - VirtualAddress: 100 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 139 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 143 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 174 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 178 + SymbolName: .text + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 196 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 200 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 040000000A000210700600000C0001000E0001120200000074000000001000000E0008107400000000000200011000001200011600000000021000006D61696E00F3F2F1 + Types: + - Kind: LF_POINTER + Pointer: + ReferentType: 1648 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 4096 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4097 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4098 + Name: main + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000001C00000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: .xdata + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 28 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 594448369 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .xdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 1192424177 + Number: 4 + - Name: .drectve + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 48 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 149686238 + Number: 5 + - Name: '.debug$S' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 324 + NumberOfRelocations: 8 + NumberOfLinenumbers: 0 + CheckSum: 4196717433 + Number: 6 + - Name: '.debug$T' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 68 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 485351071 + Number: 7 + - Name: .pdata + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 722740324 + Number: 8 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/globals-dia-func-collision3.obj b/test/COFF/Inputs/globals-dia-func-collision3.obj Binary files differnew file mode 100644 index 000000000000..ce9b87379617 --- /dev/null +++ b/test/COFF/Inputs/globals-dia-func-collision3.obj diff --git a/test/COFF/Inputs/globals-dia-vfunc-collision.obj b/test/COFF/Inputs/globals-dia-vfunc-collision.obj Binary files differnew file mode 100644 index 000000000000..3191c3ea2b28 --- /dev/null +++ b/test/COFF/Inputs/globals-dia-vfunc-collision.obj diff --git a/test/COFF/Inputs/globals-dia-vfunc-collision2.obj b/test/COFF/Inputs/globals-dia-vfunc-collision2.obj Binary files differnew file mode 100644 index 000000000000..f40610216675 --- /dev/null +++ b/test/COFF/Inputs/globals-dia-vfunc-collision2.obj diff --git a/test/COFF/Inputs/globals-dia-vfunc-simple.obj b/test/COFF/Inputs/globals-dia-vfunc-simple.obj Binary files differnew file mode 100644 index 000000000000..f0a9b4da836d --- /dev/null +++ b/test/COFF/Inputs/globals-dia-vfunc-simple.obj diff --git a/test/COFF/Inputs/guardcf-align-foobar.yaml b/test/COFF/Inputs/guardcf-align-foobar.yaml new file mode 100644 index 000000000000..7878c459a4fd --- /dev/null +++ b/test/COFF/Inputs/guardcf-align-foobar.yaml @@ -0,0 +1,51 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text.foo + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 31C0C3 + - Name: .text.bar + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: FFE1 +symbols: + - Name: .text.foo + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 3 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3963538403 + Number: 1 + - Name: .text.bar + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 2 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 1143549852 + Number: 2 + - Name: foo + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: bar + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/loadconfig-cfg-x64.s b/test/COFF/Inputs/loadconfig-cfg-x64.s new file mode 100644 index 000000000000..1440b115f46a --- /dev/null +++ b/test/COFF/Inputs/loadconfig-cfg-x64.s @@ -0,0 +1,11 @@ +# This is the _load_config_used definition needed for /guard:cf tests. + + .section .rdata,"dr" +.globl _load_config_used +_load_config_used: + .long 256 + .fill 124, 1, 0 + .quad __guard_fids_table + .quad __guard_fids_count + .long __guard_flags + .fill 128, 1, 0 diff --git a/test/COFF/Inputs/natvis-1.natvis b/test/COFF/Inputs/natvis-1.natvis new file mode 100644 index 000000000000..8797a363655e --- /dev/null +++ b/test/COFF/Inputs/natvis-1.natvis @@ -0,0 +1 @@ +1st Natvis Test diff --git a/test/COFF/Inputs/natvis-2.natvis b/test/COFF/Inputs/natvis-2.natvis new file mode 100644 index 000000000000..50ba44306c4a --- /dev/null +++ b/test/COFF/Inputs/natvis-2.natvis @@ -0,0 +1 @@ +Second Natvis Test diff --git a/test/COFF/Inputs/natvis-3.natvis b/test/COFF/Inputs/natvis-3.natvis new file mode 100644 index 000000000000..a10b1a120a69 --- /dev/null +++ b/test/COFF/Inputs/natvis-3.natvis @@ -0,0 +1 @@ +Third Natvis Test diff --git a/test/COFF/Inputs/order.yaml b/test/COFF/Inputs/order.yaml new file mode 100644 index 000000000000..02e91d12261d --- /dev/null +++ b/test/COFF/Inputs/order.yaml @@ -0,0 +1,76 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: unrelated2 + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .text + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 2 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: fn4 + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .text + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: fn1 + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/otherFunc.s b/test/COFF/Inputs/otherFunc.s new file mode 100644 index 000000000000..ae8b9228a61a --- /dev/null +++ b/test/COFF/Inputs/otherFunc.s @@ -0,0 +1,7 @@ +.global otherFunc +.global MessageBoxA +.text +otherFunc: + ret +MessageBoxA: + ret diff --git a/test/COFF/Inputs/pdb-file-statics-a.yaml b/test/COFF/Inputs/pdb-file-statics-a.yaml new file mode 100644 index 000000000000..957eb5aee869 --- /dev/null +++ b/test/COFF/Inputs/pdb-file-statics-a.yaml @@ -0,0 +1,1866 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'D:\src\llvmbuild\cl\Debug\x64\a.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 11 + FrontendBuild: 25547 + FrontendQFE: 0 + BackendMajor: 19 + BackendMinor: 11 + BackendBuild: 25547 + BackendQFE: 0 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_LDATA32 + DataSym: + Type: 116 + DisplayName: x + - Kind: S_UDT + UDTSym: + Type: 4193 + UDTName: '__vc_attributes::event_sourceAttribute' + - Kind: S_UDT + UDTSym: + Type: 4185 + UDTName: '__vc_attributes::event_sourceAttribute::optimize_e' + - Kind: S_UDT + UDTSym: + Type: 4182 + UDTName: '__vc_attributes::event_sourceAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4178 + UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute' + - Kind: S_UDT + UDTSym: + Type: 4172 + UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4168 + UDTName: '__vc_attributes::helper_attributes::usageAttribute' + - Kind: S_UDT + UDTSym: + Type: 4162 + UDTName: '__vc_attributes::helper_attributes::usageAttribute::usage_e' + - Kind: S_UDT + UDTSym: + Type: 4158 + UDTName: '__vc_attributes::threadingAttribute' + - Kind: S_UDT + UDTSym: + Type: 4150 + UDTName: '__vc_attributes::threadingAttribute::threading_e' + - Kind: S_UDT + UDTSym: + Type: 4146 + UDTName: '__vc_attributes::aggregatableAttribute' + - Kind: S_UDT + UDTSym: + Type: 4138 + UDTName: '__vc_attributes::aggregatableAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4134 + UDTName: '__vc_attributes::event_receiverAttribute' + - Kind: S_UDT + UDTSym: + Type: 4124 + UDTName: '__vc_attributes::event_receiverAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4120 + UDTName: '__vc_attributes::moduleAttribute' + - Kind: S_UDT + UDTSym: + Type: 4106 + UDTName: '__vc_attributes::moduleAttribute::type_e' + - !FileChecksums + Checksums: + - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp' + Kind: MD5 + Checksum: 70DD90BF2C1A2E8D7C450DFA55E3062D + - !InlineeLines + HasExtraFiles: false + Sites: + - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp' + LineNum: 8 + Inlinee: 4099 + - !StringTable + Strings: + - 'd:\src\llvmbuild\cl\debug\x64\a.cpp' + - 'D:\src\llvmbuild\cl\Debug\x64\a.obj' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4203 + Relocations: + - VirtualAddress: 132 + SymbolName: '?x@@3HA' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 136 + SymbolName: '?x@@3HA' + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4096 + - Kind: LF_POINTER + Pointer: + ReferentType: 1648 + Attrs: 65548 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: a + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116, 4098 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 2 + ArgumentList: 4100 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4101 + Name: main + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: b + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::moduleAttribute' + UniqueName: '.?AUmoduleAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: dll + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: exe + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: service + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4 + Name: unspecified + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: EXE + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: SERVICE + - Kind: LF_ENUM + Enum: + NumEnumerators: 6 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4105 + Name: '__vc_attributes::moduleAttribute::type_e' + UniqueName: '.?AW4type_e@moduleAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'd:\src\llvmbuild\cl\debug\x64\predefined c++ attributes (compiler internal)' + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4106 + SourceFile: 4107 + LineNumber: 482 + - Kind: LF_MODIFIER + Modifier: + ModifiedType: 112 + Modifiers: [ None, Const ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4109 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4106, 4110, 4110, 4110, 116, 48, 4110, 116, + 4110, 4110, 116, 48, 48, 4110, 4110 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4104 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4104 + ThisType: 4112 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 15 + ArgumentList: 4111 + ThisPointerAdjustment: 0 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4106 ] + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4104 + ThisType: 4112 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4114 + ThisPointerAdjustment: 0 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4104 + ThisType: 4112 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4116 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4113 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4115 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4117 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4106 + Name: type_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 3 + MethodList: 4118 + Name: moduleAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 0 + Name: type + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 8 + Name: name + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 16 + Name: version + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 24 + Name: uuid + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 32 + Name: lcid + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 36 + Name: control + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 40 + Name: helpstring + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 48 + Name: helpstringcontext + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 56 + Name: helpstringdll + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 64 + Name: helpfile + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 72 + Name: helpcontext + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 76 + Name: hidden + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 77 + Name: restricted + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 80 + Name: custom + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4110 + FieldOffset: 88 + Name: resource_name + - Kind: LF_STRUCTURE + Class: + MemberCount: 19 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4119 + Name: '__vc_attributes::moduleAttribute' + UniqueName: '.?AUmoduleAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 96 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4120 + SourceFile: 4107 + LineNumber: 481 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::event_receiverAttribute' + UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: native + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: com + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: managed + - Kind: LF_ENUM + Enum: + NumEnumerators: 3 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4123 + Name: '__vc_attributes::event_receiverAttribute::type_e' + UniqueName: '.?AW4type_e@event_receiverAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4124 + SourceFile: 4107 + LineNumber: 136 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4124, 48 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4122 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4122 + ThisType: 4127 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 2 + ArgumentList: 4126 + ThisPointerAdjustment: 0 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4124 ] + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4122 + ThisType: 4127 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4129 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4122 + ThisType: 4127 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4116 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4128 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4130 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4131 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4124 + Name: type_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 3 + MethodList: 4132 + Name: event_receiverAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4124 + FieldOffset: 0 + Name: type + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 4 + Name: layout_dependent + - Kind: LF_STRUCTURE + Class: + MemberCount: 6 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4133 + Name: '__vc_attributes::event_receiverAttribute' + UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 8 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4134 + SourceFile: 4107 + LineNumber: 135 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::aggregatableAttribute' + UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: never + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: allowed + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: always + - Kind: LF_ENUM + Enum: + NumEnumerators: 3 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4137 + Name: '__vc_attributes::aggregatableAttribute::type_e' + UniqueName: '.?AW4type_e@aggregatableAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4138 + SourceFile: 4107 + LineNumber: 545 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4138 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4136 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4136 + ThisType: 4141 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4140 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4136 + ThisType: 4141 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4116 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4142 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4143 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4138 + Name: type_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 2 + MethodList: 4144 + Name: aggregatableAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4138 + FieldOffset: 0 + Name: type + - Kind: LF_STRUCTURE + Class: + MemberCount: 4 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4145 + Name: '__vc_attributes::aggregatableAttribute' + UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4146 + SourceFile: 4107 + LineNumber: 544 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::threadingAttribute' + UniqueName: '.?AUthreadingAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: apartment + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: single + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: free + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4 + Name: neutral + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 5 + Name: both + - Kind: LF_ENUM + Enum: + NumEnumerators: 5 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4149 + Name: '__vc_attributes::threadingAttribute::threading_e' + UniqueName: '.?AW4threading_e@threadingAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4150 + SourceFile: 4107 + LineNumber: 423 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4150 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4148 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4148 + ThisType: 4153 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4152 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4148 + ThisType: 4153 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4116 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4154 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4155 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4150 + Name: threading_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 2 + MethodList: 4156 + Name: threadingAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4150 + FieldOffset: 0 + Name: value + - Kind: LF_STRUCTURE + Class: + MemberCount: 4 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4157 + Name: '__vc_attributes::threadingAttribute' + UniqueName: '.?AUthreadingAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4158 + SourceFile: 4107 + LineNumber: 422 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::helper_attributes::usageAttribute' + UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: eAnyUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: eCoClassUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: eCOMInterfaceUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 6 + Name: eInterfaceUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 8 + Name: eMemberUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16 + Name: eMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 32 + Name: eInterfaceMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 64 + Name: eInterfaceMemberUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 128 + Name: eCoClassMemberUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 256 + Name: eCoClassMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 768 + Name: eGlobalMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1024 + Name: eGlobalDataUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2048 + Name: eClassUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4096 + Name: eInterfaceParameterUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 12288 + Name: eMethodParameterUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16384 + Name: eIDLModuleUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 32768 + Name: eAnonymousUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 65536 + Name: eTypedefUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 131072 + Name: eUnionUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 262144 + Name: eEnumUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 524288 + Name: eDefineTagUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1048576 + Name: eStructUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2097152 + Name: eLocalUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4194304 + Name: ePropertyUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 8388608 + Name: eEventUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16777216 + Name: eTemplateUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16777216 + Name: eModuleUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 33554432 + Name: eIllegalUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 67108864 + Name: eAsynchronousUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4161535 + Name: eAnyIDLUsage + - Kind: LF_ENUM + Enum: + NumEnumerators: 30 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4161 + Name: '__vc_attributes::helper_attributes::usageAttribute::usage_e' + UniqueName: '.?AW4usage_e@usageAttribute@helper_attributes@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4162 + SourceFile: 4107 + LineNumber: 51 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 117 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4160 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4160 + ThisType: 4165 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4164 + ThisPointerAdjustment: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4162 + Name: usage_e + - Kind: LF_ONEMETHOD + OneMethod: + Type: 4166 + Attrs: 3 + VFTableOffset: -1 + Name: usageAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 117 + FieldOffset: 0 + Name: value + - Kind: LF_STRUCTURE + Class: + MemberCount: 3 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4167 + Name: '__vc_attributes::helper_attributes::usageAttribute' + UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4168 + SourceFile: 4107 + LineNumber: 49 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute' + UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: eBoolean + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: eInteger + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: eFloat + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: eDouble + - Kind: LF_ENUM + Enum: + NumEnumerators: 4 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4171 + Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e' + UniqueName: '.?AW4type_e@v1_alttypeAttribute@helper_attributes@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4172 + SourceFile: 4107 + LineNumber: 38 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4172 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4170 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4170 + ThisType: 4175 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4174 + ThisPointerAdjustment: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4172 + Name: type_e + - Kind: LF_ONEMETHOD + OneMethod: + Type: 4176 + Attrs: 3 + VFTableOffset: -1 + Name: v1_alttypeAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4172 + FieldOffset: 0 + Name: type + - Kind: LF_STRUCTURE + Class: + MemberCount: 3 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4177 + Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute' + UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4178 + SourceFile: 4107 + LineNumber: 37 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::event_sourceAttribute' + UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: native + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: com + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: managed + - Kind: LF_ENUM + Enum: + NumEnumerators: 3 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4181 + Name: '__vc_attributes::event_sourceAttribute::type_e' + UniqueName: '.?AW4type_e@event_sourceAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4182 + SourceFile: 4107 + LineNumber: 1142 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: speed + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: size + - Kind: LF_ENUM + Enum: + NumEnumerators: 2 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4184 + Name: '__vc_attributes::event_sourceAttribute::optimize_e' + UniqueName: '.?AW4optimize_e@event_sourceAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4185 + SourceFile: 4107 + LineNumber: 1145 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4182 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4180 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4180 + ThisType: 4188 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4187 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4180 + ThisType: 4188 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4116 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4189 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4190 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4182 + Name: type_e + - Kind: LF_NESTTYPE + NestedType: + Type: 4185 + Name: optimize_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 2 + MethodList: 4191 + Name: event_sourceAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4182 + FieldOffset: 0 + Name: type + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4185 + FieldOffset: 4 + Name: optimize + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 8 + Name: decorate + - Kind: LF_STRUCTURE + Class: + MemberCount: 7 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4192 + Name: '__vc_attributes::event_sourceAttribute' + UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 12 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4193 + SourceFile: 4107 + LineNumber: 1141 + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'D:\src\llvmbuild\cl\Debug\x64' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\bin\HostX64\x64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-Z7 -O1 -c -MT -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\ATLMFC\include" -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include" -I"C:\Program' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: ' Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\shared" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\um"' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4197, 4198 ] + - Kind: LF_STRING_ID + StringId: + Id: 4199 + String: ' -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\winrt" -TP -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: a.cpp + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'D:\src\llvmbuild\cl\Debug\x64\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4195, 4196, 4201, 4202, 4200 ] + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 4883EC288B0D0000000085C97405E8000000004883C428C3 + Relocations: + - VirtualAddress: 6 + SymbolName: '?x@@3HA' + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 15 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_REL32 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 24 + DbgStart: 4 + DbgEnd: 19 + FunctionType: 4099 + Flags: [ HasOptimizedDebugInfo ] + DisplayName: a + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: __formal + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 18 + MayHaveNoName: 0 + Range: + OffsetStart: 0 + ISectStart: 0 + Range: 10 + Gaps: + - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + DefRangeFramePointerRelFullScopeSym: + Register: 48 + - Kind: S_CALLEES + CallerSym: + FuncID: [ 4103 ] + - Kind: S_FILESTATIC + FileStaticSym: + Index: 116 + ModFilenameOffset: 37 + Flags: [ IsEnregisteredGlobal, IsEnregisteredStatic ] + Name: x + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 18 + MayHaveNoName: 0 + Range: + OffsetStart: 10 + ISectStart: 0 + Range: 9 + Gaps: + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 40 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, Inlined ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 48 + Type: 116 + Register: CVRegRSP + VarName: __formal + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 24 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp' + Lines: + - Offset: 0 + LineStart: 7 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 8 + IsStatement: true + EndDelta: 0 + - Offset: 14 + LineStart: 9 + IsStatement: true + EndDelta: 0 + - Offset: 19 + LineStart: 10 + IsStatement: true + EndDelta: 0 + Columns: + Relocations: + - VirtualAddress: 44 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 80 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 84 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 132 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 136 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 208 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 212 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 4883EC288B050000000085C0740D8BC8E8000000008B05000000004883C428C3 + Relocations: + - VirtualAddress: 6 + SymbolName: '?x@@3HA' + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 17 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 23 + SymbolName: '?x@@3HA' + Type: IMAGE_REL_AMD64_REL32 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 32 + DbgStart: 4 + DbgEnd: 27 + FunctionType: 4102 + Flags: [ HasOptimizedDebugInfo ] + DisplayName: main + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: argc + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 18 + MayHaveNoName: 0 + Range: + OffsetStart: 0 + ISectStart: 0 + Range: 16 + Gaps: + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 18 + MayHaveNoName: 1 + Range: + OffsetStart: 27 + ISectStart: 0 + Range: 5 + Gaps: + - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + DefRangeFramePointerRelFullScopeSym: + Register: 48 + - Kind: S_LOCAL + LocalSym: + Type: 4098 + Flags: [ IsParameter ] + VarName: argv + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 331 + MayHaveNoName: 0 + Range: + OffsetStart: 0 + ISectStart: 0 + Range: 21 + Gaps: + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 331 + MayHaveNoName: 1 + Range: + OffsetStart: 27 + ISectStart: 0 + Range: 5 + Gaps: + - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + DefRangeFramePointerRelFullScopeSym: + Register: 56 + - Kind: S_INLINESITE + InlineSiteSym: + Inlinee: 4099 + - Kind: S_CALLEES + CallerSym: + FuncID: [ 4103 ] + - Kind: S_INLINESITE_END + ScopeEndSym: + - Kind: S_FILESTATIC + FileStaticSym: + Index: 116 + ModFilenameOffset: 37 + Flags: [ IsEnregisteredGlobal, IsEnregisteredStatic ] + Name: x + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 17 + MayHaveNoName: 0 + Range: + OffsetStart: 10 + ISectStart: 0 + Range: 22 + Gaps: + - GapStartOffset: 11 + Range: 6 + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 40 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling ] + - Kind: S_INLINEES + CallerSym: + FuncID: [ 4099 ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 48 + Type: 116 + Register: CVRegRSP + VarName: argc + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 56 + Type: 4098 + Register: CVRegRSP + VarName: argv + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 32 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'd:\src\llvmbuild\cl\debug\x64\a.cpp' + Lines: + - Offset: 0 + LineStart: 12 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 13 + IsStatement: true + EndDelta: 0 + - Offset: 27 + LineStart: 15 + IsStatement: true + EndDelta: 0 + Columns: + Relocations: + - VirtualAddress: 44 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 79 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 83 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 95 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 99 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 134 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 138 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 150 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 154 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 229 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 233 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 336 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 340 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000001800000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_ADDR32NB + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000002000000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN7' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN7' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$main' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: '@comp.id' + Value: 17130443 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '@feat.00' + Value: 2147484048 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1120 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6700 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: .bss + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '?x@@3HA' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '.text$mn' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 24 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 211387054 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: '.debug$S' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 264 + NumberOfRelocations: 8 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '.text$mn' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 32 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 3834856183 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: '.debug$S' + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 384 + NumberOfRelocations: 14 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 7 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '?b@@YAXH@Z' + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '?a@@YAXH@Z' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN5' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: '$LN7' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$unwind$?a@@YAXH@Z' + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 2942184094 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$pdata$?a@@YAXH@Z' + Value: 0 + SectionNumber: 10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .xdata + Value: 0 + SectionNumber: 11 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 7 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$unwind$main' + Value: 0 + SectionNumber: 11 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 12 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 4185285206 + Number: 7 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$pdata$main' + Value: 0 + SectionNumber: 12 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/test/COFF/Inputs/pdb-file-statics-b.yaml b/test/COFF/Inputs/pdb-file-statics-b.yaml new file mode 100644 index 000000000000..8b7a311f0f8b --- /dev/null +++ b/test/COFF/Inputs/pdb-file-statics-b.yaml @@ -0,0 +1,1552 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 2020202F44454641554C544C49423A224C4942434D5422202F44454641554C544C49423A224F4C444E414D45532220 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_OBJNAME + ObjNameSym: + Signature: 0 + ObjectName: 'D:\src\llvmbuild\cl\Debug\x64\b.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 11 + FrontendBuild: 25547 + FrontendQFE: 0 + BackendMajor: 19 + BackendMinor: 11 + BackendBuild: 25547 + BackendQFE: 0 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_LDATA32 + DataSym: + Type: 116 + DisplayName: y + - Kind: S_UDT + UDTSym: + Type: 4189 + UDTName: '__vc_attributes::event_sourceAttribute' + - Kind: S_UDT + UDTSym: + Type: 4181 + UDTName: '__vc_attributes::event_sourceAttribute::optimize_e' + - Kind: S_UDT + UDTSym: + Type: 4178 + UDTName: '__vc_attributes::event_sourceAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4174 + UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute' + - Kind: S_UDT + UDTSym: + Type: 4168 + UDTName: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4164 + UDTName: '__vc_attributes::helper_attributes::usageAttribute' + - Kind: S_UDT + UDTSym: + Type: 4158 + UDTName: '__vc_attributes::helper_attributes::usageAttribute::usage_e' + - Kind: S_UDT + UDTSym: + Type: 4154 + UDTName: '__vc_attributes::threadingAttribute' + - Kind: S_UDT + UDTSym: + Type: 4146 + UDTName: '__vc_attributes::threadingAttribute::threading_e' + - Kind: S_UDT + UDTSym: + Type: 4142 + UDTName: '__vc_attributes::aggregatableAttribute' + - Kind: S_UDT + UDTSym: + Type: 4134 + UDTName: '__vc_attributes::aggregatableAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4130 + UDTName: '__vc_attributes::event_receiverAttribute' + - Kind: S_UDT + UDTSym: + Type: 4120 + UDTName: '__vc_attributes::event_receiverAttribute::type_e' + - Kind: S_UDT + UDTSym: + Type: 4116 + UDTName: '__vc_attributes::moduleAttribute' + - Kind: S_UDT + UDTSym: + Type: 4102 + UDTName: '__vc_attributes::moduleAttribute::type_e' + - !FileChecksums + Checksums: + - FileName: 'd:\src\llvmbuild\cl\debug\x64\b.cpp' + Kind: MD5 + Checksum: 8B4E383DAF442E63771294D52BF55155 + - !StringTable + Strings: + - 'd:\src\llvmbuild\cl\debug\x64\b.cpp' + - 'D:\src\llvmbuild\cl\Debug\x64\b.obj' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4199 + Relocations: + - VirtualAddress: 132 + SymbolName: '?y@@3HA' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 136 + SymbolName: '?y@@3HA' + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: b + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: a + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::moduleAttribute' + UniqueName: '.?AUmoduleAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: dll + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: exe + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: service + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4 + Name: unspecified + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: EXE + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: SERVICE + - Kind: LF_ENUM + Enum: + NumEnumerators: 6 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4101 + Name: '__vc_attributes::moduleAttribute::type_e' + UniqueName: '.?AW4type_e@moduleAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'd:\src\llvmbuild\cl\debug\x64\predefined c++ attributes (compiler internal)' + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4102 + SourceFile: 4103 + LineNumber: 482 + - Kind: LF_MODIFIER + Modifier: + ModifiedType: 112 + Modifiers: [ None, Const ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4105 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4102, 4106, 4106, 4106, 116, 48, 4106, 116, + 4106, 4106, 116, 48, 48, 4106, 4106 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4100 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4100 + ThisType: 4108 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 15 + ArgumentList: 4107 + ThisPointerAdjustment: 0 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4102 ] + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4100 + ThisType: 4108 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4110 + ThisPointerAdjustment: 0 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4100 + ThisType: 4108 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4112 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4109 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4111 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4113 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4102 + Name: type_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 3 + MethodList: 4114 + Name: moduleAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4102 + FieldOffset: 0 + Name: type + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 8 + Name: name + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 16 + Name: version + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 24 + Name: uuid + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 32 + Name: lcid + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 36 + Name: control + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 40 + Name: helpstring + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 48 + Name: helpstringcontext + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 56 + Name: helpstringdll + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 64 + Name: helpfile + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 116 + FieldOffset: 72 + Name: helpcontext + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 76 + Name: hidden + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 77 + Name: restricted + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 80 + Name: custom + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4106 + FieldOffset: 88 + Name: resource_name + - Kind: LF_STRUCTURE + Class: + MemberCount: 19 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4115 + Name: '__vc_attributes::moduleAttribute' + UniqueName: '.?AUmoduleAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 96 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4116 + SourceFile: 4103 + LineNumber: 481 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::event_receiverAttribute' + UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: native + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: com + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: managed + - Kind: LF_ENUM + Enum: + NumEnumerators: 3 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4119 + Name: '__vc_attributes::event_receiverAttribute::type_e' + UniqueName: '.?AW4type_e@event_receiverAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4120 + SourceFile: 4103 + LineNumber: 136 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4120, 48 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4118 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4118 + ThisType: 4123 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 2 + ArgumentList: 4122 + ThisPointerAdjustment: 0 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4120 ] + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4118 + ThisType: 4123 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4125 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4118 + ThisType: 4123 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4112 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4124 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4126 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4127 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4120 + Name: type_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 3 + MethodList: 4128 + Name: event_receiverAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4120 + FieldOffset: 0 + Name: type + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 4 + Name: layout_dependent + - Kind: LF_STRUCTURE + Class: + MemberCount: 6 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4129 + Name: '__vc_attributes::event_receiverAttribute' + UniqueName: '.?AUevent_receiverAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 8 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4130 + SourceFile: 4103 + LineNumber: 135 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::aggregatableAttribute' + UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: never + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: allowed + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: always + - Kind: LF_ENUM + Enum: + NumEnumerators: 3 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4133 + Name: '__vc_attributes::aggregatableAttribute::type_e' + UniqueName: '.?AW4type_e@aggregatableAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4134 + SourceFile: 4103 + LineNumber: 545 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4134 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4132 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4132 + ThisType: 4137 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4136 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4132 + ThisType: 4137 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4112 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4138 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4139 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4134 + Name: type_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 2 + MethodList: 4140 + Name: aggregatableAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4134 + FieldOffset: 0 + Name: type + - Kind: LF_STRUCTURE + Class: + MemberCount: 4 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4141 + Name: '__vc_attributes::aggregatableAttribute' + UniqueName: '.?AUaggregatableAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4142 + SourceFile: 4103 + LineNumber: 544 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::threadingAttribute' + UniqueName: '.?AUthreadingAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: apartment + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: single + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: free + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4 + Name: neutral + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 5 + Name: both + - Kind: LF_ENUM + Enum: + NumEnumerators: 5 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4145 + Name: '__vc_attributes::threadingAttribute::threading_e' + UniqueName: '.?AW4threading_e@threadingAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4146 + SourceFile: 4103 + LineNumber: 423 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4146 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4144 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4144 + ThisType: 4149 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4148 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4144 + ThisType: 4149 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4112 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4150 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4151 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4146 + Name: threading_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 2 + MethodList: 4152 + Name: threadingAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4146 + FieldOffset: 0 + Name: value + - Kind: LF_STRUCTURE + Class: + MemberCount: 4 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4153 + Name: '__vc_attributes::threadingAttribute' + UniqueName: '.?AUthreadingAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4154 + SourceFile: 4103 + LineNumber: 422 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::helper_attributes::usageAttribute' + UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: eAnyUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: eCoClassUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: eCOMInterfaceUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 6 + Name: eInterfaceUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 8 + Name: eMemberUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16 + Name: eMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 32 + Name: eInterfaceMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 64 + Name: eInterfaceMemberUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 128 + Name: eCoClassMemberUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 256 + Name: eCoClassMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 768 + Name: eGlobalMethodUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1024 + Name: eGlobalDataUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2048 + Name: eClassUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4096 + Name: eInterfaceParameterUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 12288 + Name: eMethodParameterUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16384 + Name: eIDLModuleUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 32768 + Name: eAnonymousUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 65536 + Name: eTypedefUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 131072 + Name: eUnionUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 262144 + Name: eEnumUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 524288 + Name: eDefineTagUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1048576 + Name: eStructUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2097152 + Name: eLocalUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4194304 + Name: ePropertyUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 8388608 + Name: eEventUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16777216 + Name: eTemplateUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 16777216 + Name: eModuleUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 33554432 + Name: eIllegalUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 67108864 + Name: eAsynchronousUsage + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 4161535 + Name: eAnyIDLUsage + - Kind: LF_ENUM + Enum: + NumEnumerators: 30 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4157 + Name: '__vc_attributes::helper_attributes::usageAttribute::usage_e' + UniqueName: '.?AW4usage_e@usageAttribute@helper_attributes@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4158 + SourceFile: 4103 + LineNumber: 51 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 117 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4156 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4156 + ThisType: 4161 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4160 + ThisPointerAdjustment: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4158 + Name: usage_e + - Kind: LF_ONEMETHOD + OneMethod: + Type: 4162 + Attrs: 3 + VFTableOffset: -1 + Name: usageAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 117 + FieldOffset: 0 + Name: value + - Kind: LF_STRUCTURE + Class: + MemberCount: 3 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4163 + Name: '__vc_attributes::helper_attributes::usageAttribute' + UniqueName: '.?AUusageAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4164 + SourceFile: 4103 + LineNumber: 49 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute' + UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: eBoolean + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: eInteger + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: eFloat + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 3 + Name: eDouble + - Kind: LF_ENUM + Enum: + NumEnumerators: 4 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4167 + Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute::type_e' + UniqueName: '.?AW4type_e@v1_alttypeAttribute@helper_attributes@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4168 + SourceFile: 4103 + LineNumber: 38 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4168 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4166 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4166 + ThisType: 4171 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4170 + ThisPointerAdjustment: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4168 + Name: type_e + - Kind: LF_ONEMETHOD + OneMethod: + Type: 4172 + Attrs: 3 + VFTableOffset: -1 + Name: v1_alttypeAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4168 + FieldOffset: 0 + Name: type + - Kind: LF_STRUCTURE + Class: + MemberCount: 3 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4173 + Name: '__vc_attributes::helper_attributes::v1_alttypeAttribute' + UniqueName: '.?AUv1_alttypeAttribute@helper_attributes@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 4 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4174 + SourceFile: 4103 + LineNumber: 37 + - Kind: LF_STRUCTURE + Class: + MemberCount: 0 + Options: [ None, ForwardReference, HasUniqueName ] + FieldList: 0 + Name: '__vc_attributes::event_sourceAttribute' + UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 0 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: native + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: com + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 2 + Name: managed + - Kind: LF_ENUM + Enum: + NumEnumerators: 3 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4177 + Name: '__vc_attributes::event_sourceAttribute::type_e' + UniqueName: '.?AW4type_e@event_sourceAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4178 + SourceFile: 4103 + LineNumber: 1142 + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 0 + Name: speed + - Kind: LF_ENUMERATE + Enumerator: + Attrs: 3 + Value: 1 + Name: size + - Kind: LF_ENUM + Enum: + NumEnumerators: 2 + Options: [ None, Nested, HasUniqueName ] + FieldList: 4180 + Name: '__vc_attributes::event_sourceAttribute::optimize_e' + UniqueName: '.?AW4optimize_e@event_sourceAttribute@__vc_attributes@@' + UnderlyingType: 116 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4181 + SourceFile: 4103 + LineNumber: 1145 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 4178 ] + - Kind: LF_POINTER + Pointer: + ReferentType: 4176 + Attrs: 66572 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4176 + ThisType: 4184 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 1 + ArgumentList: 4183 + ThisPointerAdjustment: 0 + - Kind: LF_MFUNCTION + MemberFunction: + ReturnType: 3 + ClassType: 4176 + ThisType: 4184 + CallConv: NearC + Options: [ None, Constructor ] + ParameterCount: 0 + ArgumentList: 4112 + ThisPointerAdjustment: 0 + - Kind: LF_METHODLIST + MethodOverloadList: + Methods: + - Type: 4185 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Type: 4186 + Attrs: 3 + VFTableOffset: -1 + Name: '' + - Kind: LF_FIELDLIST + FieldList: + - Kind: LF_NESTTYPE + NestedType: + Type: 4178 + Name: type_e + - Kind: LF_NESTTYPE + NestedType: + Type: 4181 + Name: optimize_e + - Kind: LF_METHOD + OverloadedMethod: + NumOverloads: 2 + MethodList: 4187 + Name: event_sourceAttribute + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4178 + FieldOffset: 0 + Name: type + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 4181 + FieldOffset: 4 + Name: optimize + - Kind: LF_MEMBER + DataMember: + Attrs: 3 + Type: 48 + FieldOffset: 8 + Name: decorate + - Kind: LF_STRUCTURE + Class: + MemberCount: 7 + Options: [ None, HasConstructorOrDestructor, ContainsNestedClass, HasUniqueName ] + FieldList: 4188 + Name: '__vc_attributes::event_sourceAttribute' + UniqueName: '.?AUevent_sourceAttribute@__vc_attributes@@' + DerivationList: 0 + VTableShape: 0 + Size: 12 + - Kind: LF_UDT_SRC_LINE + UdtSourceLine: + UDT: 4189 + SourceFile: 4103 + LineNumber: 1141 + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'D:\src\llvmbuild\cl\Debug\x64' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\bin\HostX64\x64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-Z7 -O1 -c -MT -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\ATLMFC\include" -I"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.11.25503\include" -I"C:\Program' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: ' Files (x86)\Windows Kits\NETFXSDK\4.6.1\include\um" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\ucrt" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\shared" -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\um"' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4193, 4194 ] + - Kind: LF_STRING_ID + StringId: + Id: 4195 + String: ' -I"C:\Program Files (x86)\Windows Kits\10\include\10.0.16299.0\winrt" -TP -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: b.cpp + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'D:\src\llvmbuild\cl\Debug\x64\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4191, 4192, 4197, 4198, 4196 ] + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 4883EC288B0D0000000085C97405E8000000004883C428C3 + Relocations: + - VirtualAddress: 6 + SymbolName: '?y@@3HA' + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 15 + SymbolName: '?a@@YAXH@Z' + Type: IMAGE_REL_AMD64_REL32 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 24 + DbgStart: 4 + DbgEnd: 19 + FunctionType: 4098 + Flags: [ HasOptimizedDebugInfo ] + DisplayName: b + - Kind: S_LOCAL + LocalSym: + Type: 116 + Flags: [ IsParameter ] + VarName: __formal + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 18 + MayHaveNoName: 0 + Range: + OffsetStart: 0 + ISectStart: 0 + Range: 10 + Gaps: + - Kind: S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE + DefRangeFramePointerRelFullScopeSym: + Register: 48 + - Kind: S_CALLEES + CallerSym: + FuncID: [ 4099 ] + - Kind: S_FILESTATIC + FileStaticSym: + Index: 116 + ModFilenameOffset: 37 + Flags: [ IsEnregisteredGlobal, IsEnregisteredStatic ] + Name: y + - Kind: S_DEFRANGE_REGISTER + DefRangeRegisterSym: + Register: 18 + MayHaveNoName: 0 + Range: + OffsetStart: 10 + ISectStart: 0 + Range: 9 + Gaps: + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 40 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 48 + Type: 116 + Register: CVRegRSP + VarName: __formal + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 24 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'd:\src\llvmbuild\cl\debug\x64\b.cpp' + Lines: + - Offset: 0 + LineStart: 7 + IsStatement: true + EndDelta: 0 + - Offset: 4 + LineStart: 8 + IsStatement: true + EndDelta: 0 + - Offset: 14 + LineStart: 9 + IsStatement: true + EndDelta: 0 + - Offset: 19 + LineStart: 10 + IsStatement: true + EndDelta: 0 + Columns: + Relocations: + - VirtualAddress: 44 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 80 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 84 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 132 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 136 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 208 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 212 + SymbolName: '?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_SECTION + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000001800000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$?b@@YAXH@Z' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: '@comp.id' + Value: 17130443 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '@feat.00' + Value: 2147484048 + SectionNumber: -1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .drectve + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 47 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$S' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1096 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6636 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: .bss + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 4 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '?y@@3HA' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: '.text$mn' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 24 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 211387054 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: '.debug$S' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 264 + NumberOfRelocations: 8 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '?a@@YAXH@Z' + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '?b@@YAXH@Z' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN5' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$unwind$?b@@YAXH@Z' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 2942184094 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '$pdata$?b@@YAXH@Z' + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/test/COFF/Inputs/pdb-globals.yaml b/test/COFF/Inputs/pdb-globals.yaml index 98ef914d9041..669522d7811f 100644 --- a/test/COFF/Inputs/pdb-globals.yaml +++ b/test/COFF/Inputs/pdb-globals.yaml @@ -125,29 +125,21 @@ sections: Type: 116 Flags: [ IsParameter ] VarName: argc - - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: - Kind: S_LOCAL LocalSym: Type: 4099 Flags: [ IsParameter ] VarName: argv - - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: - Kind: S_LOCAL LocalSym: Type: 4103 Flags: [ ] VarName: P - - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: - Kind: S_LOCAL LocalSym: Type: 116 Flags: [ ] VarName: N - - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: - Kind: S_PROC_ID_END ScopeEndSym: - Kind: S_LPROC32_ID @@ -408,8 +400,6 @@ sections: Type: 4108 Flags: [ IsParameter ] VarName: this - - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: - Kind: S_PROC_ID_END ScopeEndSym: Relocations: diff --git a/test/COFF/Inputs/pdb-hashes-1.yaml b/test/COFF/Inputs/pdb-hashes-1.yaml index ad9e69188f51..158f936100f3 100644 --- a/test/COFF/Inputs/pdb-hashes-1.yaml +++ b/test/COFF/Inputs/pdb-hashes-1.yaml @@ -1,13 +1,13 @@ --- !COFF -header: +header: Machine: IMAGE_FILE_MACHINE_I386 Characteristics: [ ] -sections: +sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 16 - SectionData: 5589E55683EC188B450C8B4D088D55F4C745F8000000008B7508894DF089D18934248945ECE80000000083EC048D4DF4890C248945E8E80000000083C4185E5DC3 - Relocations: + SectionData: 5589E55683EC188B450C8B4D08C745F8000000008B55088D75F4894DF089F18914248945ECE80000000083EC048D4DF4890C248945E8E80000000083C4185E5DC3 + Relocations: - VirtualAddress: 38 SymbolName: '??0Foo@NS@@QAE@H@Z' Type: IMAGE_REL_I386_REL32 @@ -33,25 +33,25 @@ sections: - Name: '.debug$S' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F50000008400000000000000000000004100000000000000080000000000000052000000070000000400000001000000400000000000000008000000000000007F0000000600040000000000030000003E000000000000000800000000000000BD0000000400040000000000040000003D000000000000000800000000000000FA0000000300080000000000F1000000960000002A00471100000000000000000000000041000000000000000000000003100000000000000000006D61696E000D003E1174000000010061726763001200451116000000080000001700000000002A000D003E11001000000100617267760012004511160000000C0000001700000000002A000A003E1109100000000066001200451116000000F4FFFFFF1700000000002A0002004F110000F200000030000000000000000000000041000000000000000300000024000000000000000300000017000000040000003000000005000000F1000000100000000E000811091000004E533A3A466F6F00F40000003000000001000000100165C9E387F88362A8EB2B49539DD5A65500002B00000010019303CF100D518DAF59C31DA01FEF4AFC0000F30000004801000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A312E63707000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D2024657369202454302038202D205E203D2000 - Subsections: + SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F50000008400000000000000000000004100000000000000080000000000000052000000070000000400000001000000400000000000000008000000000000007F0000000600040000000000030000003E000000000000000800000000000000BD0000000400040000000000040000003D000000000000000800000000000000FA0000000300080000000000F1000000960000002A00471100000000000000000000000041000000000000000000000003100000000000000000006D61696E000D003E1174000000010061726763001200451116000000080000001400000000002D000D003E11001000000100617267760012004511160000000C0000001400000000002D000A003E1109100000000066001200451116000000F4FFFFFF1400000000002D0002004F110000F200000030000000000000000000000041000000000000000300000024000000000000000300000014000000040000002D00000005000000F1000000100000000E000811091000004E533A3A466F6F00F40000003000000001000000100165C9E387F88362A8EB2B49539DD5A65500002B0000001001D3AE9D06B0C1F06ABE75A0557053ED6B0000F30000004801000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A312E63707000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D2024657369202454302038202D205E203D2000 + Subsections: - !Symbols - Records: + Records: - Kind: S_COMPILE3 - Compile3Sym: + Compile3Sym: Flags: [ ] Machine: Pentium3 - FrontendMajor: 6 + FrontendMajor: 7 FrontendMinor: 0 FrontendBuild: 0 FrontendQFE: 0 - BackendMajor: 6000 + BackendMajor: 7000 BackendMinor: 0 BackendBuild: 0 BackendQFE: 0 - Version: 'clang version 6.0.0 ' + Version: 'clang version 7.0.0 ' - !FrameData - Frames: + Frames: - CodeSize: 65 FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' LocalSize: 0 @@ -85,9 +85,9 @@ sections: RvaStart: 4 SavedRegsSize: 8 - !Symbols - Records: + Records: - Kind: S_GPROC32_ID - ProcSym: + ProcSym: CodeSize: 65 DbgStart: 0 DbgEnd: 0 @@ -95,72 +95,96 @@ sections: Flags: [ ] DisplayName: main - Kind: S_LOCAL - LocalSym: + LocalSym: Type: 116 Flags: [ IsParameter ] VarName: argc - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 20 + ISectStart: 0 + Range: 45 + Gaps: - Kind: S_LOCAL - LocalSym: + LocalSym: Type: 4096 Flags: [ IsParameter ] VarName: argv - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 12 + Range: + OffsetStart: 20 + ISectStart: 0 + Range: 45 + Gaps: - Kind: S_LOCAL - LocalSym: + LocalSym: Type: 4105 Flags: [ ] VarName: f - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: -12 + Range: + OffsetStart: 20 + ISectStart: 0 + Range: 45 + Gaps: - Kind: S_PROC_ID_END - ScopeEndSym: + ScopeEndSym: - !Lines CodeSize: 65 Flags: [ ] RelocOffset: 0 RelocSegment: 0 - Blocks: + Blocks: - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp' - Lines: + Lines: - Offset: 0 LineStart: 3 IsStatement: false EndDelta: 0 - - Offset: 23 + - Offset: 20 LineStart: 4 IsStatement: false EndDelta: 0 - - Offset: 48 + - Offset: 45 LineStart: 5 IsStatement: false EndDelta: 0 - Columns: + Columns: - !Symbols - Records: + Records: - Kind: S_UDT - UDTSym: + UDTSym: Type: 4105 UDTName: 'NS::Foo' - !FileChecksums - Checksums: + Checksums: - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp' Kind: MD5 Checksum: 65C9E387F88362A8EB2B49539DD5A655 - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj.h' Kind: MD5 - Checksum: 9303CF100D518DAF59C31DA01FEF4AFC + Checksum: D3AE9D06B0C1F06ABE75A0557053ED6B - !StringTable - Strings: + Strings: - 'D:\src\llvmbuild\clang\Debug\x86\obj1.cpp' - 'D:\src\llvmbuild\clang\Debug\x86\obj.h' - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' - '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' - '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = $esi $T0 8 - ^ = ' - Relocations: + Relocations: - VirtualAddress: 68 SymbolName: _main Type: IMAGE_REL_I386_DIR32NB @@ -198,28 +222,28 @@ sections: Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 040000000A000210700400000A8000000E0001120200000074000000001000000E0008107400000000000200011000001200011600000000021000006D61696E00F3F2F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000210041000000A8000000A00011201000000740000001A0009100300000004100000051000000B00010006100000000000001A0003120D15030074000000000058001115030007100000466F6F002A0005150200000208100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E000616091000000A100000020000000E0002160410000007100000466F6F00 - Types: + Types: - Kind: LF_POINTER - Pointer: + Pointer: ReferentType: 1136 Attrs: 32778 - Kind: LF_ARGLIST - ArgList: + ArgList: ArgIndices: [ 116, 4096 ] - Kind: LF_PROCEDURE - Procedure: + Procedure: ReturnType: 116 CallConv: NearC Options: [ None ] ParameterCount: 2 ArgumentList: 4097 - Kind: LF_FUNC_ID - FuncId: + FuncId: ParentScope: 0 FunctionType: 4098 Name: main - Kind: LF_STRUCTURE - Class: + Class: MemberCount: 0 Options: [ None, ForwardReference, HasUniqueName ] FieldList: 0 @@ -229,14 +253,14 @@ sections: VTableShape: 0 Size: 0 - Kind: LF_POINTER - Pointer: + Pointer: ReferentType: 4100 Attrs: 32778 - Kind: LF_ARGLIST - ArgList: + ArgList: ArgIndices: [ 116 ] - Kind: LF_MFUNCTION - MemberFunction: + MemberFunction: ReturnType: 3 ClassType: 4100 ThisType: 4101 @@ -246,21 +270,21 @@ sections: ArgumentList: 4102 ThisPointerAdjustment: 0 - Kind: LF_FIELDLIST - FieldList: + FieldList: - Kind: LF_MEMBER - DataMember: + DataMember: Attrs: 3 Type: 116 FieldOffset: 0 Name: X - Kind: LF_ONEMETHOD - OneMethod: + OneMethod: Type: 4103 Attrs: 3 VFTableOffset: -1 Name: Foo - Kind: LF_STRUCTURE - Class: + Class: MemberCount: 2 Options: [ None, HasUniqueName ] FieldList: 4104 @@ -270,47 +294,47 @@ sections: VTableShape: 0 Size: 4 - Kind: LF_STRING_ID - StringId: + StringId: Id: 0 String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h' - Kind: LF_UDT_SRC_LINE - UdtSourceLine: + UdtSourceLine: UDT: 4105 SourceFile: 4106 LineNumber: 2 - Kind: LF_MFUNC_ID - MemberFuncId: + MemberFuncId: ClassType: 4100 FunctionType: 4103 Name: Foo - Name: '.debug$H' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: C5C93301000000009E56666824DC4B12E25261D4E09E6E9DA0F4EE31FDEC3D2D96287486127C66070B248ED52E421F55074AE5CC2D68AF9F0A3BEF23993968F7FD82CA84BF0439C1A64C9070C6A6ADB0A34D21DAD0FFC3E99E616EF06A14EA74A2420F9062A1FB04917E5975E3A50EABE5E8FE3945468547C19DC681D0BFB3B797DD91CA4D7F1953C314442D5549419E78044E38A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0C0A9021B711ACC4F67008974EBF441031BDD653F6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA0AF6C1846743F43D846BB19517E12E8873BBA90CC41DD1BEAC89CBA8897AC1BA46762E2557A82D894CEAE81AEF8680D723D403D9A4481F0E28683A98 - GlobalHashes: + SectionData: C5C9330100000100800309EE1ED8BB5B5397319F1CC14E2CDF04AA3125BBC50E95CEBA304A2C449323ADA4E788EB7A90B5DECADF1A832BA46632585CDC7606E4B97B86241E5F45B0BCD2406E22465E11A528BEF0A7F589C76079F1186C40C2165091EFEBD5B5446B26FFBFD620CFB362 + GlobalHashes: Version: 0 - HashAlgorithm: 0 - HashValues: - - 9E56666824DC4B12E25261D4E09E6E9DA0F4EE31 - - FDEC3D2D96287486127C66070B248ED52E421F55 - - 074AE5CC2D68AF9F0A3BEF23993968F7FD82CA84 - - BF0439C1A64C9070C6A6ADB0A34D21DAD0FFC3E9 - - 9E616EF06A14EA74A2420F9062A1FB04917E5975 - - E3A50EABE5E8FE3945468547C19DC681D0BFB3B7 - - 97DD91CA4D7F1953C314442D5549419E78044E38 - - A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0 - - C0A9021B711ACC4F67008974EBF441031BDD653F - - 6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA - - 0AF6C1846743F43D846BB19517E12E8873BBA90C - - C41DD1BEAC89CBA8897AC1BA46762E2557A82D89 - - 4CEAE81AEF8680D723D403D9A4481F0E28683A98 + HashAlgorithm: 1 + HashValues: + - 800309EE1ED8BB5B + - 5397319F1CC14E2C + - DF04AA3125BBC50E + - 95CEBA304A2C4493 + - 23ADA4E788EB7A90 + - B5DECADF1A832BA4 + - 6632585CDC7606E4 + - B97B86241E5F45B0 + - BCD2406E22465E11 + - A528BEF0A7F589C7 + - 6079F1186C40C216 + - 5091EFEBD5B5446B + - 26FFBFD620CFB362 - Name: '.debug$S' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 04000000F500000064000000000000000000000020000000000000000400000000000000520000000600000004000000010000001F0000000000000004000000000000007F0000000500040000000000030000001D000000000000000400000000000000BD0000000300040000000000F10000007B000000320047110000000000000000000000002000000000000000000000000C100000000000000000004E533A3A466F6F3A3A466F6F000D003E1105100000010074686973001200451116000000FCFFFFFF0F000000000011000A003E1174000000010078001200451116000000080000000F0000000000110002004F1100F2000000200000000000000000000000200000001800000001000000140000000000000003000000 - Subsections: + Subsections: - !FrameData - Frames: + Frames: - CodeSize: 32 FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' LocalSize: 0 @@ -336,9 +360,9 @@ sections: RvaStart: 3 SavedRegsSize: 4 - !Symbols - Records: + Records: - Kind: S_GPROC32_ID - ProcSym: + ProcSym: CodeSize: 32 DbgStart: 0 DbgEnd: 0 @@ -346,35 +370,51 @@ sections: Flags: [ ] DisplayName: 'NS::Foo::Foo' - Kind: S_LOCAL - LocalSym: + LocalSym: Type: 4101 Flags: [ IsParameter ] VarName: this - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: -4 + Range: + OffsetStart: 15 + ISectStart: 0 + Range: 17 + Gaps: - Kind: S_LOCAL - LocalSym: + LocalSym: Type: 116 Flags: [ IsParameter ] VarName: x - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 15 + ISectStart: 0 + Range: 17 + Gaps: - Kind: S_PROC_ID_END - ScopeEndSym: + ScopeEndSym: - !Lines CodeSize: 32 Flags: [ ] RelocOffset: 0 RelocSegment: 0 - Blocks: + Blocks: - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj.h' - Lines: + Lines: - Offset: 0 LineStart: 3 IsStatement: false EndDelta: 0 - Columns: - Relocations: + Columns: + Relocations: - VirtualAddress: 12 SymbolName: '??0Foo@NS@@QAE@H@Z' Type: IMAGE_REL_I386_DIR32NB @@ -402,18 +442,18 @@ sections: - VirtualAddress: 256 SymbolName: '??0Foo@NS@@QAE@H@Z' Type: IMAGE_REL_I386_SECTION -symbols: +symbols: - Name: .text Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 65 NumberOfRelocations: 2 NumberOfLinenumbers: 0 - CheckSum: 4176946275 + CheckSum: 1827148029 Number: 1 - Name: .data Value: 0 @@ -421,7 +461,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 0 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -433,7 +473,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 0 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -445,7 +485,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 32 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -464,7 +504,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 48 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -476,11 +516,11 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 832 NumberOfRelocations: 11 NumberOfLinenumbers: 0 - CheckSum: 4106171226 + CheckSum: 372945565 Number: 6 - Name: '.debug$S' Value: 0 @@ -488,7 +528,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 284 NumberOfRelocations: 9 NumberOfLinenumbers: 0 @@ -501,7 +541,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 316 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -513,11 +553,11 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: - Length: 268 + SectionDefinition: + Length: 112 NumberOfRelocations: 0 NumberOfLinenumbers: 0 - CheckSum: 3965031229 + CheckSum: 1535721080 Number: 8 - Name: '@feat.00' Value: 1 diff --git a/test/COFF/Inputs/pdb-hashes-2-missing.yaml b/test/COFF/Inputs/pdb-hashes-2-missing.yaml index 74f3a62fcc23..41cba5065dea 100644 --- a/test/COFF/Inputs/pdb-hashes-2-missing.yaml +++ b/test/COFF/Inputs/pdb-hashes-2-missing.yaml @@ -1,8 +1,8 @@ --- !COFF -header: +header: Machine: IMAGE_FILE_MACHINE_I386 Characteristics: [ ] -sections: +sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 16 @@ -22,25 +22,25 @@ sections: - Name: '.debug$S' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000 - Subsections: + SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000 + Subsections: - !Symbols - Records: + Records: - Kind: S_COMPILE3 - Compile3Sym: + Compile3Sym: Flags: [ ] Machine: Pentium3 - FrontendMajor: 6 + FrontendMajor: 7 FrontendMinor: 0 FrontendBuild: 0 FrontendQFE: 0 - BackendMajor: 6000 + BackendMajor: 7000 BackendMinor: 0 BackendBuild: 0 BackendQFE: 0 - Version: 'clang version 6.0.0 ' + Version: 'clang version 7.0.0 ' - !FrameData - Frames: + Frames: - CodeSize: 25 FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' LocalSize: 0 @@ -66,9 +66,9 @@ sections: RvaStart: 3 SavedRegsSize: 4 - !Symbols - Records: + Records: - Kind: S_GPROC32_ID - ProcSym: + ProcSym: CodeSize: 25 DbgStart: 0 DbgEnd: 0 @@ -76,22 +76,30 @@ sections: Flags: [ ] DisplayName: 'NS::func' - Kind: S_LOCAL - LocalSym: + LocalSym: Type: 4099 Flags: [ IsParameter ] VarName: f - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 7 + ISectStart: 0 + Range: 18 + Gaps: - Kind: S_PROC_ID_END - ScopeEndSym: + ScopeEndSym: - !Lines CodeSize: 25 Flags: [ ] RelocOffset: 0 RelocSegment: 0 - Blocks: + Blocks: - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp' - Lines: + Lines: - Offset: 0 LineStart: 3 IsStatement: false @@ -100,26 +108,26 @@ sections: LineStart: 4 IsStatement: false EndDelta: 0 - Columns: + Columns: - !Symbols - Records: + Records: - Kind: S_UDT - UDTSym: + UDTSym: Type: 4106 UDTName: 'NS::Foo' - !FileChecksums - Checksums: + Checksums: - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp' Kind: MD5 Checksum: 59DFAC75D18675AED1AD169FE316317E - !StringTable - Strings: + Strings: - 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp' - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' - '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' - '' - Relocations: + Relocations: - VirtualAddress: 68 SymbolName: '?func@NS@@YAHABUFoo@1@@Z' Type: IMAGE_REL_I386_DIR32NB @@ -145,13 +153,13 @@ sections: Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 040000000A000516000000004E5300F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000110011000000100F2F10A000210021000002A8000000A00011201000000031000000E0008107400000000000100041000000A000210011000000A8000000A00011201000000740000001A0009100300000001100000061000000B00010007100000000000001A0003120D15030074000000000058001115030008100000466F6F002A0005150200000209100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E0006160A1000000B1000000200000012000116001000000510000066756E6300F3F2F1 - Types: + Types: - Kind: LF_STRING_ID - StringId: + StringId: Id: 0 String: NS - Kind: LF_STRUCTURE - Class: + Class: MemberCount: 0 Options: [ None, ForwardReference, HasUniqueName ] FieldList: 0 @@ -161,32 +169,32 @@ sections: VTableShape: 0 Size: 0 - Kind: LF_MODIFIER - Modifier: + Modifier: ModifiedType: 4097 Modifiers: [ None, Const ] - Kind: LF_POINTER - Pointer: + Pointer: ReferentType: 4098 Attrs: 32810 - Kind: LF_ARGLIST - ArgList: + ArgList: ArgIndices: [ 4099 ] - Kind: LF_PROCEDURE - Procedure: + Procedure: ReturnType: 116 CallConv: NearC Options: [ None ] ParameterCount: 1 ArgumentList: 4100 - Kind: LF_POINTER - Pointer: + Pointer: ReferentType: 4097 Attrs: 32778 - Kind: LF_ARGLIST - ArgList: + ArgList: ArgIndices: [ 116 ] - Kind: LF_MFUNCTION - MemberFunction: + MemberFunction: ReturnType: 3 ClassType: 4097 ThisType: 4102 @@ -196,21 +204,21 @@ sections: ArgumentList: 4103 ThisPointerAdjustment: 0 - Kind: LF_FIELDLIST - FieldList: + FieldList: - Kind: LF_MEMBER - DataMember: + DataMember: Attrs: 3 Type: 116 FieldOffset: 0 Name: X - Kind: LF_ONEMETHOD - OneMethod: + OneMethod: Type: 4104 Attrs: 3 VFTableOffset: -1 Name: Foo - Kind: LF_STRUCTURE - Class: + Class: MemberCount: 2 Options: [ None, HasUniqueName ] FieldList: 4105 @@ -220,27 +228,27 @@ sections: VTableShape: 0 Size: 4 - Kind: LF_STRING_ID - StringId: + StringId: Id: 0 String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h' - Kind: LF_UDT_SRC_LINE - UdtSourceLine: + UdtSourceLine: UDT: 4106 SourceFile: 4107 LineNumber: 2 - Kind: LF_FUNC_ID - FuncId: + FuncId: ParentScope: 4096 FunctionType: 4101 Name: func -symbols: +symbols: - Name: .text Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 25 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -252,7 +260,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 0 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -264,7 +272,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 0 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -276,7 +284,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 48 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -288,11 +296,11 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 584 NumberOfRelocations: 7 NumberOfLinenumbers: 0 - CheckSum: 2847177244 + CheckSum: 917356735 Number: 5 - Name: '.debug$T' Value: 0 @@ -300,7 +308,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 320 NumberOfRelocations: 0 NumberOfLinenumbers: 0 diff --git a/test/COFF/Inputs/pdb-hashes-2.yaml b/test/COFF/Inputs/pdb-hashes-2.yaml index 63e9fc02ad5a..51ea512f1aa4 100644 --- a/test/COFF/Inputs/pdb-hashes-2.yaml +++ b/test/COFF/Inputs/pdb-hashes-2.yaml @@ -1,8 +1,8 @@ --- !COFF -header: +header: Machine: IMAGE_FILE_MACHINE_I386 Characteristics: [ ] -sections: +sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 16 @@ -22,25 +22,25 @@ sections: - Name: '.debug$S' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: 04000000F10000002F0000002D003C1101000000070006000000000000007017000000000000636C616E672076657273696F6E20362E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000 - Subsections: + SectionData: 04000000F10000002F0000002D003C110100000007000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F5000000640000000000000000000000190000000000000004000000000000002B000000040000000400000001000000180000000000000004000000000000005800000003000400000000000300000016000000000000000400000000000000960000000100040000000000F1000000540000002E0047110000000000000000000000001900000000000000000000000D100000000000000000004E533A3A66756E63000A003E110310000001006600120045111600000008000000070000000000120002004F11F20000002800000000000000000000001900000000000000020000001C00000000000000030000000700000004000000F1000000100000000E0008110A1000004E533A3A466F6F00F40000001800000001000000100159DFAC75D18675AED1AD169FE316317E0000F3000000D400000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A322E63707000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2000245430202E7261536561726368203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200024543020246562702034202B203D202465697020245430205E203D2024657370202454302034202B203D2024656270202454302034202D205E203D200000 + Subsections: - !Symbols - Records: + Records: - Kind: S_COMPILE3 - Compile3Sym: + Compile3Sym: Flags: [ ] Machine: Pentium3 - FrontendMajor: 6 + FrontendMajor: 7 FrontendMinor: 0 FrontendBuild: 0 FrontendQFE: 0 - BackendMajor: 6000 + BackendMajor: 7000 BackendMinor: 0 BackendBuild: 0 BackendQFE: 0 - Version: 'clang version 6.0.0 ' + Version: 'clang version 7.0.0 ' - !FrameData - Frames: + Frames: - CodeSize: 25 FrameFunc: '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' LocalSize: 0 @@ -66,9 +66,9 @@ sections: RvaStart: 3 SavedRegsSize: 4 - !Symbols - Records: + Records: - Kind: S_GPROC32_ID - ProcSym: + ProcSym: CodeSize: 25 DbgStart: 0 DbgEnd: 0 @@ -76,22 +76,30 @@ sections: Flags: [ ] DisplayName: 'NS::func' - Kind: S_LOCAL - LocalSym: + LocalSym: Type: 4099 Flags: [ IsParameter ] VarName: f - Kind: S_DEFRANGE_REGISTER_REL - DefRangeRegisterRelSym: + DefRangeRegisterRelSym: + Register: 22 + Flags: 0 + BasePointerOffset: 8 + Range: + OffsetStart: 7 + ISectStart: 0 + Range: 18 + Gaps: - Kind: S_PROC_ID_END - ScopeEndSym: + ScopeEndSym: - !Lines CodeSize: 25 Flags: [ ] RelocOffset: 0 RelocSegment: 0 - Blocks: + Blocks: - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp' - Lines: + Lines: - Offset: 0 LineStart: 3 IsStatement: false @@ -100,26 +108,26 @@ sections: LineStart: 4 IsStatement: false EndDelta: 0 - Columns: + Columns: - !Symbols - Records: + Records: - Kind: S_UDT - UDTSym: + UDTSym: Type: 4106 UDTName: 'NS::Foo' - !FileChecksums - Checksums: + Checksums: - FileName: 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp' Kind: MD5 Checksum: 59DFAC75D18675AED1AD169FE316317E - !StringTable - Strings: + Strings: - 'D:\src\llvmbuild\clang\Debug\x86\obj2.cpp' - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = ' - '$T0 .raSearch = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' - '$T0 $ebp 4 + = $eip $T0 ^ = $esp $T0 4 + = $ebp $T0 4 - ^ = ' - '' - Relocations: + Relocations: - VirtualAddress: 68 SymbolName: '?func@NS@@YAHABUFoo@1@@Z' Type: IMAGE_REL_I386_DIR32NB @@ -145,13 +153,13 @@ sections: Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 SectionData: 040000000A000516000000004E5300F12A0005150000800200000000000000000000000000004E533A3A466F6F002E3F4155466F6F404E53404000F10A000110011000000100F2F10A000210021000002A8000000A00011201000000031000000E0008107400000000000100041000000A000210011000000A8000000A00011201000000740000001A0009100300000001100000061000000B00010007100000000000001A0003120D15030074000000000058001115030008100000466F6F002A0005150200000209100000000000000000000004004E533A3A466F6F002E3F4155466F6F404E53404000F12E00051600000000443A5C7372635C6C6C766D6275696C645C636C616E675C44656275675C7838365C6F626A2E6800F10E0006160A1000000B1000000200000012000116001000000510000066756E6300F3F2F1 - Types: + Types: - Kind: LF_STRING_ID - StringId: + StringId: Id: 0 String: NS - Kind: LF_STRUCTURE - Class: + Class: MemberCount: 0 Options: [ None, ForwardReference, HasUniqueName ] FieldList: 0 @@ -161,32 +169,32 @@ sections: VTableShape: 0 Size: 0 - Kind: LF_MODIFIER - Modifier: + Modifier: ModifiedType: 4097 Modifiers: [ None, Const ] - Kind: LF_POINTER - Pointer: + Pointer: ReferentType: 4098 Attrs: 32810 - Kind: LF_ARGLIST - ArgList: + ArgList: ArgIndices: [ 4099 ] - Kind: LF_PROCEDURE - Procedure: + Procedure: ReturnType: 116 CallConv: NearC Options: [ None ] ParameterCount: 1 ArgumentList: 4100 - Kind: LF_POINTER - Pointer: + Pointer: ReferentType: 4097 Attrs: 32778 - Kind: LF_ARGLIST - ArgList: + ArgList: ArgIndices: [ 116 ] - Kind: LF_MFUNCTION - MemberFunction: + MemberFunction: ReturnType: 3 ClassType: 4097 ThisType: 4102 @@ -196,21 +204,21 @@ sections: ArgumentList: 4103 ThisPointerAdjustment: 0 - Kind: LF_FIELDLIST - FieldList: + FieldList: - Kind: LF_MEMBER - DataMember: + DataMember: Attrs: 3 Type: 116 FieldOffset: 0 Name: X - Kind: LF_ONEMETHOD - OneMethod: + OneMethod: Type: 4104 Attrs: 3 VFTableOffset: -1 Name: Foo - Kind: LF_STRUCTURE - Class: + Class: MemberCount: 2 Options: [ None, HasUniqueName ] FieldList: 4105 @@ -220,49 +228,49 @@ sections: VTableShape: 0 Size: 4 - Kind: LF_STRING_ID - StringId: + StringId: Id: 0 String: 'D:\src\llvmbuild\clang\Debug\x86\obj.h' - Kind: LF_UDT_SRC_LINE - UdtSourceLine: + UdtSourceLine: UDT: 4106 SourceFile: 4107 LineNumber: 2 - Kind: LF_FUNC_ID - FuncId: + FuncId: ParentScope: 4096 FunctionType: 4101 Name: func - Name: '.debug$H' Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: C5C9330100000000EC145CD76AEFE74E78880D531132B3BB8FFACEF79E616EF06A14EA74A2420F9062A1FB04917E59759949E334BA18509ED692F3C65CE242D8450EBC78B81B63AF8316DC324562EB9F0D4A0D708E8A25C263DB05943C19B84A36719E1E414DDA3EDBDF005322238D70F9058EEDC5C50EF11BC849618B51FD89E3A50EABE5E8FE3945468547C19DC681D0BFB3B797DD91CA4D7F1953C314442D5549419E78044E38A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0C0A9021B711ACC4F67008974EBF441031BDD653F6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA0AF6C1846743F43D846BB19517E12E8873BBA90CC41DD1BEAC89CBA8897AC1BA46762E2557A82D89DCBC783AF285D9DBB672F67A81E36906B2038B57 - GlobalHashes: + SectionData: C5C93301000001004A061540B751965F23ADA4E788EB7A9032673B3BABE3CA5356B1521BDAE4BEA70661C95750D0206E896FB09488EE8E1BB5DECADF1A832BA46632585CDC7606E4B97B86241E5F45B0BCD2406E22465E11A528BEF0A7F589C76079F1186C40C2165091EFEBD5B5446B5AAD8721C21DF3E6 + GlobalHashes: Version: 0 - HashAlgorithm: 0 - HashValues: - - EC145CD76AEFE74E78880D531132B3BB8FFACEF7 - - 9E616EF06A14EA74A2420F9062A1FB04917E5975 - - 9949E334BA18509ED692F3C65CE242D8450EBC78 - - B81B63AF8316DC324562EB9F0D4A0D708E8A25C2 - - 63DB05943C19B84A36719E1E414DDA3EDBDF0053 - - 22238D70F9058EEDC5C50EF11BC849618B51FD89 - - E3A50EABE5E8FE3945468547C19DC681D0BFB3B7 - - 97DD91CA4D7F1953C314442D5549419E78044E38 - - A0BF16BFFAA5EE9C0103E7DBFE9941E63379C0B0 - - C0A9021B711ACC4F67008974EBF441031BDD653F - - 6935DFF3112C6A5346EF2AC94B9B7EB56EF55CFA - - 0AF6C1846743F43D846BB19517E12E8873BBA90C - - C41DD1BEAC89CBA8897AC1BA46762E2557A82D89 - - DCBC783AF285D9DBB672F67A81E36906B2038B57 -symbols: + HashAlgorithm: 1 + HashValues: + - 4A061540B751965F + - 23ADA4E788EB7A90 + - 32673B3BABE3CA53 + - 56B1521BDAE4BEA7 + - 0661C95750D0206E + - 896FB09488EE8E1B + - B5DECADF1A832BA4 + - 6632585CDC7606E4 + - B97B86241E5F45B0 + - BCD2406E22465E11 + - A528BEF0A7F589C7 + - 6079F1186C40C216 + - 5091EFEBD5B5446B + - 5AAD8721C21DF3E6 +symbols: - Name: .text Value: 0 SectionNumber: 1 SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 25 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -274,7 +282,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 0 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -286,7 +294,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 0 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -298,7 +306,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 48 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -310,11 +318,11 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 584 NumberOfRelocations: 7 NumberOfLinenumbers: 0 - CheckSum: 2847177244 + CheckSum: 917356735 Number: 5 - Name: '.debug$T' Value: 0 @@ -322,7 +330,7 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: + SectionDefinition: Length: 320 NumberOfRelocations: 0 NumberOfLinenumbers: 0 @@ -334,11 +342,11 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: - Length: 288 + SectionDefinition: + Length: 120 NumberOfRelocations: 0 NumberOfLinenumbers: 0 - CheckSum: 2348181452 + CheckSum: 358820662 Number: 7 - Name: '@feat.00' Value: 1 diff --git a/test/COFF/Inputs/pdb-scopes-a.yaml b/test/COFF/Inputs/pdb-scopes-a.yaml index e422a6241f27..0fc41723bdc2 100644 --- a/test/COFF/Inputs/pdb-scopes-a.yaml +++ b/test/COFF/Inputs/pdb-scopes-a.yaml @@ -53,7 +53,7 @@ sections: RegRelativeSym: Offset: 8 Type: 116 - Register: RSP + Register: CVRegRSP VarName: x - Kind: S_PROC_ID_END ScopeEndSym: @@ -93,7 +93,7 @@ sections: RegRelativeSym: Offset: 64 Type: 116 - Register: RSP + Register: CVRegRSP VarName: argc - Kind: S_BLOCK32 BlockSym: @@ -104,7 +104,7 @@ sections: RegRelativeSym: Offset: 32 Type: 116 - Register: RSP + Register: CVRegRSP VarName: x - Kind: S_END ScopeEndSym: @@ -117,7 +117,7 @@ sections: RegRelativeSym: Offset: 36 Type: 116 - Register: RSP + Register: CVRegRSP VarName: y - Kind: S_END ScopeEndSym: diff --git a/test/COFF/Inputs/pdb-scopes-b.yaml b/test/COFF/Inputs/pdb-scopes-b.yaml index b1c602143c3f..c0ee98b0d64c 100644 --- a/test/COFF/Inputs/pdb-scopes-b.yaml +++ b/test/COFF/Inputs/pdb-scopes-b.yaml @@ -53,7 +53,7 @@ sections: RegRelativeSym: Offset: 64 Type: 116 - Register: RSP + Register: CVRegRSP VarName: x - Kind: S_BLOCK32 BlockSym: @@ -64,7 +64,7 @@ sections: RegRelativeSym: Offset: 32 Type: 116 - Register: RSP + Register: CVRegRSP VarName: y - Kind: S_END ScopeEndSym: @@ -77,7 +77,7 @@ sections: RegRelativeSym: Offset: 36 Type: 116 - Register: RSP + Register: CVRegRSP VarName: w - Kind: S_END ScopeEndSym: diff --git a/test/COFF/Inputs/pdb-type-server-simple-a.yaml b/test/COFF/Inputs/pdb-type-server-simple-a.yaml index 78c68168127b..8425c4f63b70 100644 --- a/test/COFF/Inputs/pdb-type-server-simple-a.yaml +++ b/test/COFF/Inputs/pdb-type-server-simple-a.yaml @@ -53,7 +53,7 @@ sections: RegRelativeSym: Offset: 32 Type: 4102 - Register: RSP + Register: CVRegRSP VarName: f - Kind: S_PROC_ID_END ScopeEndSym: diff --git a/test/COFF/Inputs/pdb-type-server-simple-b.yaml b/test/COFF/Inputs/pdb-type-server-simple-b.yaml index 56e97d530894..3b511cb0d861 100644 --- a/test/COFF/Inputs/pdb-type-server-simple-b.yaml +++ b/test/COFF/Inputs/pdb-type-server-simple-b.yaml @@ -53,7 +53,7 @@ sections: RegRelativeSym: Offset: 8 Type: 4097 - Register: RSP + Register: CVRegRSP VarName: p - Kind: S_PROC_ID_END ScopeEndSym: diff --git a/test/COFF/Inputs/pdb_lines_1_relative.yaml b/test/COFF/Inputs/pdb_lines_1_relative.yaml new file mode 100644 index 000000000000..947de419d6b8 --- /dev/null +++ b/test/COFF/Inputs/pdb_lines_1_relative.yaml @@ -0,0 +1,401 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC28C744242400000000E800000000B82A0000004883C428C3 + Relocations: + - VirtualAddress: 13 + SymbolName: foo + Type: IMAGE_REL_AMD64_REL32 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 4883EC28E800000000904883C428C3 + Relocations: + - VirtualAddress: 5 + SymbolName: bar + Type: IMAGE_REL_AMD64_REL32 + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 04000000F10000002F0000002D003C1100000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F1000000300000002A0047110000000000000000000000001B000000000000000000000002100000000000000000006D61696E0002004F11F20000003000000000000000000000001B00000000000000030000002400000000000000020000000C000000030000001100000004000000F400000030000000010000001001EA6429BCE282CCF3F0E3CD93B216EB410000110000001001061EB73ABB642532857A4F1D9CBAC3230000F30000001C000000002E5C7064625F6C696E65735F312E63002E5C666F6F2E6800000000 + Subsections: + - !Symbols + Records: + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ ] + Machine: X64 + FrontendMajor: 7 + FrontendMinor: 0 + FrontendBuild: 0 + FrontendQFE: 0 + BackendMajor: 7000 + BackendMinor: 0 + BackendBuild: 0 + BackendQFE: 0 + Version: 'clang version 7.0.0 ' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 27 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4098 + Flags: [ ] + DisplayName: main + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 27 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: '.\pdb_lines_1.c' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: false + EndDelta: 0 + - Offset: 12 + LineStart: 3 + IsStatement: false + EndDelta: 0 + - Offset: 17 + LineStart: 4 + IsStatement: false + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: '.\pdb_lines_1.c' + Kind: MD5 + Checksum: EA6429BCE282CCF3F0E3CD93B216EB41 + - FileName: '.\foo.h' + Kind: MD5 + Checksum: 061EB73ABB642532857A4F1D9CBAC323 + - !StringTable + Strings: + - '.\pdb_lines_1.c' + - '.\foo.h' + - '' + - '' + - '' + Relocations: + - VirtualAddress: 100 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 124 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 128 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 0400000006000112000000000E0008107400000000000000001000001200011600000000011000006D61696E00F3F2F10E0008100300000000000000001000000E0001160000000003100000666F6F00 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: main + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4099 + Name: foo + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000001B00000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: main + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: .xdata + Type: IMAGE_REL_AMD64_ADDR32NB + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0104010004420000' + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 04000000F10000002F000000290047110000000000000000000000000F00000000000000000000000410000000000000000000666F6F0002004F1100F20000003000000000000000000000000F000000180000000300000024000000000000000200000004000000030000000900000004000000 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 15 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4100 + Flags: [ ] + DisplayName: foo + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 15 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: '.\foo.h' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: false + EndDelta: 0 + - Offset: 4 + LineStart: 3 + IsStatement: false + EndDelta: 0 + - Offset: 9 + LineStart: 4 + IsStatement: false + EndDelta: 0 + Columns: + Relocations: + - VirtualAddress: 44 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 68 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 72 + SymbolName: foo + Type: IMAGE_REL_AMD64_SECTION + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000000F00000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: foo + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: foo + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: .xdata + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 27 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 3051916600 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .xdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 4 + - Name: .text + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 15 + NumberOfRelocations: 1 + NumberOfLinenumbers: 0 + CheckSum: 236440503 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ANY + - Name: foo + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .xdata + Value: 0 + SectionNumber: 10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 264583633 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: .drectve + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 48 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 149686238 + Number: 6 + - Name: '.debug$S' + Value: 0 + SectionNumber: 7 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 264 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 2204933783 + Number: 7 + - Name: '.debug$S' + Value: 0 + SectionNumber: 11 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 116 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 2691661839 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: '.debug$T' + Value: 0 + SectionNumber: 8 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 80 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3541780432 + Number: 8 + - Name: .pdata + Value: 0 + SectionNumber: 9 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 567356797 + Number: 9 + - Name: .pdata + Value: 0 + SectionNumber: 12 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 3642757804 + Number: 5 + Selection: IMAGE_COMDAT_SELECT_ASSOCIATIVE + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: bar + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/Inputs/pdb_lines_2_relative.yaml b/test/COFF/Inputs/pdb_lines_2_relative.yaml new file mode 100644 index 000000000000..1b051d82d9a4 --- /dev/null +++ b/test/COFF/Inputs/pdb_lines_2_relative.yaml @@ -0,0 +1,190 @@ +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 + - Name: .data + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .bss + Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 4 + SectionData: '' + - Name: .drectve + Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] + Alignment: 1 + SectionData: 202F44454641554C544C49423A6C6962636D742E6C6962202F44454641554C544C49423A6F6C646E616D65732E6C6962 + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 04000000F10000002F0000002D003C1100000000D0000700000000000000581B000000000000636C616E672076657273696F6E20372E302E30200000F10000002F0000002900471100000000000000000000000001000000000000000000000002100000000000000000006261720002004F1100F2000000200000000000000000000000010000000000000001000000140000000000000002000000F400000018000000010000001001DF91CB3A2B8D917486574BB50CAC4CC70000F300000014000000002E5C7064625F6C696E65735F322E6300000000 + Subsections: + - !Symbols + Records: + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ ] + Machine: X64 + FrontendMajor: 7 + FrontendMinor: 0 + FrontendBuild: 0 + FrontendQFE: 0 + BackendMajor: 7000 + BackendMinor: 0 + BackendBuild: 0 + BackendQFE: 0 + Version: 'clang version 7.0.0 ' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 1 + DbgStart: 0 + DbgEnd: 0 + FunctionType: 4098 + Flags: [ ] + DisplayName: bar + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 1 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: '.\pdb_lines_2.c' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: false + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: '.\pdb_lines_2.c' + Kind: MD5 + Checksum: DF91CB3A2B8D917486574BB50CAC4CC7 + - !StringTable + Strings: + - '.\pdb_lines_2.c' + - '' + - '' + - '' + Relocations: + - VirtualAddress: 100 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 124 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 128 + SymbolName: bar + Type: IMAGE_REL_AMD64_SECTION + - Name: '.debug$T' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 0400000006000112000000000E0008100300000000000000001000000E000116000000000110000062617200 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: bar +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 40735498 + Number: 1 + - Name: .data + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 2 + - Name: .bss + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 0 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + - Name: .drectve + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 48 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 149686238 + Number: 4 + - Name: '.debug$S' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 216 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 2383431754 + Number: 5 + - Name: '.debug$T' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 44 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 179171995 + Number: 6 + - Name: bar + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/arm64-branch-range.test b/test/COFF/arm64-branch-range.test new file mode 100644 index 000000000000..0b581e9c464d --- /dev/null +++ b/test/COFF/arm64-branch-range.test @@ -0,0 +1,16 @@ +// REQUIRES: aarch64 + +// RUN: echo -e '.globl _start\n _start:\n bl too_far26\n' > %t.main26.s +// RUN: echo -e '.globl _start\n _start:\n b.ne too_far19\n' > %t.main19.s +// RUN: echo -e '.globl _start\n _start:\n tbz x0, #0, too_far14\n' > %t.main14.s + +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main26.s -o %t.main26.obj +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main19.s -o %t.main19.obj +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %t.main14.s -o %t.main14.obj +// RUN: llvm-mc -filetype=obj -triple=aarch64-windows %S/Inputs/far-arm64-abs.s -o %t.far.obj + +// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main26.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s +// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main19.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s +// RUN: not lld-link -base:0x10000 -entry:_start -subsystem:console %t.main14.obj %t.far.obj -out:%t.exe 2>&1 | FileCheck %s + +// CHECK: relocation out of range diff --git a/test/COFF/arm64-relocs-imports.test b/test/COFF/arm64-relocs-imports.test index 57590dcf733a..c7b8b7c28466 100644 --- a/test/COFF/arm64-relocs-imports.test +++ b/test/COFF/arm64-relocs-imports.test @@ -38,43 +38,57 @@ # BEFORE: 74: 00 00 00 00 <unknown> # BEFORE: 78: 01 00 00 00 <unknown> # BEFORE: 7c: 01 00 00 00 <unknown> +# BEFORE: 80: 00 00 00 91 add x0, x0, #0 +# BEFORE: 84: 00 00 40 91 add x0, x0, #0, lsl #12 +# BEFORE: 88: 00 00 40 f9 ldr x0, [x0] +# BEFORE: 8c: 01 00 00 00 <unknown> +# BEFORE: 90: 20 1a 09 30 adr x0, #74565 +# BEFORE: 94: 01 00 00 54 b.ne #0 +# BEFORE: 98: 00 00 00 36 tbz w0, #0, #0 # AFTER: Disassembly of section .text: -# AFTER: 140002000: fe 0f 1f f8 str x30, [sp, #-16]! -# AFTER: 140002004: e0 ff ff f0 adrp x0, #-4096 -# AFTER: 140002008: 00 18 00 91 add x0, x0, #6 -# AFTER: 14000200c: 1d 00 00 94 bl #116 -# AFTER: 140002010: 00 21 40 39 ldrb w0, [x8, #8] -# AFTER: 140002014: 00 11 40 79 ldrh w0, [x8, #8] -# AFTER: 140002018: 00 09 40 b9 ldr w0, [x8, #8] -# AFTER: 14000201c: 00 05 40 f9 ldr x0, [x8, #8] -# AFTER: 140002020: 00 21 00 39 strb w0, [x8, #8] -# AFTER: 140002024: 00 11 00 79 strh w0, [x8, #8] -# AFTER: 140002028: 00 09 00 b9 str w0, [x8, #8] -# AFTER: 14000202c: 00 05 00 f9 str x0, [x8, #8] -# AFTER: 140002030: 00 41 40 3d ldr b0, [x8, #16] -# AFTER: 140002034: 00 21 40 7d ldr h0, [x8, #16] -# AFTER: 140002038: 00 11 40 bd ldr s0, [x8, #16] -# AFTER: 14000203c: 00 09 40 fd ldr d0, [x8, #16] -# AFTER: 140002040: 00 05 c0 3d ldr q0, [x8, #16] -# AFTER: 140002044: 00 41 00 3d str b0, [x8, #16] -# AFTER: 140002048: 00 21 00 7d str h0, [x8, #16] -# AFTER: 14000204c: 00 11 00 bd str s0, [x8, #16] -# AFTER: 140002050: 00 09 00 fd str d0, [x8, #16] -# AFTER: 140002054: 00 05 80 3d str q0, [x8, #16] -# AFTER: 140002058: 00 09 40 f9 ldr x0, [x8, #16] -# AFTER: 14000205c: 00 00 00 b0 adrp x0, #4096 -# AFTER: 140002060: 00 fc 47 f9 ldr x0, [x0, #4088] -# AFTER: 140002064: e0 03 1f 2a mov w0, wzr -# AFTER: 140002068: fe 07 41 f8 ldr x30, [sp], #16 -# AFTER: 14000206c: c0 03 5f d6 ret -# AFTER: 140002070: 10 10 00 40 <unknown> -# AFTER: 140002074: 01 00 00 00 <unknown> -# AFTER: 140002078: 09 10 00 00 <unknown> -# AFTER: 14000207c: 09 00 00 00 <unknown> -# AFTER: 140002080: 10 00 00 b0 adrp x16, #4096 -# AFTER: 140002084: 10 1e 40 f9 ldr x16, [x16, #56] -# AFTER: 140002088: 00 02 1f d6 br x16 +# AFTER: 140001000: fe 0f 1f f8 str x30, [sp, #-16]! +# AFTER: 140001004: 00 00 00 b0 adrp x0, #4096 +# AFTER: 140001008: 00 18 00 91 add x0, x0, #6 +# AFTER: 14000100c: 24 00 00 94 bl #144 +# AFTER: 140001010: 00 21 40 39 ldrb w0, [x8, #8] +# AFTER: 140001014: 00 11 40 79 ldrh w0, [x8, #8] +# AFTER: 140001018: 00 09 40 b9 ldr w0, [x8, #8] +# AFTER: 14000101c: 00 05 40 f9 ldr x0, [x8, #8] +# AFTER: 140001020: 00 21 00 39 strb w0, [x8, #8] +# AFTER: 140001024: 00 11 00 79 strh w0, [x8, #8] +# AFTER: 140001028: 00 09 00 b9 str w0, [x8, #8] +# AFTER: 14000102c: 00 05 00 f9 str x0, [x8, #8] +# AFTER: 140001030: 00 41 40 3d ldr b0, [x8, #16] +# AFTER: 140001034: 00 21 40 7d ldr h0, [x8, #16] +# AFTER: 140001038: 00 11 40 bd ldr s0, [x8, #16] +# AFTER: 14000103c: 00 09 40 fd ldr d0, [x8, #16] +# AFTER: 140001040: 00 05 c0 3d ldr q0, [x8, #16] +# AFTER: 140001044: 00 41 00 3d str b0, [x8, #16] +# AFTER: 140001048: 00 21 00 7d str h0, [x8, #16] +# AFTER: 14000104c: 00 11 00 bd str s0, [x8, #16] +# AFTER: 140001050: 00 09 00 fd str d0, [x8, #16] +# AFTER: 140001054: 00 05 80 3d str q0, [x8, #16] +# AFTER: 140001058: 00 09 40 f9 ldr x0, [x8, #16] +# AFTER: 14000105c: 00 00 00 f0 adrp x0, #12288 +# AFTER: 140001060: 00 fc 47 f9 ldr x0, [x0, #4088] +# AFTER: 140001064: e0 03 1f 2a mov w0, wzr +# AFTER: 140001068: fe 07 41 f8 ldr x30, [sp], #16 +# AFTER: 14000106c: c0 03 5f d6 ret +# AFTER: 140001070: 10 20 00 40 <unknown> +# AFTER: 140001074: 01 00 00 00 <unknown> +# AFTER: 140001078: 09 20 00 00 <unknown> +# AFTER: 14000107c: 09 00 00 00 <unknown> +# AFTER: 140001080: 00 20 0e 91 add x0, x0, #904 +# AFTER: 140001084: 00 04 40 91 add x0, x0, #1, lsl #12 +# AFTER: 140001088: 00 c4 41 f9 ldr x0, [x0, #904] +# AFTER: 14000108c: 03 00 00 00 <unknown> +# AFTER: 140001090: e0 95 09 30 adr x0, #78525 +# AFTER: 140001094: 41 00 00 54 b.ne #8 +# AFTER: 140001098: 20 00 00 36 tbz w0, #0, #4 +# AFTER: 14000109c: 10 00 00 b0 adrp x16, #4096 +# AFTER: 1400010a0: 10 2a 40 f9 ldr x16, [x16, #80] +# AFTER: 1400010a4: 00 02 1f d6 br x16 --- !COFF header: @@ -84,7 +98,7 @@ sections: - Name: .text Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 4 - SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD608000000000000000100000001000000 + SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F90001003900010079000100B9000100F90001403D0001407D000140BD000140FD0001C03D0001003D0001007D000100BD000100FD0001803D000540F9201A01B000FC4FF9E0031F2AFE0741F8C0035FD6080000000000000001000000010000000000009100004091000040f901000000201a09300100005400000036 Relocations: - VirtualAddress: 4 SymbolName: .Lstr @@ -167,6 +181,27 @@ sections: - VirtualAddress: 124 SymbolName: .Lglobal Type: IMAGE_REL_ARM64_SECREL + - VirtualAddress: 128 + SymbolName: .Lglobal5000 + Type: IMAGE_REL_ARM64_SECREL_LOW12A + - VirtualAddress: 132 + SymbolName: .Lglobal5000 + Type: IMAGE_REL_ARM64_SECREL_HIGH12A + - VirtualAddress: 136 + SymbolName: .Lglobal5000 + Type: IMAGE_REL_ARM64_SECREL_LOW12L + - VirtualAddress: 140 + SymbolName: .Lglobal + Type: IMAGE_REL_ARM64_SECTION + - VirtualAddress: 144 + SymbolName: .Lglobal + Type: IMAGE_REL_ARM64_REL21 + - VirtualAddress: 148 + SymbolName: function + Type: IMAGE_REL_ARM64_BRANCH19 + - VirtualAddress: 152 + SymbolName: function + Type: IMAGE_REL_ARM64_BRANCH14 - Name: .data Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] Alignment: 4 @@ -240,4 +275,10 @@ symbols: SimpleType: IMAGE_SYM_TYPE_NULL ComplexType: IMAGE_SYM_DTYPE_NULL StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .Lglobal5000 + Value: 5000 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC ... diff --git a/test/COFF/armnt-movt32t.test b/test/COFF/armnt-movt32t.test index 7c6965efed6a..6a0640c76fc3 100644 --- a/test/COFF/armnt-movt32t.test +++ b/test/COFF/armnt-movt32t.test @@ -11,7 +11,7 @@ # BEFORE: 8: 70 47 bx lr # AFTER: Disassembly of section .text: -# AFTER: 0: 41 f2 00 00 movw r0, #4096 +# AFTER: 0: 42 f2 00 00 movw r0, #8192 # AFTER: 4: c0 f2 40 00 movt r0, #64 # AFTER: 8: 70 47 bx lr diff --git a/test/COFF/associative-comdat.s b/test/COFF/associative-comdat.s index dd5419533c16..a3d069b53571 100644 --- a/test/COFF/associative-comdat.s +++ b/test/COFF/associative-comdat.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t1.obj # RUN: llvm-mc -triple=x86_64-windows-msvc %S/Inputs/associative-comdat-2.s -filetype=obj -o %t2.obj @@ -9,14 +10,15 @@ # CHECK: Sections [ # CHECK: Section { -# CHECK: Number: 1 -# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00) -# CHECK-NEXT: VirtualSize: 0x4 -# CHECK: Section { +# CHECK: Number: 2 # CHECK-LABEL: Name: .rdata (2E 72 64 61 74 61 00 00) # This is the critical check to show that only *one* definition of # foo_assoc was retained. This *must* be 8, not 16. # CHECK-NEXT: VirtualSize: 0x8 +# CHECK: Section { +# CHECK: Number: 3 +# CHECK-LABEL: Name: .data (2E 64 61 74 61 00 00 00) +# CHECK-NEXT: VirtualSize: 0x4 .text .def main; diff --git a/test/COFF/baserel.test b/test/COFF/baserel.test index ce0b27621caf..6441bb2be30d 100644 --- a/test/COFF/baserel.test +++ b/test/COFF/baserel.test @@ -9,35 +9,35 @@ # BASEREL: BaseReloc [ # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: DIR64 -# BASEREL-NEXT: Address: 0x2007 +# BASEREL-NEXT: Address: 0x1007 # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: DIR64 -# BASEREL-NEXT: Address: 0x200C +# BASEREL-NEXT: Address: 0x100C # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: DIR64 -# BASEREL-NEXT: Address: 0x201E +# BASEREL-NEXT: Address: 0x101E # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: ABSOLUTE -# BASEREL-NEXT: Address: 0x2000 +# BASEREL-NEXT: Address: 0x1000 # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: DIR64 -# BASEREL-NEXT: Address: 0x3007 +# BASEREL-NEXT: Address: 0x4007 # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: DIR64 -# BASEREL-NEXT: Address: 0x300C +# BASEREL-NEXT: Address: 0x400C # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: DIR64 -# BASEREL-NEXT: Address: 0x301E +# BASEREL-NEXT: Address: 0x401E # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: ABSOLUTE -# BASEREL-NEXT: Address: 0x3000 +# BASEREL-NEXT: Address: 0x4000 # BASEREL-NEXT: } # # NOBASEREL: BaseReloc [ diff --git a/test/COFF/combined-resources.test b/test/COFF/combined-resources.test index e8d5d65008d5..37dfc5732f48 100644 --- a/test/COFF/combined-resources.test +++ b/test/COFF/combined-resources.test @@ -11,8 +11,8 @@ # RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \ # RUN: FileCheck %s -CHECK: ResourceTableRVA: 0x1000 -CHECK-NEXT: ResourceTableSize: 0xC1C +CHECK: ResourceTableRVA: 0x2000 +CHECK-NEXT: ResourceTableSize: 0xC20 CHECK-DAG: Resources [ CHECK-NEXT: Total Number of Resources: 13 CHECK-DAG: .rsrc Data ( @@ -49,19 +49,19 @@ CHECK-NEXT: 01D0: 00000000 00000000 00000000 00000100 |................| CHECK-NEXT: 01E0: 09040000 A0020000 00000000 00000000 |................| CHECK-NEXT: 01F0: 00000000 00000300 09040000 B0020000 |................| CHECK-NEXT: 0200: 04080000 C0020000 07100000 D0020000 |................| -CHECK-NEXT: 0210: FC1A0000 39000000 00000000 00000000 |....9...........| -CHECK-NEXT: 0220: C4130000 28030000 00000000 00000000 |....(...........| -CHECK-NEXT: 0230: EC160000 28030000 00000000 00000000 |....(...........| -CHECK-NEXT: 0240: CC1A0000 30000000 00000000 00000000 |....0...........| -CHECK-NEXT: 0250: 141A0000 2E000000 00000000 00000000 |................| -CHECK-NEXT: 0260: 441A0000 6C000000 00000000 00000000 |D...l...........| -CHECK-NEXT: 0270: 7C130000 2A000000 00000000 00000000 ||...*...........| -CHECK-NEXT: 0280: AC130000 18000000 00000000 00000000 |................| -CHECK-NEXT: 0290: 041C0000 18000000 00000000 00000000 |................| -CHECK-NEXT: 02A0: B41A0000 18000000 00000000 00000000 |................| -CHECK-NEXT: 02B0: 3C1B0000 36000000 00000000 00000000 |<...6...........| -CHECK-NEXT: 02C0: 741B0000 43000000 00000000 00000000 |t...C...........| -CHECK-NEXT: 02D0: BC1B0000 42000000 00000000 00000000 |....B...........| +CHECK-NEXT: 0210: 002B0000 39000000 00000000 00000000 |.+..9...........| +CHECK-NEXT: 0220: C8230000 28030000 00000000 00000000 |.#..(...........| +CHECK-NEXT: 0230: F0260000 28030000 00000000 00000000 |.&..(...........| +CHECK-NEXT: 0240: D02A0000 30000000 00000000 00000000 |.*..0...........| +CHECK-NEXT: 0250: 182A0000 2E000000 00000000 00000000 |.*..............| +CHECK-NEXT: 0260: 482A0000 6C000000 00000000 00000000 |H*..l...........| +CHECK-NEXT: 0270: 80230000 2A000000 00000000 00000000 |.#..*...........| +CHECK-NEXT: 0280: B0230000 18000000 00000000 00000000 |.#..............| +CHECK-NEXT: 0290: 082C0000 18000000 00000000 00000000 |.,..............| +CHECK-NEXT: 02A0: B82A0000 18000000 00000000 00000000 |.*..............| +CHECK-NEXT: 02B0: 402B0000 36000000 00000000 00000000 |@+..6...........| +CHECK-NEXT: 02C0: 782B0000 43000000 00000000 00000000 |x+..C...........| +CHECK-NEXT: 02D0: C02B0000 42000000 00000000 00000000 |.+..B...........| CHECK-NEXT: 02E0: 0E004D00 59004100 43004300 45004C00 |..M.Y.A.C.C.E.L.| CHECK-NEXT: 02F0: 45005200 41005400 4F005200 53000600 |E.R.A.T.O.R.S...| CHECK-NEXT: 0300: 43005500 52005300 4F005200 04004F00 |C.U.R.S.O.R...O.| @@ -71,14 +71,14 @@ CHECK-NEXT: 0330: 45004100 54002200 0B005300 54005200 |E.A.T."...S.T.R.| CHECK-NEXT: 0340: 49004E00 47004100 52005200 41005900 |I.N.G.A.R.R.A.Y.| CHECK-NEXT: 0350: 0A004D00 59005200 45005300 4F005500 |..M.Y.R.E.S.O.U.| CHECK-NEXT: 0360: 52004300 45000900 52004100 4E004400 |R.C.E...R.A.N.D.| -CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000500 |O.M.D.A.T.......| -CHECK-NEXT: 0380: 48006500 6C006C00 6F000000 00000000 |H.e.l.l.o.......| +CHECK-NEXT: 0370: 4F004D00 44004100 54000000 00000000 |O.M.D.A.T.......| +CHECK-NEXT: 0380: 00000500 48006500 6C006C00 6F000000 |....H.e.l.l.o...| CHECK-NEXT: 0390: 00000000 00000000 00000000 00000000 |................| -CHECK-NEXT: 03A0: 00000000 00000000 00000000 11000300 |................| -CHECK-NEXT: 03B0: E7030000 0D004400 4C040000 82001200 |......D.L.......| -CHECK-NEXT: 03C0: BC010000 28000000 10000000 10000000 |....(...........| -CHECK-NEXT: 03D0: 01001800 00000000 00030000 C40E0000 |................| -CHECK-NEXT: 03E0: C40E0000 00000000 00000000 FFFFFFFF |................| +CHECK-NEXT: 03A0: 00000000 00000000 00000000 00000000 |................| +CHECK-NEXT: 03B0: 11000300 E7030000 0D004400 4C040000 |..........D.L...| +CHECK-NEXT: 03C0: 82001200 BC010000 28000000 10000000 |........(.......| +CHECK-NEXT: 03D0: 10000000 01001800 00000000 00030000 |................| +CHECK-NEXT: 03E0: C40E0000 C40E0000 00000000 00000000 |................| CHECK-NEXT: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| @@ -86,50 +86,50 @@ CHECK-NEXT: 0420: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0430: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0440: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0450: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0460: FF7F7F7F 7C7C7C78 78787575 75FFFFFF |....|||xxxuuu...| -CHECK-NEXT: 0470: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF 979797FF FFFFFFFF |................| -CHECK-NEXT: 0490: FF838383 AAAAAADB DBDB7979 79757575 |..........yyyuuu| -CHECK-NEXT: 04A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF 9C9C9C98 9898FFFF |................| -CHECK-NEXT: 04C0: FF888888 DBDBDBB7 B7B77D7D 7DFFFFFF |..........}}}...| -CHECK-NEXT: 04D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF A0A0A09C 9C9C9393 |................| -CHECK-NEXT: 04F0: 93ADADAD F2F2F284 84848181 81FFFFFF |................| -CHECK-NEXT: 0500: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF A4A4A4D7 D7D79D9D |................| -CHECK-NEXT: 0520: 9DD0D0D0 EEEEEE91 91918D8D 8DFFFFFF |................| -CHECK-NEXT: 0530: FFFFFF81 81817E7E 7EFFFFFF FFFFFFFF |......~~~.......| -CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF A9A9A9F2 F2F2E5E5 |................| -CHECK-NEXT: 0550: E5E2E2E2 95959591 91918D8D 8D898989 |................| -CHECK-NEXT: 0560: 868686FF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF ADADADF2 F2F2E1E1 |................| -CHECK-NEXT: 0580: E1DFDFDF E7E7E7E4 E4E4BBBB BB8E8E8E |................| -CHECK-NEXT: 0590: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF B5B5B5F2 F2F2E8E8 |................| -CHECK-NEXT: 05B0: E8E7E7E7 EAEAEAC6 C6C69E9E 9EFFFFFF |................| -CHECK-NEXT: 05C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF B9B9B9F4 F4F4ECEC |................| -CHECK-NEXT: 05E0: ECEDEDED CBCBCBA7 A7A7FFFF FFFFFFFF |................| +CHECK-NEXT: 0460: FFFFFFFF FF7F7F7F 7C7C7C78 78787575 |........|||xxxuu| +CHECK-NEXT: 0470: 75FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |u...............| +CHECK-NEXT: 0480: FFFFFFFF FFFFFFFF FFFFFFFF 979797FF |................| +CHECK-NEXT: 0490: FFFFFFFF FF838383 AAAAAADB DBDB7979 |..............yy| +CHECK-NEXT: 04A0: 79757575 FFFFFFFF FFFFFFFF FFFFFFFF |yuuu............| +CHECK-NEXT: 04B0: FFFFFFFF FFFFFFFF FFFFFFFF 9C9C9C98 |................| +CHECK-NEXT: 04C0: 9898FFFF FF888888 DBDBDBB7 B7B77D7D |..............}}| +CHECK-NEXT: 04D0: 7DFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |}...............| +CHECK-NEXT: 04E0: FFFFFFFF FFFFFFFF FFFFFFFF A0A0A09C |................| +CHECK-NEXT: 04F0: 9C9C9393 93ADADAD F2F2F284 84848181 |................| +CHECK-NEXT: 0500: 81FFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0510: FFFFFFFF FFFFFFFF FFFFFFFF A4A4A4D7 |................| +CHECK-NEXT: 0520: D7D79D9D 9DD0D0D0 EEEEEE91 91918D8D |................| +CHECK-NEXT: 0530: 8DFFFFFF FFFFFF81 81817E7E 7EFFFFFF |..........~~~...| +CHECK-NEXT: 0540: FFFFFFFF FFFFFFFF FFFFFFFF A9A9A9F2 |................| +CHECK-NEXT: 0550: F2F2E5E5 E5E2E2E2 95959591 91918D8D |................| +CHECK-NEXT: 0560: 8D898989 868686FF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0570: FFFFFFFF FFFFFFFF FFFFFFFF ADADADF2 |................| +CHECK-NEXT: 0580: F2F2E1E1 E1DFDFDF E7E7E7E4 E4E4BBBB |................| +CHECK-NEXT: 0590: BB8E8E8E FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 05A0: FFFFFFFF FFFFFFFF FFFFFFFF B5B5B5F2 |................| +CHECK-NEXT: 05B0: F2F2E8E8 E8E7E7E7 EAEAEAC6 C6C69E9E |................| +CHECK-NEXT: 05C0: 9EFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 05D0: FFFFFFFF FFFFFFFF FFFFFFFF B9B9B9F4 |................| +CHECK-NEXT: 05E0: F4F4ECEC ECEDEDED CBCBCBA7 A7A7FFFF |................| CHECK-NEXT: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF BDBDBDF7 F7F7EFEF |................| -CHECK-NEXT: 0610: EFD0D0D0 AFAFAFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF FFFFFFFF BDBDBDF7 |................| +CHECK-NEXT: 0610: F7F7EFEF EFD0D0D0 AFAFAFFF FFFFFFFF |................| CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF C1C1C1F7 F7F7D5D5 |................| -CHECK-NEXT: 0640: D5B6B6B6 FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF FFFFFFFF C1C1C1F7 |................| +CHECK-NEXT: 0640: F7F7D5D5 D5B6B6B6 FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0650: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF C4C4C4D9 D9D9BEBE |................| -CHECK-NEXT: 0670: BEFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0660: FFFFFFFF FFFFFFFF FFFFFFFF C4C4C4D9 |................| +CHECK-NEXT: 0670: D9D9BEBE BEFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0680: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF C8C8C8C5 C5C5FFFF |................| -CHECK-NEXT: 06A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF FFFFFFFF C8C8C8C5 |................| +CHECK-NEXT: 06A0: C5C5FFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 06B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF CBCBCBFF FFFFFFFF |................| +CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF FFFFFFFF CBCBCBFF |................| CHECK-NEXT: 06D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF 28000000 |............(...| -CHECK-NEXT: 06F0: 10000000 10000000 01001800 00000000 |................| -CHECK-NEXT: 0700: 00030000 C40E0000 C40E0000 00000000 |................| -CHECK-NEXT: 0710: 00000000 FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 06E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 06F0: 28000000 10000000 10000000 01001800 |(...............| +CHECK-NEXT: 0700: 00000000 00030000 C40E0000 C40E0000 |................| +CHECK-NEXT: 0710: 00000000 00000000 FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0720: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0730: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0740: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| @@ -142,29 +142,29 @@ CHECK-NEXT: 07A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 07B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 07C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 07D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 07E0: A0E3A901 B31801B3 1801B318 01B31801 |................| -CHECK-NEXT: 07F0: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........| +CHECK-NEXT: 07E0: FFFFFFFF A0E3A901 B31801B3 1801B318 |................| +CHECK-NEXT: 07F0: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....| CHECK-NEXT: 0800: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0810: 01B31800 D7331CDB 49DBF9E2 9BEFAF00 |.....3..I.......| -CHECK-NEXT: 0820: D73300D7 3301B318 FFFFFFFF FFFFFFFF |.3..3...........| +CHECK-NEXT: 0810: FFFFFFFF 01B31800 D7331CDB 49DBF9E2 |.........3..I...| +CHECK-NEXT: 0820: 9BEFAF00 D73300D7 3301B318 FFFFFFFF |.....3..3.......| CHECK-NEXT: 0830: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0840: 01B31800 DE55F6FE F9DBFAE7 FEFFFE86 |.....U..........| -CHECK-NEXT: 0850: EFAE00DE 5501B318 FFFFFFFF FFFFFFFF |....U...........| +CHECK-NEXT: 0840: FFFFFFFF 01B31800 DE55F6FE F9DBFAE7 |.........U......| +CHECK-NEXT: 0850: FEFFFE86 EFAE00DE 5501B318 FFFFFFFF |........U.......| CHECK-NEXT: 0860: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0870: 01B31800 E676DBFB EC00E676 57EFA5FB |.....v.....vW...| -CHECK-NEXT: 0880: FFFD55EE A401B318 FFFFFFFF FFFFFFFF |..U.............| +CHECK-NEXT: 0870: FFFFFFFF 01B31800 E676DBFB EC00E676 |.........v.....v| +CHECK-NEXT: 0880: 57EFA5FB FFFD55EE A401B318 FFFFFFFF |W.....U.........| CHECK-NEXT: 0890: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 08A0: 01B31800 ED9800ED 9800ED98 00ED9887 |................| -CHECK-NEXT: 08B0: F7CFFEFF FF01B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08A0: FFFFFFFF 01B31800 ED9800ED 9800ED98 |................| +CHECK-NEXT: 08B0: 00ED9887 F7CFFEFF FF01B318 FFFFFFFF |................| CHECK-NEXT: 08C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 08D0: 01B31800 F4BA00F4 BA00F4BA 00F4BA00 |................| -CHECK-NEXT: 08E0: F4BA9CFB E401B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08D0: FFFFFFFF 01B31800 F4BA00F4 BA00F4BA |................| +CHECK-NEXT: 08E0: 00F4BA00 F4BA9CFB E401B318 FFFFFFFF |................| CHECK-NEXT: 08F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0900: 01B31800 FBDB00FB DB00FBDB 00FBDB00 |................| -CHECK-NEXT: 0910: FBDB00FB DB01B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0900: FFFFFFFF 01B31800 FBDB00FB DB00FBDB |................| +CHECK-NEXT: 0910: 00FBDB00 FBDB00FB DB01B318 FFFFFFFF |................| CHECK-NEXT: 0920: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0930: 9FE2A801 B31801B3 1801B318 01B31801 |................| -CHECK-NEXT: 0940: B31801B3 1861D06F FFFFFFFF FFFFFFFF |.....a.o........| +CHECK-NEXT: 0930: FFFFFFFF 9FE2A801 B31801B3 1801B318 |................| +CHECK-NEXT: 0940: 01B31801 B31801B3 1861D06F FFFFFFFF |.........a.o....| CHECK-NEXT: 0950: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0960: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0970: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| @@ -177,37 +177,37 @@ CHECK-NEXT: 09D0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 09E0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 09F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| CHECK-NEXT: 0A00: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| -CHECK-NEXT: 0A10: FFFFFFFF 00000000 00006400 79007500 |..........d.y.u.| -CHECK-NEXT: 0A20: 00000000 65007300 68006100 6C006100 |....e.s.h.a.l.a.| -CHECK-NEXT: 0A30: 00008000 66006B00 61006F00 79006100 |....f.k.a.o.y.a.| -CHECK-NEXT: 0A40: 00000000 0000C080 00000000 02000A00 |................| -CHECK-NEXT: 0A50: 0A00C800 2C010000 00005400 65007300 |....,.....T.e.s.| -CHECK-NEXT: 0A60: 74000000 01000250 00000000 0A000A00 |t......P........| -CHECK-NEXT: 0A70: E6000E00 0100FFFF 82004300 6F006E00 |..........C.o.n.| -CHECK-NEXT: 0A80: 74006900 6E007500 65003A00 00000000 |t.i.n.u.e.:.....| -CHECK-NEXT: 0A90: 00000150 00000000 42008600 A1000D00 |...P....B.......| -CHECK-NEXT: 0AA0: 0200FFFF 80002600 4F004B00 00000000 |......&.O.K.....| -CHECK-NEXT: 0AB0: 00000000 11005800 A4000000 0D004800 |......X.......H.| -CHECK-NEXT: 0AC0: 2E160000 82001200 BC010000 00000000 |................| -CHECK-NEXT: 0AD0: 00006400 66006900 73006800 00000000 |..d.f.i.s.h.....| -CHECK-NEXT: 0AE0: 65007300 61006C00 61006400 00008000 |e.s.a.l.a.d.....| -CHECK-NEXT: 0AF0: 66006400 75006300 6B000000 74686973 |f.d.u.c.k...this| -CHECK-NEXT: 0B00: 20697320 61207573 65722064 6566696E | is a user defin| -CHECK-NEXT: 0B10: 65642072 65736F75 72636500 69742063 |ed resource.it c| -CHECK-NEXT: 0B20: 6F6E7461 696E7320 6D616E79 20737472 |ontains many str| -CHECK-NEXT: 0B30: 696E6773 00000000 00000000 74686973 |ings........this| -CHECK-NEXT: 0B40: 20697320 61207261 6E646F6D 20626974 | is a random bit| -CHECK-NEXT: 0B50: 206F6620 64617461 20746861 74206D65 | of data that me| -CHECK-NEXT: 0B60: 616E7320 6E6F7468 696E6700 A9230E14 |ans nothing..#..| -CHECK-NEXT: 0B70: F4F60000 7A686534 20736869 34207969 |....zhe4 shi4 yi| -CHECK-NEXT: 0B80: 31676534 20737569 326A6931 20646520 |1ge4 sui2ji1 de | -CHECK-NEXT: 0B90: 73687534 6A75342C 207A6865 34207969 |shu4ju4, zhe4 yi| -CHECK-NEXT: 0BA0: 34776569 347A6865 20736865 6E326D65 |4wei4zhe shen2me| -CHECK-NEXT: 0BB0: 00A9230E 14F4F600 00000000 44696573 |..#.........Dies| -CHECK-NEXT: 0BC0: 20697374 2065696E 207A7566 C3A46C6C | ist ein zuf..ll| -CHECK-NEXT: 0BD0: 69676573 20426974 20766F6E 20446174 |iges Bit von Dat| -CHECK-NEXT: 0BE0: 656E2C20 64696520 6E696368 74732062 |en, die nichts b| -CHECK-NEXT: 0BF0: 65646575 74657400 A9230E14 F4F60000 |edeutet..#......| -CHECK-NEXT: 0C00: 00000000 11000300 E7030000 0D004400 |..............D.| -CHECK-NEXT: 0C10: 4C040000 82001200 BC010000 |L...........| +CHECK-NEXT: 0A10: FFFFFFFF FFFFFFFF 00000000 00006400 |..............d.| +CHECK-NEXT: 0A20: 79007500 00000000 65007300 68006100 |y.u.....e.s.h.a.| +CHECK-NEXT: 0A30: 6C006100 00008000 66006B00 61006F00 |l.a.....f.k.a.o.| +CHECK-NEXT: 0A40: 79006100 00000000 0000C080 00000000 |y.a.............| +CHECK-NEXT: 0A50: 02000A00 0A00C800 2C010000 00005400 |........,.....T.| +CHECK-NEXT: 0A60: 65007300 74000000 01000250 00000000 |e.s.t......P....| +CHECK-NEXT: 0A70: 0A000A00 E6000E00 0100FFFF 82004300 |..............C.| +CHECK-NEXT: 0A80: 6F006E00 74006900 6E007500 65003A00 |o.n.t.i.n.u.e.:.| +CHECK-NEXT: 0A90: 00000000 00000150 00000000 42008600 |.......P....B...| +CHECK-NEXT: 0AA0: A1000D00 0200FFFF 80002600 4F004B00 |..........&.O.K.| +CHECK-NEXT: 0AB0: 00000000 00000000 11005800 A4000000 |..........X.....| +CHECK-NEXT: 0AC0: 0D004800 2E160000 82001200 BC010000 |..H.............| +CHECK-NEXT: 0AD0: 00000000 00006400 66006900 73006800 |......d.f.i.s.h.| +CHECK-NEXT: 0AE0: 00000000 65007300 61006C00 61006400 |....e.s.a.l.a.d.| +CHECK-NEXT: 0AF0: 00008000 66006400 75006300 6B000000 |....f.d.u.c.k...| +CHECK-NEXT: 0B00: 74686973 20697320 61207573 65722064 |this is a user d| +CHECK-NEXT: 0B10: 6566696E 65642072 65736F75 72636500 |efined resource.| +CHECK-NEXT: 0B20: 69742063 6F6E7461 696E7320 6D616E79 |it contains many| +CHECK-NEXT: 0B30: 20737472 696E6773 00000000 00000000 | strings........| +CHECK-NEXT: 0B40: 74686973 20697320 61207261 6E646F6D |this is a random| +CHECK-NEXT: 0B50: 20626974 206F6620 64617461 20746861 | bit of data tha| +CHECK-NEXT: 0B60: 74206D65 616E7320 6E6F7468 696E6700 |t means nothing.| +CHECK-NEXT: 0B70: A9230E14 F4F60000 7A686534 20736869 |.#......zhe4 shi| +CHECK-NEXT: 0B80: 34207969 31676534 20737569 326A6931 |4 yi1ge4 sui2ji1| +CHECK-NEXT: 0B90: 20646520 73687534 6A75342C 207A6865 | de shu4ju4, zhe| +CHECK-NEXT: 0BA0: 34207969 34776569 347A6865 20736865 |4 yi4wei4zhe she| +CHECK-NEXT: 0BB0: 6E326D65 00A9230E 14F4F600 00000000 |n2me..#.........| +CHECK-NEXT: 0BC0: 44696573 20697374 2065696E 207A7566 |Dies ist ein zuf| +CHECK-NEXT: 0BD0: C3A46C6C 69676573 20426974 20766F6E |..lliges Bit von| +CHECK-NEXT: 0BE0: 20446174 656E2C20 64696520 6E696368 | Daten, die nich| +CHECK-NEXT: 0BF0: 74732062 65646575 74657400 A9230E14 |ts bedeutet..#..| +CHECK-NEXT: 0C00: F4F60000 00000000 11000300 E7030000 |................| +CHECK-NEXT: 0C10: 0D004400 4C040000 82001200 BC010000 |..D.L...........| CHECK-NEXT: ) diff --git a/test/COFF/common-alignment.test b/test/COFF/common-alignment.test index a4ee15729107..db02d9157c85 100644 --- a/test/COFF/common-alignment.test +++ b/test/COFF/common-alignment.test @@ -4,8 +4,8 @@ # RUN: llvm-objdump -d %t.exe | FileCheck %s # Operands of B8 (MOV EAX) are common symbols -# CHECK: 3000: b8 00 10 00 40 -# CHECK: 3005: b8 10 10 00 40 +# CHECK: 1000: b8 00 20 00 40 +# CHECK: 1005: b8 10 20 00 40 --- !COFF header: @@ -23,10 +23,6 @@ sections: - VirtualAddress: 6 SymbolName: bssdata4_align16 Type: IMAGE_REL_AMD64_ADDR32 - - Name: .data - Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] - Alignment: 4 - SectionData: 03000000 - Name: .drectve Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ] Alignment: 1 @@ -45,18 +41,6 @@ symbols: NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 - - Name: .data - Value: 0 - SectionNumber: 2 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: - Length: 4 - NumberOfRelocations: 0 - NumberOfLinenumbers: 0 - CheckSum: 0 - Number: 0 - Name: main Value: 0 SectionNumber: 1 diff --git a/test/COFF/common.test b/test/COFF/common.test index 4a00153f3e93..7d11da2ae150 100644 --- a/test/COFF/common.test +++ b/test/COFF/common.test @@ -4,11 +4,11 @@ # RUN: llvm-objdump -d %t.exe | FileCheck %s # Operands of B8 (MOV EAX) are common symbols -# CHECK: 3000: b8 00 10 00 40 -# CHECK: 3005: b8 04 10 00 40 -# CHECK: 300a: b8 20 10 00 40 -# CHECK: 300f: b8 60 10 00 40 -# CHECK: 3014: b8 70 10 00 40 +# CHECK: 1000: b8 00 20 00 40 +# CHECK: 1005: b8 04 20 00 40 +# CHECK: 100a: b8 20 20 00 40 +# CHECK: 100f: b8 60 20 00 40 +# CHECK: 1014: b8 70 20 00 40 --- !COFF header: @@ -35,10 +35,6 @@ sections: - VirtualAddress: 21 SymbolName: bssdata16 Type: IMAGE_REL_AMD64_ADDR32 - - Name: .data - Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] - Alignment: 4 - SectionData: 03000000 symbols: - Name: .text Value: 0 @@ -52,18 +48,6 @@ symbols: NumberOfLinenumbers: 0 CheckSum: 0 Number: 0 - - Name: .data - Value: 0 - SectionNumber: 2 - SimpleType: IMAGE_SYM_TYPE_NULL - ComplexType: IMAGE_SYM_DTYPE_NULL - StorageClass: IMAGE_SYM_CLASS_STATIC - SectionDefinition: - Length: 4 - NumberOfRelocations: 0 - NumberOfLinenumbers: 0 - CheckSum: 0 - Number: 0 - Name: main Value: 0 SectionNumber: 1 diff --git a/test/COFF/crt-chars.test b/test/COFF/crt-chars.test new file mode 100644 index 000000000000..e685631bb504 --- /dev/null +++ b/test/COFF/crt-chars.test @@ -0,0 +1,32 @@ +# RUN: yaml2obj %s > %t.obj +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck %s + +# CHECK: Name: .CRT +# CHECK: Characteristics [ +# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# CHECK-NEXT: IMAGE_SCN_MEM_READ +# CHECK-NEXT: ] +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 010203 +# CHECK-NEXT: ) + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .CRT$XCZ + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 03 + - Name: .CRT$XCU + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 1 + SectionData: 02 + - Name: .CRT$XCA + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 01 +symbols: +... diff --git a/test/COFF/ctors_dtors_priority.s b/test/COFF/ctors_dtors_priority.s index 60562ba57a52..efa03543027b 100644 --- a/test/COFF/ctors_dtors_priority.s +++ b/test/COFF/ctors_dtors_priority.s @@ -22,9 +22,9 @@ main: .quad 2 # CHECK: Contents of section .ctors: -# CHECK-NEXT: 140001000 01000000 00000000 02000000 00000000 -# CHECK-NEXT: 140001010 03000000 00000000 - -# CHECK: Contents of section .dtors: # CHECK-NEXT: 140002000 01000000 00000000 02000000 00000000 # CHECK-NEXT: 140002010 03000000 00000000 + +# CHECK: Contents of section .dtors: +# CHECK-NEXT: 140003000 01000000 00000000 02000000 00000000 +# CHECK-NEXT: 140003010 03000000 00000000 diff --git a/test/COFF/debug-reloc.s b/test/COFF/debug-reloc.s new file mode 100644 index 000000000000..57ab9bf9cdbc --- /dev/null +++ b/test/COFF/debug-reloc.s @@ -0,0 +1,58 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj + +# RUN: lld-link -lldmingw -debug:dwarf -out:%t.exe -entry:mainfunc -subsystem:console %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck %s -check-prefix SECTIONS +# RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck %s -check-prefix RELOCS +# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s -check-prefix HEADERS +# RUN: llvm-readobj -coff-debug-directory %t.exe | FileCheck %s -check-prefix DEBUG + +# SECTIONS: Number: 2 +# SECTIONS-NEXT: Name: .buildid (2E 62 75 69 6C 64 69 64) +# SECTIONS-NEXT: VirtualSize: 0x35 +# SECTIONS-NEXT: VirtualAddress: 0x2000 +# SECTIONS: Number: 3 +# SECTIONS-NEXT: Name: .data (2E 64 61 74 61 00 00 00) +# SECTIONS-NEXT: VirtualSize: 0x8 +# SECTIONS-NEXT: VirtualAddress: 0x3000 + +# RELOCS: BaseReloc [ +# RELOCS-NEXT: Entry { +# RELOCS-NEXT: Type: DIR64 +# RELOCS-NEXT: Address: 0x3000 +# RELOCS-NEXT: } +# RELOCS-NEXT: Entry { +# RELOCS-NEXT: Type: ABSOLUTE +# RELOCS-NEXT: Address: 0x3000 +# RELOCS-NEXT: } +# RELOCS-NEXT: ] + +# HEADERS: DebugRVA: 0x2000 +# HEADERS: DebugSize: 0x1C + +# DEBUG: DebugDirectory [ +# DEBUG: DebugEntry { +# DEBUG: Type: CodeView (0x2) +# DEBUG: SizeOfData: 0x19 +# DEBUG: AddressOfRawData: 0x201C +# DEBUG: PointerToRawData: 0x61C + + .text + .def mainfunc; + .scl 2; + .type 32; + .endef + .globl mainfunc +mainfunc: +.Lfunc_begin0: + xorl %eax, %eax + retq + + .data + .globl ptr +ptr: + .quad mainfunc + + .section .debug_info,"dr" + .quad .Lfunc_begin0 diff --git a/test/COFF/def-export-stdcall.s b/test/COFF/def-export-stdcall.s index 851ac6d975b9..fd1ec2ca3ace 100644 --- a/test/COFF/def-export-stdcall.s +++ b/test/COFF/def-export-stdcall.s @@ -32,8 +32,7 @@ # DECORATED-IMPLIB: Name type: name # DECORATED-IMPLIB-NEXT: __imp_@fastcall@8 # DECORATED-IMPLIB-NEXT: @fastcall@8 -# TODO: To match link.exe, this one should also be Name type: name. -# DECORATED-IMPLIB: Name type: noprefix +# DECORATED-IMPLIB: Name type: name # DECORATED-IMPLIB-NEXT: __imp__stdcall@8 # DECORATED-IMPLIB-NEXT: _stdcall@8 # DECORATED-IMPLIB: Name type: name @@ -41,12 +40,12 @@ # DECORATED-IMPLIB-NEXT: vectorcall@@8 # DECORATED-EXPORTS: Name: @fastcall@8 -# TODO: To match link.exe, this one should actually be _stdcall@8 -# DECORATED-EXPORTS: Name: stdcall@8 +# DECORATED-EXPORTS: Name: _stdcall@8 # DECORATED-EXPORTS: Name: vectorcall@@8 -# RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall@8\n @fastcall@8" > %t.def +# GNU tools don't support vectorcall at the moment, but test it for completeness. +# RUN: echo -e "LIBRARY foo\nEXPORTS\n stdcall@8\n @fastcall@8\n vectorcall@@8" > %t.def # RUN: lld-link -lldmingw -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib # RUN: llvm-readobj %t.lib | FileCheck -check-prefix DECORATED-MINGW-IMPLIB %s # RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix DECORATED-MINGW-EXPORTS %s @@ -57,9 +56,39 @@ # DECORATED-MINGW-IMPLIB: Name type: noprefix # DECORATED-MINGW-IMPLIB-NEXT: __imp__stdcall@8 # DECORATED-MINGW-IMPLIB-NEXT: _stdcall@8 +# GNU tools don't support vectorcall, but this test is just to track that +# lld's behaviour remains consistent over time. +# DECORATED-MINGW-IMPLIB: Name type: name +# DECORATED-MINGW-IMPLIB-NEXT: __imp_vectorcall@@8 +# DECORATED-MINGW-IMPLIB-NEXT: vectorcall@@8 # DECORATED-MINGW-EXPORTS: Name: @fastcall@8 # DECORATED-MINGW-EXPORTS: Name: stdcall@8 +# DECORATED-MINGW-EXPORTS: Name: vectorcall@@8 + +# RUN: lld-link -lldmingw -kill-at -entry:dllmain -dll -def:%t.def %t.obj -out:%t.dll -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck -check-prefix MINGW-KILL-AT-IMPLIB %s +# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s + +# RUN: lld-link -lldmingw -kill-at -entry:dllmain -dll %t.obj -out:%t.dll -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck -check-prefix MINGW-KILL-AT-IMPLIB %s +# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix MINGW-KILL-AT-EXPORTS %s + +# MINGW-KILL-AT-IMPLIB: Name type: noprefix +# MINGW-KILL-AT-IMPLIB: __imp__fastcall +# MINGW-KILL-AT-IMPLIB-NEXT: _fastcall +# MINGW-KILL-AT-IMPLIB: Name type: noprefix +# MINGW-KILL-AT-IMPLIB-NEXT: __imp__stdcall +# MINGW-KILL-AT-IMPLIB-NEXT: _stdcall +# GNU tools don't support vectorcall, but this test is just to track that +# lld's behaviour remains consistent over time. +# MINGW-KILL-AT-IMPLIB: Name type: noprefix +# MINGW-KILL-AT-IMPLIB-NEXT: __imp__vectorcall +# MINGW-KILL-AT-IMPLIB-NEXT: _vectorcall + +# MINGW-KILL-AT-EXPORTS: Name: fastcall +# MINGW-KILL-AT-EXPORTS: Name: stdcall +# MINGW-KILL-AT-EXPORTS: Name: vectorcall .def _stdcall@8; diff --git a/test/COFF/default-alignment.test b/test/COFF/default-alignment.test new file mode 100644 index 000000000000..da8ea06a77ee --- /dev/null +++ b/test/COFF/default-alignment.test @@ -0,0 +1,21 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld-link /out:%t.exe %t.obj /entry:__ImageBase /subsystem:console +# RUN: llvm-objdump -s %t.exe | FileCheck %s + +# CHECK: Contents of section .rdata: +# CHECK-NEXT: 01000000 00000000 00000000 00000000 +# CHECK-NEXT: 02 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + SectionData: 01 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + SectionData: 02 +symbols: +... diff --git a/test/COFF/delayimports-armnt.yaml b/test/COFF/delayimports-armnt.yaml index 231b4bc5c1f1..a080d028d20f 100644 --- a/test/COFF/delayimports-armnt.yaml +++ b/test/COFF/delayimports-armnt.yaml @@ -20,7 +20,7 @@ # IMPORT-NEXT: UnloadDelayImportTable: 0x0 # IMPORT-NEXT: Import { # IMPORT-NEXT: Symbol: function (0) -# IMPORT-NEXT: Address: 0x401019 +# IMPORT-NEXT: Address: 0x40100D # IMPORT-NEXT: } # IMPORT-NEXT: } # @@ -35,11 +35,11 @@ # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: ARM_MOV32(T) -# BASEREL-NEXT: Address: 0x1018 +# BASEREL-NEXT: Address: 0x1022 # BASEREL-NEXT: } # BASEREL-NEXT: Entry { -# BASEREL-NEXT: Type: ARM_MOV32(T) -# BASEREL-NEXT: Address: 0x102E +# BASEREL-NEXT: Type: ABSOLUTE +# BASEREL-NEXT: Address: 0x1000 # BASEREL-NEXT: } # BASEREL-NEXT: Entry { # BASEREL-NEXT: Type: HIGHLOW @@ -51,19 +51,19 @@ # BASEREL-NEXT: } # BASEREL-NEXT: ] # -# DISASM: 401018: 43 f2 08 0c movw r12, #12296 -# DISASM-NEXT: 40101c: c0 f2 40 0c movt r12, #64 -# DISASM-NEXT: 401020: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr} -# DISASM-NEXT: 401024: 0d f2 10 0b addw r11, sp, #16 -# DISASM-NEXT: 401028: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7} -# DISASM-NEXT: 40102c: 61 46 mov r1, r12 -# DISASM-NEXT: 40102e: 42 f2 00 00 movw r0, #8192 -# DISASM-NEXT: 401032: c0 f2 40 00 movt r0, #64 -# DISASM-NEXT: 401036: ff f7 e3 ff bl #-58 -# DISASM-NEXT: 40103a: 84 46 mov r12, r0 -# DISASM-NEXT: 40103c: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7} -# DISASM-NEXT: 401040: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr} -# DISASM-NEXT: 401044: 60 47 bx r12 +# DISASM: 40100c: 43 f2 08 0c movw r12, #12296 +# DISASM-NEXT: c0 f2 40 0c movt r12, #64 +# DISASM-NEXT: 2d e9 0f 48 push.w {r0, r1, r2, r3, r11, lr} +# DISASM-NEXT: 0d f2 10 0b addw r11, sp, #16 +# DISASM-NEXT: 2d ed 10 0b vpush {d0, d1, d2, d3, d4, d5, d6, d7} +# DISASM-NEXT: 61 46 mov r1, r12 +# DISASM-NEXT: 42 f2 00 00 movw r0, #8192 +# DISASM-NEXT: c0 f2 40 00 movt r0, #64 +# DISASM-NEXT: ff f7 e9 ff bl #-46 +# DISASM-NEXT: 84 46 mov r12, r0 +# DISASM-NEXT: bd ec 10 0b vpop {d0, d1, d2, d3, d4, d5, d6, d7} +# DISASM-NEXT: bd e8 0f 48 pop.w {r0, r1, r2, r3, r11, lr} +# DISASM-NEXT: 60 47 bx r12 --- !COFF header: diff --git a/test/COFF/delayimports.test b/test/COFF/delayimports.test index 2c27d58dc793..c6888b31720e 100644 --- a/test/COFF/delayimports.test +++ b/test/COFF/delayimports.test @@ -7,35 +7,35 @@ IMPORT: DelayImport { IMPORT-NEXT: Name: std64.dll IMPORT-NEXT: Attributes: 0x1 -IMPORT-NEXT: ModuleHandle: 0x1018 -IMPORT-NEXT: ImportAddressTable: 0x1020 -IMPORT-NEXT: ImportNameTable: 0x3040 +IMPORT-NEXT: ModuleHandle: 0x3018 +IMPORT-NEXT: ImportAddressTable: 0x3020 +IMPORT-NEXT: ImportNameTable: 0x2040 IMPORT-NEXT: BoundDelayImportTable: 0x0 IMPORT-NEXT: UnloadDelayImportTable: 0x0 IMPORT-NEXT: Import { IMPORT-NEXT: Symbol: ExitProcess (0) -IMPORT-NEXT: Address: 0x140002066 +IMPORT-NEXT: Address: 0x140001066 IMPORT-NEXT: } IMPORT-NEXT: Import { IMPORT-NEXT: Symbol: (50) -IMPORT-NEXT: Address: 0x1400020BD +IMPORT-NEXT: Address: 0x1400010BD IMPORT-NEXT: } IMPORT-NEXT: Import { IMPORT-NEXT: Symbol: MessageBoxA (0) -IMPORT-NEXT: Address: 0x140002114 +IMPORT-NEXT: Address: 0x140001114 IMPORT-NEXT: } IMPORT-NEXT: } BASEREL: BaseReloc [ BASEREL-NEXT: Entry { BASEREL-NEXT: Type: DIR64 -BASEREL-NEXT: Address: 0x1020 +BASEREL-NEXT: Address: 0x3020 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: DIR64 -BASEREL-NEXT: Address: 0x1028 +BASEREL-NEXT: Address: 0x3028 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: DIR64 -BASEREL-NEXT: Address: 0x1030 +BASEREL-NEXT: Address: 0x3030 BASEREL-NEXT: } diff --git a/test/COFF/delayimports32.test b/test/COFF/delayimports32.test index 006eecff4d95..9aa8f8697d4c 100644 --- a/test/COFF/delayimports32.test +++ b/test/COFF/delayimports32.test @@ -2,7 +2,7 @@ # RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj # RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ # RUN: /entry:main@0 /alternatename:___delayLoadHelper2@8=_main@0 \ -# RUN: /debug /delayload:std32.dll /out:%t.exe +# RUN: /delayload:std32.dll /out:%t.exe # RUN: llvm-readobj -coff-imports %t.exe | FileCheck -check-prefix=IMPORT %s # RUN: llvm-readobj -coff-basereloc %t.exe | FileCheck -check-prefix=BASEREL %s # RUN: llvm-objdump -d %t.exe | FileCheck -check-prefix=DISASM %s @@ -13,75 +13,75 @@ IMPORT-NEXT: AddressSize: 32bit IMPORT-NEXT: DelayImport { IMPORT-NEXT: Name: std32.dll IMPORT-NEXT: Attributes: 0x1 -IMPORT-NEXT: ModuleHandle: 0x1018 -IMPORT-NEXT: ImportAddressTable: 0x1020 -IMPORT-NEXT: ImportNameTable: 0x4040 +IMPORT-NEXT: ModuleHandle: 0x3018 +IMPORT-NEXT: ImportAddressTable: 0x3020 +IMPORT-NEXT: ImportNameTable: 0x2040 IMPORT-NEXT: BoundDelayImportTable: 0x0 IMPORT-NEXT: UnloadDelayImportTable: 0x0 IMPORT-NEXT: Import { IMPORT-NEXT: Symbol: ExitProcess (0) -IMPORT-NEXT: Address: 0x402029 +IMPORT-NEXT: Address: 0x401029 IMPORT-NEXT: } IMPORT-NEXT: Import { IMPORT-NEXT: Symbol: MessageBoxA (0) -IMPORT-NEXT: Address: 0x40203E +IMPORT-NEXT: Address: 0x40103E IMPORT-NEXT: } IMPORT-NEXT: } BASEREL: BaseReloc [ BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x1020 +BASEREL-NEXT: Address: 0x1005 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x1024 +BASEREL-NEXT: Address: 0x100C BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x2005 +BASEREL-NEXT: Address: 0x101F BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x200C +BASEREL-NEXT: Address: 0x1025 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x201F +BASEREL-NEXT: Address: 0x102C BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x2025 +BASEREL-NEXT: Address: 0x1031 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x202C +BASEREL-NEXT: Address: 0x1041 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x2031 +BASEREL-NEXT: Address: 0x1046 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x2041 +BASEREL-NEXT: Address: 0x3020 BASEREL-NEXT: } BASEREL-NEXT: Entry { BASEREL-NEXT: Type: HIGHLOW -BASEREL-NEXT: Address: 0x2046 +BASEREL-NEXT: Address: 0x3024 BASEREL-NEXT: } BASEREL-NEXT: ] -DISASM: 202b: 68 20 10 40 00 pushl $4198432 -DISASM-NEXT: 2030: 68 00 40 40 00 pushl $4210688 -DISASM-NEXT: 2035: e8 c6 ff ff ff calll -58 <.text> -DISASM-NEXT: 203a: 5a popl %edx -DISASM-NEXT: 203b: 59 popl %ecx -DISASM-NEXT: 203c: ff e0 jmpl *%eax -DISASM-NEXT: 203e: 51 pushl %ecx -DISASM-NEXT: 203f: 52 pushl %edx -DISASM-NEXT: 2040: 68 24 10 40 00 pushl $4198436 -DISASM-NEXT: 2045: 68 00 40 40 00 pushl $4210688 -DISASM-NEXT: 204a: e8 b1 ff ff ff calll -79 <.text> -DISASM-NEXT: 204f: 5a popl %edx -DISASM-NEXT: 2050: 59 popl %ecx -DISASM-NEXT: 2051: ff e0 jmpl *%eax +DISASM: 102b: 68 20 30 40 00 pushl $4206624 +DISASM-NEXT: 1030: 68 00 20 40 00 pushl $4202496 +DISASM-NEXT: 1035: e8 c6 ff ff ff calll -58 <.text> +DISASM-NEXT: 103a: 5a popl %edx +DISASM-NEXT: 103b: 59 popl %ecx +DISASM-NEXT: 103c: ff e0 jmpl *%eax +DISASM-NEXT: 103e: 51 pushl %ecx +DISASM-NEXT: 103f: 52 pushl %edx +DISASM-NEXT: 1040: 68 24 30 40 00 pushl $4206628 +DISASM-NEXT: 1045: 68 00 20 40 00 pushl $4202496 +DISASM-NEXT: 104a: e8 b1 ff ff ff calll -79 <.text> +DISASM-NEXT: 104f: 5a popl %edx +DISASM-NEXT: 1050: 59 popl %ecx +DISASM-NEXT: 1051: ff e0 jmpl *%eax diff --git a/test/COFF/dll.test b/test/COFF/dll.test index abd39f4eeb24..f04e28c561bf 100644 --- a/test/COFF/dll.test +++ b/test/COFF/dll.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 \ # RUN: /export:mangled @@ -26,7 +27,7 @@ EXPORT2-NEXT: 1 0x1010 exportfn3 EXPORT2-NEXT: 2 0x101c mangled2 # RUN: llvm-as -o %t.lto.obj %p/Inputs/export.ll -# RUN: lld-link /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2 +# RUN: lld-link -opt:noicf /out:%t.lto.dll /dll %t.lto.obj /export:exportfn1 /export:exportfn2 # RUN: llvm-objdump -p %t.lto.dll | FileCheck -check-prefix=EXPORT-LTO %s EXPORT-LTO: Export Table: diff --git a/test/COFF/dllexport-mingw.s b/test/COFF/dllexport-mingw.s index 8bf035b36dcf..a96003b5ed22 100644 --- a/test/COFF/dllexport-mingw.s +++ b/test/COFF/dllexport-mingw.s @@ -1,4 +1,4 @@ -# REQEUIRES: x86 +# REQUIRES: x86 # RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj diff --git a/test/COFF/dllexport.s b/test/COFF/dllexport.s new file mode 100644 index 000000000000..78d97c978748 --- /dev/null +++ b/test/COFF/dllexport.s @@ -0,0 +1,58 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-windows-msvc %s -o %t.obj + +# RUN: lld-link -entry:dllmain -dll %t.obj -out:%t.dll -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck -check-prefix DECORATED-IMPLIB %s +# RUN: llvm-readobj -coff-exports %t.dll | FileCheck -check-prefix DECORATED-EXPORTS %s + +# DECORATED-IMPLIB: Name type: name +# DECORATED-IMPLIB-NEXT: __imp_@fastcall@8 +# DECORATED-IMPLIB-NEXT: @fastcall@8 +# DECORATED-IMPLIB: Name type: name +# DECORATED-IMPLIB-NEXT: __imp__stdcall@8 +# DECORATED-IMPLIB-NEXT: _stdcall@8 +# DECORATED-IMPLIB: Name type: noprefix +# DECORATED-IMPLIB-NEXT: __imp___underscored +# DECORATED-IMPLIB-NEXT: __underscored +# DECORATED-IMPLIB: Name type: name +# DECORATED-IMPLIB-NEXT: __imp_vectorcall@@8 +# DECORATED-IMPLIB-NEXT: vectorcall@@8 + +# DECORATED-EXPORTS: Name: @fastcall@8 +# DECORATED-EXPORTS: Name: _stdcall@8 +# DECORATED-EXPORTS: Name: _underscored +# DECORATED-EXPORTS: Name: vectorcall@@8 + + .def _stdcall@8; + .scl 2; + .type 32; + .endef + .globl _stdcall@8 + .globl @fastcall@8 + .globl vectorcall@@8 + .globl __underscored +_stdcall@8: + movl 8(%esp), %eax + addl 4(%esp), %eax + retl $8 +@fastcall@8: + movl 8(%esp), %eax + addl 4(%esp), %eax + retl $8 +vectorcall@@8: + movl 8(%esp), %eax + addl 4(%esp), %eax + retl $8 +__underscored: + ret + + .def _dllmain; + .scl 2; + .type 32; + .endef + .globl _dllmain +_dllmain: + retl + +.section .drectve +.ascii "-export:__underscored -export:_stdcall@8 -export:@fastcall@8 -export:vectorcall@@8" diff --git a/test/COFF/driver.test b/test/COFF/driver.test index 36de6c200cb1..aef7046d198b 100644 --- a/test/COFF/driver.test +++ b/test/COFF/driver.test @@ -4,3 +4,14 @@ MISSING: nosuchfile.obj: {{[Nn]}}o such file or directory # RUN: lld-link --version | FileCheck -check-prefix=VERSION %s VERSION: {{LLD [0-9]+\.[0-9]+}} + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link /out:%t.dll /dll %t.obj +# RUN: not lld-link /out:%t.exe %t.dll 2>&1 | FileCheck -check-prefix=BADFILE %s +BADFILE: bad file type. Did you specify a DLL instead of an import library? + +# RUN: lld-link /lib /help | FileCheck -check-prefix=LIBHELP %s +LIBHELP: OVERVIEW: LLVM Lib + +# RUN: not lld-link /WX /lib 2>&1 | FileCheck -check-prefix=LIBBAD %s +LIBBAD: ignoring /lib since it's not the first argument diff --git a/test/COFF/duplicate.test b/test/COFF/duplicate.test index c2f743ebc28f..e2d3181c98f2 100644 --- a/test/COFF/duplicate.test +++ b/test/COFF/duplicate.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 RUN: llc -mtriple x86_64-windows-msvc -filetype obj -o alpha.obj %S/Inputs/alpha.ll RUN: llc -mtriple x86_64-windows-msvc -filetype obj -o beta.obj %S/Inputs/beta.ll RUN: lld-link /out:alpha.dll /dll alpha.obj /implib:alpha.lib diff --git a/test/COFF/entry-inference3.test b/test/COFF/entry-inference3.test new file mode 100644 index 000000000000..7de14e10fe8d --- /dev/null +++ b/test/COFF/entry-inference3.test @@ -0,0 +1,35 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: not lld-link /out:%t.exe %t.obj /verbose /nodefaultlib > %t.log 2>&1 +# RUN: FileCheck %s < %t.log + +# CHECK: Entry name inferred: mainCRTStartup + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B82A000000C3 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: mainCRTStartup + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/error-limit.test b/test/COFF/error-limit.test index 3eebd12aaabe..09c3b9d07f30 100644 --- a/test/COFF/error-limit.test +++ b/test/COFF/error-limit.test @@ -3,27 +3,27 @@ RUN: 21 22 2>&1 | FileCheck -check-prefix=DEFAULT %s DEFAULT: could not open 01 DEFAULT: could not open 20 -DEFAULT-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors) +DEFAULT-NEXT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors) DEFAULT-NOT: could not open 21 -RUN: not lld-link /ERRORLIMIT:5 01 02 03 04 05 06 07 08 09 10 2>&1 \ +RUN: not lld-link /errorlimit:5 01 02 03 04 05 06 07 08 09 10 2>&1 \ RUN: | FileCheck -check-prefix=LIMIT5 %s LIMIT5: could not open 01 LIMIT5: could not open 05 -LIMIT5-NEXT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors) +LIMIT5-NEXT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors) LIMIT5-NOT: could not open 06 -RUN: not lld-link /ERRORLIMIT:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \ +RUN: not lld-link /errorlimit:0 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 \ RUN: 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=UNLIMITED %s UNLIMITED: could not open 01 UNLIMITED: could not open 20 UNLIMITED: could not open 21 UNLIMITED: could not open 22 -UNLIMITED-NOT: too many errors emitted, stopping now (use /ERRORLIMIT:0 to see all errors) +UNLIMITED-NOT: too many errors emitted, stopping now (use /errorlimit:0 to see all errors) -RUN: not lld-link /ERRORLIMIT:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \ +RUN: not lld-link /errorlimit:XYZ 01 02 03 04 05 06 07 08 09 10 11 12 13 14 \ RUN: 15 16 17 18 19 20 21 22 2>&1 | FileCheck -check-prefix=WRONG %s -WRONG: /ERRORLIMIT: number expected, but got XYZ +WRONG: /errorlimit: number expected, but got XYZ diff --git a/test/COFF/export-all.s b/test/COFF/export-all.s index 96c7dca5df29..5509a8dbac91 100644 --- a/test/COFF/export-all.s +++ b/test/COFF/export-all.s @@ -1,4 +1,4 @@ -# REQEUIRES: x86 +# REQUIRES: x86 # RUN: llvm-mc -triple=i686-windows-gnu %s -filetype=obj -o %t.obj diff --git a/test/COFF/export-armnt.yaml b/test/COFF/export-armnt.yaml index 367dabf70d88..88d198c59b6c 100644 --- a/test/COFF/export-armnt.yaml +++ b/test/COFF/export-armnt.yaml @@ -9,10 +9,10 @@ # CHECK: DLL name: export-armnt.yaml.tmp.dll # CHECK: Ordinal RVA Name # CHECK-NEXT: 0 0 -# CHECK-NEXT: 1 0x1000 exportdata -# CHECK-NEXT: 2 0x2005 exportfn1 -# CHECK-NEXT: 3 0x2009 exportfn2 -# CHECK-NEXT: 4 0x2009 exportfn3 +# CHECK-NEXT: 1 0x3000 exportdata +# CHECK-NEXT: 2 0x1005 exportfn1 +# CHECK-NEXT: 3 0x1009 exportfn2 +# CHECK-NEXT: 4 0x1009 exportfn3 --- !COFF header: diff --git a/test/COFF/export.test b/test/COFF/export.test index 174f4ac55d9d..a00a29c13d4c 100644 --- a/test/COFF/export.test +++ b/test/COFF/export.test @@ -86,6 +86,10 @@ SYMTAB: exportfn3 in export.test.tmp.DLL # RUN: lld-link /out:%t.dll /dll %t.obj /export:foo=kernel32.foobar # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=FORWARDER %s +# RUN: echo "EXPORTS foo=kernel32.foobar" > %t.def +# RUN: lld-link /out:%t.dll /dll %t.obj /def:%t.def +# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=FORWARDER %s + FORWARDER: Export Table: FORWARDER: DLL name: export.test.tmp.dll FORWARDER: Ordinal base: 0 diff --git a/test/COFF/export32.test b/test/COFF/export32.test index 34cd1a73319e..9218ac2829d1 100644 --- a/test/COFF/export32.test +++ b/test/COFF/export32.test @@ -2,6 +2,10 @@ # # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s +# +# RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1 /export:exportfn2 /merge:.edata=.rdata +# RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK1 %s +# RUN: llvm-readobj -file-headers -sections %t.dll | FileCheck -check-prefix=HEADER-MERGE %s # CHECK1: Export Table: # CHECK1: DLL name: export32.test.tmp.dll @@ -10,6 +14,12 @@ # CHECK1-NEXT: 1 0x1008 exportfn1 # CHECK1-NEXT: 2 0x1010 exportfn2 +# HEADER-MERGE: ExportTableRVA: 0x2000 +# HEADER-MERGE-NEXT: ExportTableSize: 0x7E +# HEADER-MERGE: Name: .rdata +# HEADER-MERGE-NEXT: VirtualSize: 0x7E +# HEADER-MERGE-NEXT: VirtualAddress: 0x2000 + # RUN: lld-link /out:%t.dll /dll %t.obj /export:exportfn1,@5 \ # RUN: /export:exportfn2 /export:mangled # RUN: llvm-objdump -p %t.dll | FileCheck -check-prefix=CHECK2 %s diff --git a/test/COFF/filename-casing.s b/test/COFF/filename-casing.s index e210aea9358a..0834c034ee74 100644 --- a/test/COFF/filename-casing.s +++ b/test/COFF/filename-casing.s @@ -6,8 +6,10 @@ # RUN: llvm-lib /out:%T/MixedCase.lib %T/MixedCase.obj # RUN: not lld-link /machine:x64 /entry:main %T/MixedCase.lib 2>&1 | FileCheck -check-prefix=ARCHIVE %s -# OBJECT: MixedCase.obj: undefined symbol: f -# ARCHIVE: MixedCase.lib(MixedCase.obj): undefined symbol: f +# OBJECT: undefined symbol: f +# OBJECT-NEXT: >>> referenced by {{.*}}MixedCase.obj:(main) +# ARCHIVE: undefined symbol: f +# ARCHIVE-NEXT: >>> referenced by {{.*}}MixedCase.lib(MixedCase.obj):(main) .globl main main: diff --git a/test/COFF/fixed.test b/test/COFF/fixed.test new file mode 100644 index 000000000000..6975fed0846b --- /dev/null +++ b/test/COFF/fixed.test @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: yaml2obj < %p/Inputs/hello32.yaml > %t.obj +# +# RUN: lld-link %t.obj /fixed %p/Inputs/std32.lib /subsystem:console \ +# RUN: /entry:main@0 /debug /out:%t.fixed.exe +# RUN: llvm-readobj -file-headers %t.fixed.exe | \ +# RUN: FileCheck -check-prefix=EXEFIXED %s +# +# RUN: lld-link %t.obj %p/Inputs/std32.lib /subsystem:console \ +# RUN: /entry:main@0 /debug /out:%t.exe +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=EXEREL %s +# +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# +# RUN: lld-link %t.obj /dll /fixed /debug /out:%t.fixed.dll +# RUN: llvm-readobj -file-headers %t.fixed.dll | FileCheck -check-prefix=DLLFIXED %s +# +# RUN: lld-link %t.obj /dll /debug /out:%t.dll +# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=DLLREL %s + +EXEFIXED-NOT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE +DLLFIXED-NOT: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE +EXEREL: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE +DLLREL: IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE diff --git a/test/COFF/force.test b/test/COFF/force.test index b96c1f84cd44..20c4e1a6457f 100644 --- a/test/COFF/force.test +++ b/test/COFF/force.test @@ -4,8 +4,10 @@ # RUN: lld-link /out:%t.exe /entry:main %t.obj /force >& %t.log # RUN: FileCheck -check-prefix=WARN %s < %t.log -# ERROR: error: {{.*}}.obj: undefined symbol: foo -# WARN: warning: {{.*}}.obj: undefined symbol: foo +# ERROR: error: undefined symbol: foo +# ERROR-NEXT: >>> referenced by {{.*}}.obj +# WARN: warning: undefined symbol: foo +# WARN-NEXT: >>> referenced by {{.*}}.obj --- !COFF header: diff --git a/test/COFF/gfids-corrupt.s b/test/COFF/gfids-corrupt.s new file mode 100644 index 000000000000..92cd321c09c1 --- /dev/null +++ b/test/COFF/gfids-corrupt.s @@ -0,0 +1,84 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -opt:noref -guard:nolongjmp -out:%t.exe -entry:main 2>&1 | FileCheck %s --check-prefix=ERRS +# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s + +# ERRS: warning: ignoring .gfids$y symbol table index section in object {{.*}}gfids-corrupt{{.*}} +# ERRS: warning: ignoring invalid symbol table index in section .gfids$y in object {{.*}}gfids-corrupt{{.*}} + +# The table is arbitrary, really. +# CHECK: ImageBase: 0x140000000 +# CHECK: LoadConfig [ +# CHECK: SEHandlerTable: 0x0 +# CHECK: SEHandlerCount: 0 +# CHECK: GuardCFCheckFunction: 0x0 +# CHECK: GuardCFCheckDispatch: 0x0 +# CHECK: GuardCFFunctionTable: 0x14000{{.*}} +# CHECK: GuardCFFunctionCount: 2 +# CHECK: GuardFlags: 0x500 +# CHECK: GuardAddressTakenIatEntryTable: 0x0 +# CHECK: GuardAddressTakenIatEntryCount: 0 +# CHECK: GuardLongJumpTargetTable: 0x0 +# CHECK: GuardLongJumpTargetCount: 0 +# CHECK: ] +# CHECK: GuardFidTable [ +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: ] + + +# Indicate that gfids are present. + .def @feat.00; .scl 3; .type 0; .endef + .globl @feat.00 +@feat.00 = 0x800 + + .def f1; .scl 2; .type 32; .endef + .section .text,"xr",one_only,f1 + .global f1 +f1: + movl $42, %eax + retq + + .def f2; .scl 2; .type 32; .endef + .section .text,"xr",one_only,f2 + .global f2 +f2: + movl $13, %eax + retq + + .section .data,"dw",one_only,fp1 + .globl fp1 +fp1: + .quad f1 + + .section .data,"dw",one_only,fp2 + .globl fp2 +fp2: + .quad f2 + + .section .gfids$y,"dr",associative,fp1 + .symidx f1 + .byte 0 + + .section .gfids$y,"dr",associative,fp2 + .symidx f2 + .long 0x400 + + .def main; .scl 2; .type 32; .endef + .section .text,"xr",one_only,main + .globl main +main: + callq *fp1(%rip) + callq *fp2(%rip) + xor %eax, %eax + retq + + .section .rdata,"dr" +.globl _load_config_used +_load_config_used: + .long 256 + .fill 124, 1, 0 + .quad __guard_fids_table + .quad __guard_fids_count + .long __guard_flags + .fill 128, 1, 0 diff --git a/test/COFF/gfids-fallback.s b/test/COFF/gfids-fallback.s new file mode 100644 index 000000000000..53fff17ce0bd --- /dev/null +++ b/test/COFF/gfids-fallback.s @@ -0,0 +1,97 @@ +# REQUIRES: x86 +# RUN: grep -B99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t1.obj +# RUN: grep -A99999 [S]PLITMARKER %s | llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t2.obj +# RUN: lld-link %t1.obj %t2.obj -guard:nolongjmp -out:%t.exe -entry:main -opt:noref +# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s + +# CHECK: ImageBase: 0x140000000 +# CHECK: LoadConfig [ +# CHECK: SEHandlerTable: 0x0 +# CHECK: SEHandlerCount: 0 +# CHECK: GuardCFCheckFunction: 0x0 +# CHECK: GuardCFCheckDispatch: 0x0 +# CHECK: GuardCFFunctionTable: 0x14000{{.*}} +# CHECK: GuardCFFunctionCount: 3 +# CHECK: GuardFlags: 0x500 +# CHECK: GuardAddressTakenIatEntryTable: 0x0 +# CHECK: GuardAddressTakenIatEntryCount: 0 +# CHECK: GuardLongJumpTargetTable: 0x0 +# CHECK: GuardLongJumpTargetCount: 0 +# CHECK: ] +# CHECK: GuardFidTable [ +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: ] + + +# Indicate that no gfids are present. All symbols used by relocations in this +# file will be considered address-taken. + .def @feat.00; .scl 3; .type 0; .endef + .globl @feat.00 +@feat.00 = 0 + + .def main; .scl 2; .type 32; .endef + .section .text,"xr",one_only,main + .globl main +main: + subq $8, %rsp + leaq foo(%rip), %rdx + callq bar + movl $0, %eax + addq $8, %rsp + retq + +# Should not appear in gfids table. + .def baz; .scl 2; .type 32; .endef + .section .text,"xr",one_only,baz + .globl baz +baz: + mov $1, %eax + retq + + .def qux; .scl 2; .type 32; .endef + .section .text,"xr",one_only,qux + .globl qux +qux: + mov $2, %eax + retq + + .def quxx; .scl 2; .type 32; .endef + .section .text,"xr",one_only,quxx + .globl quxx +quxx: + mov $3, %eax + retq + +# Load config. + .section .rdata,"dr" +.globl _load_config_used +_load_config_used: + .long 256 + .fill 124, 1, 0 + .quad __guard_fids_table + .quad __guard_fids_count + .long __guard_flags + .fill 128, 1, 0 + +# SPLITMARKER + +# Indicate that gfids are present. This file does not take any addresses. + .def @feat.00; .scl 3; .type 0; .endef + .globl @feat.00 +@feat.00 = 0x800 + + .def foo; .scl 2; .type 32; .endef + .section .text,"xr",one_only,foo + .global foo +foo: + movl $42, %eax + retq + + .def bar; .scl 2; .type 32; .endef + .section .text,"xr",one_only,bar + .global bar +bar: + movl $13, %eax + retq diff --git a/test/COFF/gfids-gc.s b/test/COFF/gfids-gc.s new file mode 100644 index 000000000000..22fdbf19ce45 --- /dev/null +++ b/test/COFF/gfids-gc.s @@ -0,0 +1,131 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main +# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC +# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:noref -entry:main -debug:dwarf +# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-NOGC +# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:ref -entry:main +# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK-GC + +# This assembly is meant to mimic what CL emits for this kind of C code when +# /Gw (-fdata-sections) is enabled: +# int f() { return 42; } +# int g() { return 13; } +# int (*fp1)() = &f; +# int (*fp2)() = &g; +# int main() { +# return fp1(); +# } +# Compile with 'cl -c -guard:cf -Gw -O1' and note the two associative .gfids$y +# sections. + +# Expect 3 entries: main, f, and g. + +# CHECK-NOGC: ImageBase: 0x140000000 +# CHECK-NOGC: LoadConfig [ +# CHECK-NOGC: SEHandlerTable: 0x0 +# CHECK-NOGC: SEHandlerCount: 0 +# CHECK-NOGC: GuardCFCheckFunction: 0x0 +# CHECK-NOGC: GuardCFCheckDispatch: 0x0 +# CHECK-NOGC: GuardCFFunctionTable: 0x14000{{.*}} +# CHECK-NOGC: GuardCFFunctionCount: 3 +# CHECK-NOGC: GuardFlags: 0x500 +# CHECK-NOGC: GuardAddressTakenIatEntryTable: 0x0 +# CHECK-NOGC: GuardAddressTakenIatEntryCount: 0 +# CHECK-NOGC: GuardLongJumpTargetTable: 0x0 +# CHECK-NOGC: GuardLongJumpTargetCount: 0 +# CHECK-NOGC: ] +# CHECK-NOGC: GuardFidTable [ +# CHECK-NOGC-NEXT: 0x14000{{.*}} +# CHECK-NOGC-NEXT: 0x14000{{.*}} +# CHECK-NOGC-NEXT: 0x14000{{.*}} +# CHECK-NOGC-NEXT: ] + +# Expect 2 entries: main and f. fp2 was discarded, so g was only used as a +# direct call target. + +# CHECK-GC: ImageBase: 0x140000000 +# CHECK-GC: LoadConfig [ +# CHECK-GC: SEHandlerTable: 0x0 +# CHECK-GC: SEHandlerCount: 0 +# CHECK-GC: GuardCFCheckFunction: 0x0 +# CHECK-GC: GuardCFCheckDispatch: 0x0 +# CHECK-GC: GuardCFFunctionTable: 0x14000{{.*}} +# CHECK-GC: GuardCFFunctionCount: 2 +# CHECK-GC: GuardFlags: 0x500 +# CHECK-GC: GuardAddressTakenIatEntryTable: 0x0 +# CHECK-GC: GuardAddressTakenIatEntryCount: 0 +# CHECK-GC: GuardLongJumpTargetTable: 0x0 +# CHECK-GC: GuardLongJumpTargetCount: 0 +# CHECK-GC: ] +# CHECK-GC: GuardFidTable [ +# CHECK-GC-NEXT: 0x14000{{.*}} +# CHECK-GC-NEXT: 0x14000{{.*}} +# CHECK-GC-NEXT: ] + + +# We need @feat.00 to have 0x800 to indicate .gfids are present. + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +@feat.00 = 0x801 + + .def main; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,main + .globl main +main: + # Call g directly so that it is not dead stripped. + callq g + rex64 jmpq *fp1(%rip) + + .def f; + .scl 3; + .type 32; + .endef + .section .text,"xr",one_only,f +f: + movl $42, %eax + retq + + .section .data,"dw",one_only,fp1 + .globl fp1 +fp1: + .quad f + + .section .gfids$y,"dr",associative,fp1 + .symidx f + +# Section GC will remove the following, so 'g' should not be present in the +# guard fid table. + + .def g; + .scl 3; + .type 32; + .endef + .section .text,"xr",one_only,g +g: + movl $13, %eax + retq + + .section .data,"dw",one_only,fp2 + .globl fp2 +fp2: + .quad g + + .section .gfids$y,"dr",associative,fp2 + .symidx g + + .section .rdata,"dr" +.globl _load_config_used +_load_config_used: + .long 256 + .fill 124, 1, 0 + .quad __guard_fids_table + .quad __guard_fids_count + .long __guard_flags + .fill 128, 1, 0 diff --git a/test/COFF/gfids-icf.s b/test/COFF/gfids-icf.s new file mode 100644 index 000000000000..b0b4d7019fc1 --- /dev/null +++ b/test/COFF/gfids-icf.s @@ -0,0 +1,88 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -guard:nolongjmp -out:%t.exe -opt:icf -entry:main +# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s --check-prefix=CHECK + +# This assembly is meant to mimic what CL emits for this kind of C code: +# int icf1() { return 42; } +# int icf2() { return 42; } +# int (*fp1)() = &icf1; +# int (*fp2)() = &icf2; +# int main() { +# return fp1(); +# return fp2(); +# } + +# 'icf1' and 'icf2' are address taken, but should be merged into one entry. +# There are two entries in the table because 'main' is included. + +# CHECK: ImageBase: 0x140000000 +# CHECK: LoadConfig [ +# CHECK: SEHandlerTable: 0x0 +# CHECK: SEHandlerCount: 0 +# CHECK: GuardCFCheckFunction: 0x0 +# CHECK: GuardCFCheckDispatch: 0x0 +# CHECK: GuardCFFunctionTable: 0x14000{{.*}} +# CHECK: GuardCFFunctionCount: 2 +# CHECK: GuardFlags: 0x500 +# CHECK: GuardAddressTakenIatEntryTable: 0x0 +# CHECK: GuardAddressTakenIatEntryCount: 0 +# CHECK: GuardLongJumpTargetTable: 0x0 +# CHECK: GuardLongJumpTargetCount: 0 +# CHECK: ] +# CHECK: GuardFidTable [ +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: ] + + +# Indicate that gfids are present. + .def @feat.00; .scl 3; .type 0; .endef + .globl @feat.00 +@feat.00 = 0x800 + + .def icf1; .scl 2; .type 32; .endef + .section .text,"xr",one_only,icf1 + .global icf1 +icf1: + movl $42, %eax + retq + + .def icf2; .scl 2; .type 32; .endef + .section .text,"xr",one_only,icf2 + .global icf2 +icf2: + movl $42, %eax + retq + +# Take their two addresses. + .data + .globl fp1 +fp1: + .quad icf1 + .globl fp2 +fp2: + .quad icf2 + + .section .gfids$y,"dr" + .symidx icf1 + .symidx icf2 + + .def main; .scl 2; .type 32; .endef + .section .text,"xr",one_only,main + .globl main +main: + callq *fp1(%rip) + callq *fp2(%rip) + xor %eax, %eax + retq + + .section .rdata,"dr" +.globl _load_config_used +_load_config_used: + .long 256 + .fill 124, 1, 0 + .quad __guard_fids_table + .quad __guard_fids_count + .long __guard_flags + .fill 128, 1, 0 diff --git a/test/COFF/guard-longjmp.s b/test/COFF/guard-longjmp.s new file mode 100644 index 000000000000..a6d115d3ed39 --- /dev/null +++ b/test/COFF/guard-longjmp.s @@ -0,0 +1,104 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple x86_64-windows-msvc %s -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -guard:cf -out:%t.exe -entry:main +# RUN: llvm-readobj -file-headers -coff-load-config %t.exe | FileCheck %s + +# CHECK: ImageBase: 0x140000000 +# CHECK: LoadConfig [ +# CHECK: SEHandlerTable: 0x0 +# CHECK: SEHandlerCount: 0 +# CHECK: GuardCFCheckFunction: 0x0 +# CHECK: GuardCFCheckDispatch: 0x0 +# CHECK: GuardCFFunctionTable: 0x14000{{.*}} +# CHECK: GuardCFFunctionCount: 1 +# CHECK: GuardFlags: 0x10500 +# CHECK: GuardAddressTakenIatEntryTable: 0x0 +# CHECK: GuardAddressTakenIatEntryCount: 0 +# CHECK: GuardLongJumpTargetTable: 0x14000{{.*}} +# CHECK: GuardLongJumpTargetCount: 1 +# CHECK: ] +# CHECK: GuardLJmpTable [ +# CHECK-NEXT: 0x14000{{.*}} +# CHECK-NEXT: ] + + +# This assembly is reduced from C code like: +# #include <setjmp.h> +# jmp_buf buf; +# void g() { longjmp(buf, 1); } +# void f() { +# if (setjmp(buf)) +# return; +# g(); +# } +# int main() { f(); } + +# We need @feat.00 to have 0x800 to indicate /guard:cf. + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +@feat.00 = 0x801 + .def f; .scl 2; .type 32; .endef + .globl f +f: + pushq %rbp + subq $32, %rsp + leaq 32(%rsp), %rbp + leaq buf(%rip), %rcx + leaq -32(%rbp), %rdx + callq _setjmp +.Lljmp1: + testl %eax, %eax + je .LBB1_1 + addq $32, %rsp + popq %rbp + retq +.LBB1_1: # %if.end + leaq buf(%rip), %rcx + movl $1, %edx + callq longjmp + ud2 + + # Record the longjmp target. + .section .gljmp$y,"dr" + .symidx .Lljmp1 + .text + + # Provide setjmp/longjmp stubs. + .def _setjmp; .scl 2; .type 32; .endef + .globl _setjmp +_setjmp: + retq + + .def longjmp; .scl 2; .type 32; .endef + .globl longjmp +longjmp: + retq + + .def main; .scl 2; .type 32; .endef + .globl main # -- Begin function main +main: # @main + subq $40, %rsp + callq f + xorl %eax, %eax + addq $40, %rsp + retq + + .comm buf,256,4 # @buf + + .section .rdata,"dr" +.globl _load_config_used +_load_config_used: + .long 256 + .fill 124, 1, 0 + .quad __guard_fids_table + .quad __guard_fids_count + .long __guard_flags + .fill 12, 1, 0 + .quad __guard_iat_table + .quad __guard_iat_count + .quad __guard_longjmp_table + .quad __guard_fids_count + .fill 84, 1, 0 diff --git a/test/COFF/guardcf-align.s b/test/COFF/guardcf-align.s new file mode 100644 index 000000000000..a0caabc92b0d --- /dev/null +++ b/test/COFF/guardcf-align.s @@ -0,0 +1,45 @@ +# RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj -o %t.obj %s +# RUN: yaml2obj < %p/Inputs/guardcf-align-foobar.yaml \ +# RUN: > %T/guardcf-align-foobar.obj +# RUN: lld-link -out:%T/guardcf-align.exe -entry:main -guard:cf \ +# RUN: %t.obj %T/guardcf-align-foobar.obj +# RUN: llvm-readobj -coff-load-config %T/guardcf-align.exe | FileCheck %s + +# Check that the gfids table contains at least one entry that ends in 0 +# and no entries that end in something other than 0. +# CHECK: GuardFidTable [ +# CHECK-NOT: 0x{{[0-9A-Fa-f]+[^0]$}} +# CHECK: 0x{{[0-9A-Fa-f]+0$}} +# CHECK-NOT: 0x{{[0-9A-Fa-f]+[^0]$}} +# CHECK: ] + +# @feat.00 and _load_config_used to indicate we have gfids. + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +@feat.00 = 0x801 + + .section .rdata,"dr" +.globl _load_config_used +_load_config_used: + .long 256 + .fill 124, 1, 0 + .quad __guard_fids_table + .quad __guard_fids_count + .long __guard_flags + .fill 128, 1, 0 + +# Functions that are called indirectly. + .section .gfids$y,"dr" + .symidx foo + + + .section .text,"rx" + .global main +main: + movq foo, %rcx + xorq %rax, %rax + callq bar + retq diff --git a/test/COFF/guardcf-lto.ll b/test/COFF/guardcf-lto.ll new file mode 100644 index 000000000000..8ab3e1e04f83 --- /dev/null +++ b/test/COFF/guardcf-lto.ll @@ -0,0 +1,40 @@ +; REQUIRES: x86 +; Set up an import library for a DLL that will do the indirect call. +; RUN: echo -e 'LIBRARY library\nEXPORTS\n do_indirect_call\n' > %t.def +; RUN: lld-link -lib -def:%t.def -out:%t.lib -machine:x64 + +; Generate an object that will have the load configuration normally provided by +; the CRT. +; RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %S/Inputs/loadconfig-cfg-x64.s -o %t.ldcfg.obj + +; RUN: llvm-as %s -o %t.bc +; RUN: lld-link -entry:main -guard:cf -dll %t.bc %t.lib %t.ldcfg.obj -out:%t.dll +; RUN: llvm-readobj -coff-load-config %t.dll | FileCheck %s + +; There must be *two* entries in the table: DLL entry point, and my_handler. + +; CHECK: LoadConfig [ +; CHECK: GuardCFFunctionTable: 0x{{[^0].*}} +; CHECK-NEXT: GuardCFFunctionCount: 2 +; CHECK-NEXT: GuardFlags: 0x10500 +; CHECK: ] +; CHECK: GuardFidTable [ +; CHECK-NEXT: 0x180{{.*}} +; CHECK-NEXT: 0x180{{.*}} +; CHECK-NEXT: ] + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.12.25835" + +declare dllimport void @do_indirect_call(void ()*) + +define dso_local i32 @main() local_unnamed_addr { +entry: + tail call void @do_indirect_call(void ()* nonnull @my_handler) + ret i32 0 +} + +define dso_local void @my_handler() { +entry: + ret void +} diff --git a/test/COFF/hello32.test b/test/COFF/hello32.test index 2399193da6a1..87c58797a901 100644 --- a/test/COFF/hello32.test +++ b/test/COFF/hello32.test @@ -11,7 +11,7 @@ HEADER-NEXT: AddressSize: 32bit HEADER-NEXT: ImageFileHeader { HEADER-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) HEADER-NEXT: SectionCount: 4 -HEADER-NEXT: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +HEADER-NEXT: TimeDateStamp: HEADER-NEXT: PointerToSymbolTable: 0x0 HEADER-NEXT: SymbolCount: 0 HEADER-NEXT: OptionalHeaderSize: 224 @@ -27,8 +27,8 @@ HEADER-NEXT: MinorLinkerVersion: 0 HEADER-NEXT: SizeOfCode: 512 HEADER-NEXT: SizeOfInitializedData: 1536 HEADER-NEXT: SizeOfUninitializedData: 0 -HEADER-NEXT: AddressOfEntryPoint: 0x2000 -HEADER-NEXT: BaseOfCode: 0x2000 +HEADER-NEXT: AddressOfEntryPoint: 0x1000 +HEADER-NEXT: BaseOfCode: 0x1000 HEADER-NEXT: BaseOfData: 0x0 HEADER-NEXT: ImageBase: 0x400000 HEADER-NEXT: SectionAlignment: 4096 @@ -40,7 +40,7 @@ HEADER-NEXT: MinorImageVersion: 0 HEADER-NEXT: MajorSubsystemVersion: 6 HEADER-NEXT: MinorSubsystemVersion: 0 HEADER-NEXT: SizeOfImage: 20480 -HEADER-NEXT: SizeOfHeaders: 512 +HEADER-NEXT: SizeOfHeaders: 1024 HEADER-NEXT: Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI (0x3) HEADER-NEXT: Characteristics [ (0x9540) HEADER-NEXT: IMAGE_DLL_CHARACTERISTICS_APPCONTAINER (0x1000) @@ -57,7 +57,7 @@ HEADER-NEXT: NumberOfRvaAndSize: 16 HEADER-NEXT: DataDirectory { HEADER-NEXT: ExportTableRVA: 0x0 HEADER-NEXT: ExportTableSize: 0x0 -HEADER-NEXT: ImportTableRVA: 0x3000 +HEADER-NEXT: ImportTableRVA: 0x2000 HEADER-NEXT: ImportTableSize: 0x28 HEADER-NEXT: ResourceTableRVA: 0x0 HEADER-NEXT: ResourceTableSize: 0x0 @@ -79,7 +79,7 @@ HEADER-NEXT: LoadConfigTableRVA: 0x0 HEADER-NEXT: LoadConfigTableSize: 0x0 HEADER-NEXT: BoundImportRVA: 0x0 HEADER-NEXT: BoundImportSize: 0x0 -HEADER-NEXT: IATRVA: 0x3034 +HEADER-NEXT: IATRVA: 0x2034 HEADER-NEXT: IATSize: 0xC HEADER-NEXT: DelayImportDescriptorRVA: 0x0 HEADER-NEXT: DelayImportDescriptorSize: 0x0 @@ -91,10 +91,10 @@ HEADER-NEXT: } HEADER-NEXT: } HEADER-NEXT: DOSHeader { HEADER-NEXT: Magic: MZ -HEADER-NEXT: UsedBytesInTheLastPage: 0 -HEADER-NEXT: FileSizeInPages: 0 +HEADER-NEXT: UsedBytesInTheLastPage: 120 +HEADER-NEXT: FileSizeInPages: 1 HEADER-NEXT: NumberOfRelocationItems: 0 -HEADER-NEXT: HeaderSizeInParagraphs: 0 +HEADER-NEXT: HeaderSizeInParagraphs: 4 HEADER-NEXT: MinimumExtraParagraphs: 0 HEADER-NEXT: MaximumExtraParagraphs: 0 HEADER-NEXT: InitialRelativeSS: 0 @@ -106,7 +106,7 @@ HEADER-NEXT: AddressOfRelocationTable: 64 HEADER-NEXT: OverlayNumber: 0 HEADER-NEXT: OEMid: 0 HEADER-NEXT: OEMinfo: 0 -HEADER-NEXT: AddressOfNewExeHeader: 64 +HEADER-NEXT: AddressOfNewExeHeader: 120 HEADER-NEXT: } IMPORTS: Format: COFF-i386 @@ -114,8 +114,8 @@ IMPORTS: Arch: i386 IMPORTS: AddressSize: 32bit IMPORTS: Import { IMPORTS: Name: std32.dll -IMPORTS: ImportLookupTableRVA: 0x3028 -IMPORTS: ImportAddressTableRVA: 0x3034 +IMPORTS: ImportLookupTableRVA: 0x2028 +IMPORTS: ImportAddressTableRVA: 0x2034 IMPORTS: Symbol: ExitProcess (0) IMPORTS: Symbol: MessageBoxA (1) IMPORTS: } @@ -123,10 +123,10 @@ IMPORTS: } BASEREL: BaseReloc [ BASEREL: Entry { BASEREL: Type: HIGHLOW -BASEREL: Address: 0x2005 +BASEREL: Address: 0x1005 BASEREL: } BASEREL: Entry { BASEREL: Type: HIGHLOW -BASEREL: Address: 0x200C +BASEREL: Address: 0x100C BASEREL: } BASEREL: ] diff --git a/test/COFF/icf-different-align.test b/test/COFF/icf-different-align.test index 3502ed3449a4..0e2fce9f65dc 100644 --- a/test/COFF/icf-different-align.test +++ b/test/COFF/icf-different-align.test @@ -2,9 +2,14 @@ # RUN: lld-link /entry:foo /out:%t.exe /subsystem:console /include:bar \ # RUN: /verbose %t.obj > %t.log 2>&1 # RUN: FileCheck %s < %t.log +# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=OBJDUMP %s -# CHECK-NOT: Selected foo -# CHECK-NOT: Removed bar +# CHECK: Selected foo +# CHECK: Removed bar + +# OBJDUMP: Contents of section .text: +# OBJDUMP-NEXT: 140001000 00cccccc cccccccc cccccccc cccccccc +# OBJDUMP-NEXT: 140001010 4883ec28 e8000000 004883c4 28c3 --- !COFF header: @@ -19,6 +24,10 @@ sections: Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] Alignment: 16 SectionData: 4883EC28E8000000004883C428C3 + - Name: '.text' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 00 symbols: - Name: '.text$mn' Value: 0 diff --git a/test/COFF/icf-executable.s b/test/COFF/icf-executable.s index 7f923d25ca45..461439d72c1f 100644 --- a/test/COFF/icf-executable.s +++ b/test/COFF/icf-executable.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -triple=x86_64-windows-msvc %s -filetype=obj -o %t.obj # RUN: lld-link -entry:main %t.obj -out:%t.exe -verbose 2>&1 | FileCheck %s diff --git a/test/COFF/icf-pdata.s b/test/COFF/icf-pdata.s new file mode 100644 index 000000000000..8f5b3baece7d --- /dev/null +++ b/test/COFF/icf-pdata.s @@ -0,0 +1,98 @@ +# REQUIRES: x86 +# RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata +# RUN: llvm-readobj -sections -coff-exports %t.dll | FileCheck %s + +# CHECK: Name: .pdata +# CHECK-NEXT: VirtualSize: 0x18 +# CHECK: Name: .xdata +# CHECK-NEXT: VirtualSize: 0x10 + +# CHECK: Name: xdata1 +# CHECK-NEXT: RVA: 0x1010 +# CHECK: Name: xdata1a +# CHECK-NEXT: RVA: 0x1010 +# CHECK: Name: xdata1b +# CHECK-NEXT: RVA: 0x1030 + + .text +callee: + ret + + .def xdata1; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata1 + .globl xdata1 # -- Begin function xdata1 + .p2align 4, 0x90 +xdata1: # @xdata1 +.seh_proc xdata1 +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata1 + .seh_endproc + # -- End function + +# xdata1a is identical to xdata1, so it should be ICFd, and so should its pdata. +# It also has associative debug and CFG sections which should be ignored by ICF. + .def xdata1a; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata1a + .globl xdata1a # -- Begin function xdata1a + .p2align 4, 0x90 +xdata1a: # @xdata1a +.seh_proc xdata1a +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 40 + .seh_endprologue + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata1a + .seh_endproc + + .section .debug$S,"r",associative,xdata1a + .section .gfids$y,"r",associative,xdata1a + .section .gljmp$y,"r",associative,xdata1a + +# xdata1b's text is identical to xdata1, but its xdata specifies a different +# stack size, so it cannot be ICFd with xdata1. + .def xdata1b; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,xdata1b + .globl xdata1b # -- Begin function xdata1b + .p2align 4, 0x90 +xdata1b: # @xdata1b +.seh_proc xdata1b +# BB#0: # %entry + subq $40, %rsp + .seh_stackalloc 48 + .seh_endprologue + callq callee + nop + addq $40, %rsp + jmp callee # TAILCALL + .seh_handlerdata + .section .text,"xr",one_only,xdata1b + .seh_endproc + # -- End function + + .section .drectve,"yn" + .ascii " -export:xdata1" + .ascii " -export:xdata1a" + .ascii " -export:xdata1b" diff --git a/test/COFF/icf-simple.test b/test/COFF/icf-simple.test index ead7e7679ce6..19f13c6065fa 100644 --- a/test/COFF/icf-simple.test +++ b/test/COFF/icf-simple.test @@ -23,6 +23,11 @@ # RUN: /include:bar /verbose %t.obj > %t.log 2>&1 # RUN: FileCheck -check-prefix=NOICF %s < %t.log +# /profile disables ICF. +# RUN: lld-link /profile /entry:foo /out:%t.exe /subsystem:console \ +# RUN: /include:bar /verbose %t.obj > %t.log 2>&1 +# RUN: FileCheck -check-prefix=NOICF %s < %t.log + # /opt:noref disables ICF. # RUN: lld-link /opt:noref /entry:foo /out:%t.exe /subsystem:console \ # RUN: /include:bar /verbose %t.obj > %t.log 2>&1 diff --git a/test/COFF/icf-vtables.s b/test/COFF/icf-vtables.s new file mode 100644 index 000000000000..650024763610 --- /dev/null +++ b/test/COFF/icf-vtables.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s +# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console +# RUN: llvm-objdump -s %t.exe | FileCheck %s + +# CHECK: Contents of section .text: +.globl main +main: +# CHECK-NEXT: 140001000 00200040 01000000 01200040 01000000 +.8byte "??_" +.8byte "??_7" +# CHECK-NEXT: 140001010 01200040 01000000 +.8byte "??_7a" + +.section .rdata,"dr",discard,"??_" +.globl "??_" +"??_": +.byte 42 + +.section .rdata,"dr",discard,"??_7" +.globl "??_7" +"??_7": +.byte 42 + +.section .rdata,"dr",discard,"??_7a" +.globl "??_7a" +"??_7a": +.byte 42 diff --git a/test/COFF/icf-xdata.s b/test/COFF/icf-xdata.s index 8fb4bad057bd..f2b6c3df6c61 100644 --- a/test/COFF/icf-xdata.s +++ b/test/COFF/icf-xdata.s @@ -1,13 +1,26 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -triple x86_64-windows-msvc -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -dll -noentry -out:%t.dll -merge:.xdata=.xdata 2>&1 \ +# RUN: | FileCheck %s --check-prefix=WARN +# RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=XDATA # RUN: lld-link %t.obj -dll -noentry -out:%t.dll -# RUN: llvm-readobj -sections %t.dll | FileCheck %s +# RUN: llvm-readobj -sections %t.dll | FileCheck %s --check-prefix=RDATA # There shouldn't be much xdata, because all three .pdata entries (12 bytes # each) should use the same .xdata unwind info. -# CHECK: Name: .pdata -# CHECK-NEXT: VirtualSize: 0x24 -# CHECK: Name: .xdata -# CHECK-NEXT: VirtualSize: 0x8 +# XDATA: Name: .rdata +# XDATA-NEXT: VirtualSize: 0x73 +# XDATA: Name: .pdata +# XDATA-NEXT: VirtualSize: 0x24 +# XDATA: Name: .xdata +# XDATA-NEXT: VirtualSize: 0x8 +# +# WARN: warning: .xdata=.rdata: already merged into .xdata +# +# RDATA: Name: .rdata +# RDATA-NEXT: VirtualSize: 0x7C +# RDATA: Name: .pdata +# RDATA-NEXT: VirtualSize: 0x24 .text callee: diff --git a/test/COFF/implib-name.test b/test/COFF/implib-name.test index 81b5b258483f..4a875ab24b74 100644 --- a/test/COFF/implib-name.test +++ b/test/COFF/implib-name.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: mkdir -p %T # RUN: llvm-mc -triple x86_64-unknown-windows-msvc -filetype obj -o %T/object.obj %S/Inputs/object.s diff --git a/test/COFF/imports.test b/test/COFF/imports.test index 326bfbebbb05..64f3900a1c2f 100644 --- a/test/COFF/imports.test +++ b/test/COFF/imports.test @@ -15,8 +15,8 @@ TEXT: Disassembly of section .text: TEXT-NEXT: .text: TEXT-NEXT: subq $40, %rsp TEXT-NEXT: movq $0, %rcx -TEXT-NEXT: leaq -4108(%rip), %rdx -TEXT-NEXT: leaq -4121(%rip), %r8 +TEXT-NEXT: leaq 8180(%rip), %rdx +TEXT-NEXT: leaq 8167(%rip), %r8 TEXT-NEXT: movl $0, %r9d TEXT-NEXT: callq 60 TEXT-NEXT: movl $0, %ecx @@ -28,8 +28,8 @@ TEXT: jmpq *4082(%rip) IMPORT: Import { IMPORT-NEXT: Name: std64.dll -IMPORT-NEXT: ImportLookupTableRVA: 0x3028 -IMPORT-NEXT: ImportAddressTableRVA: 0x3048 +IMPORT-NEXT: ImportLookupTableRVA: 0x2028 +IMPORT-NEXT: ImportAddressTableRVA: 0x2048 IMPORT-NEXT: Symbol: ExitProcess (0) IMPORT-NEXT: Symbol: (50) IMPORT-NEXT: Symbol: MessageBoxA (1) diff --git a/test/COFF/incremental.test b/test/COFF/incremental.test new file mode 100644 index 000000000000..01f27487da3c --- /dev/null +++ b/test/COFF/incremental.test @@ -0,0 +1,100 @@ +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj + +# RUN: lld-link -out:%t.dll -dll %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -incremental %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=WARN-REF %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=KEEP %s + +# RUN: lld-link -out:%t.dll -dll -debug %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=KEEP %s + +# RUN: lld-link -out:%t.dll -dll -debug -incremental:no %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug -incremental:no %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -opt:icf %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -opt:icf %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,icf %t.obj 2>&1 \ +# RUN: | FileCheck -check-prefix=WARN-ICF %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,icf %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -debug -opt:icf %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug -opt:icf %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -opt:ref %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -opt:ref %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -incremental -opt:ref %t.obj 2>&1 \ +# RUN: | FileCheck -check-prefix=WARN-REF %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental -opt:ref %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: touch %t.order +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj \ +# RUN: -order:@%t.order 2>&1 | FileCheck -check-prefix=WARN-ORDER %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf -order:@%t.order %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf %t.obj \ +# RUN: -order:@%t.order 2>&1 | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf -order:@%t.order %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf %t.obj \ +# RUN: -profile 2>&1 | FileCheck -check-prefix=WARN-PROFILE %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental -opt:noref,noicf -profile %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf %t.obj \ +# RUN: -profile 2>&1 | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -opt:noref,noicf -profile %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: lld-link -out:%t.dll -dll -debug -opt:ref %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug -opt:ref %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# NOWARN-NOT: ignoring '/incremental' +# WARN-ICF: ignoring '/incremental' because ICF is enabled; use '/opt:noicf' to disable +# WARN-REF: ignoring '/incremental' because REF is enabled; use '/opt:noref' to disable +# WARN-ORDER: ignoring '/incremental' due to '/order' specification +# WARN-PROFILE: ignoring '/incremental' due to '/profile' specification +# KEEP: {{Feb 1 1980|1980-02-01}} +# NOKEEP-NOT: {{Feb 1 1980|1980-02-01}} diff --git a/test/COFF/invalid-section-number.test b/test/COFF/invalid-section-number.test new file mode 100644 index 000000000000..bada902d7bc0 --- /dev/null +++ b/test/COFF/invalid-section-number.test @@ -0,0 +1,34 @@ +# RUN: yaml2obj %s > %t.obj +# RUN: not lld-link %t.obj 2>&1 | FileCheck %s + +# CHECK: foo should not refer to special section -10 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: B82A000000C3 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 6 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: foo + Value: 0 + SectionNumber: -10 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/largeaddressaware.test b/test/COFF/largeaddressaware.test index d035e7ce9993..76aadee6a946 100644 --- a/test/COFF/largeaddressaware.test +++ b/test/COFF/largeaddressaware.test @@ -9,7 +9,7 @@ HEADER-NEXT: AddressSize: 32bit HEADER-NEXT: ImageFileHeader { HEADER-NEXT: Machine: IMAGE_FILE_MACHINE_I386 (0x14C) HEADER-NEXT: SectionCount: 4 -HEADER-NEXT: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +HEADER-NEXT: TimeDateStamp: HEADER-NEXT: PointerToSymbolTable: 0x0 HEADER-NEXT: SymbolCount: 0 HEADER-NEXT: OptionalHeaderSize: 224 diff --git a/test/COFF/loadcfg.ll b/test/COFF/loadcfg.ll index c49ae2f6ebd5..6c1cf69e8728 100644 --- a/test/COFF/loadcfg.ll +++ b/test/COFF/loadcfg.ll @@ -1,8 +1,9 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s ; RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console ; RUN: llvm-readobj -file-headers %t.exe | FileCheck %s -; CHECK: LoadConfigTableRVA: 0x1000 +; CHECK: LoadConfigTableRVA: 0x2000 ; CHECK: LoadConfigTableSize: 0x70 target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/COFF/loadcfg.test b/test/COFF/loadcfg.test index 072ee6b1edb8..2e226f439415 100644 --- a/test/COFF/loadcfg.test +++ b/test/COFF/loadcfg.test @@ -2,7 +2,7 @@ # RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s -# CHECK: LoadConfigTableRVA: 0x1000 +# CHECK: LoadConfigTableRVA: 0x2000 # CHECK: LoadConfigTableSize: 0x70 --- !COFF diff --git a/test/COFF/loadcfg32.test b/test/COFF/loadcfg32.test index 03a066c1e552..9485aa08820d 100644 --- a/test/COFF/loadcfg32.test +++ b/test/COFF/loadcfg32.test @@ -2,7 +2,7 @@ # RUN: lld-link /out:%t.exe %t.obj /entry:main /subsystem:console # RUN: llvm-readobj -file-headers %t.exe | FileCheck %s -# CHECK: LoadConfigTableRVA: 0x1000 +# CHECK: LoadConfigTableRVA: 0x2000 # CHECK: LoadConfigTableSize: 0x40 --- !COFF diff --git a/test/COFF/lto-chkstk.ll b/test/COFF/lto-chkstk.ll index 43b0bff164e3..cf831615ec52 100644 --- a/test/COFF/lto-chkstk.ll +++ b/test/COFF/lto-chkstk.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s ; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-foo.obj %S/Inputs/lto-chkstk-foo.s ; RUN: llvm-mc -triple=x86_64-pc-windows-msvc -filetype=obj -o %T/lto-chkstk-chkstk.obj %S/Inputs/lto-chkstk-chkstk.s diff --git a/test/COFF/lto-comdat.ll b/test/COFF/lto-comdat.ll index b255f69d1ab5..c5c1d7ba0a4f 100644 --- a/test/COFF/lto-comdat.ll +++ b/test/COFF/lto-comdat.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %T/comdat-main.lto.obj %s ; RUN: llvm-as -o %T/comdat1.lto.obj %S/Inputs/lto-comdat1.ll ; RUN: llvm-as -o %T/comdat2.lto.obj %S/Inputs/lto-comdat2.ll @@ -45,25 +46,24 @@ ; TEXT-11-NEXT: xorl %eax, %eax ; TEXT-11-NEXT: retq -; HEADERS-01: AddressOfEntryPoint: 0x2000 +; HEADERS-01: AddressOfEntryPoint: 0x1000 ; TEXT-01: Disassembly of section .text: ; TEXT-01-NEXT: .text: ; TEXT-01-NEXT: subq $40, %rsp -; TEXT-01-NEXT: callq 39 -; TEXT-01-NEXT: callq 50 +; TEXT-01-NEXT: callq 23 +; TEXT-01-NEXT: callq 18 ; TEXT-01-NEXT: callq 13 ; TEXT-01-NEXT: xorl %eax, %eax ; TEXT-01-NEXT: addq $40, %rsp ; TEXT-01: retq ; TEXT-01-NOT: callq ; TEXT-01: retq -; TEXT-01-NOT: callq -; TEXT-01: retq -; TEXT-01-NOT: callq -; TEXT-01: retq +; TEXT-01: int3 +; TEXT-01: int3 +; TEXT-01: int3 ; TEXT-01-NOT: {{.}} -; HEADERS-10: AddressOfEntryPoint: 0x2020 +; HEADERS-10: AddressOfEntryPoint: 0x1020 ; TEXT-10: Disassembly of section .text: ; TEXT-10-NEXT: .text: ; TEXT-10-NEXT: subq $40, %rsp diff --git a/test/COFF/lto-icf.ll b/test/COFF/lto-icf.ll new file mode 100644 index 000000000000..b36b572eb889 --- /dev/null +++ b/test/COFF/lto-icf.ll @@ -0,0 +1,27 @@ +; REQUIRES: x86 +; Test that ICF works after LTO, i.e. both functions have the same address. +; Previously, when we didn't enable function sections, ICF didn't work. + +; RUN: llvm-as %s -o %t.bc +; RUN: lld-link -opt:icf -dll -noentry %t.bc -out:%t.dll +; RUN: llvm-readobj -coff-exports %t.dll | FileCheck %s + +; CHECK: Export { +; CHECK: Export { +; CHECK: RVA: 0x[[RVA:.*]] +; CHECK: Export { +; CHECK: RVA: 0x[[RVA]] +; CHECK-NOT: Export + +target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-pc-windows-msvc19.12.25835" + +define dllexport i8* @icf_ptr() { +entry: + ret i8* null +} + +define dllexport i64 @icf_int() { +entry: + ret i64 0 +} diff --git a/test/COFF/lto-lazy-reference.ll b/test/COFF/lto-lazy-reference.ll index 22f953975682..1e92873776c1 100644 --- a/test/COFF/lto-lazy-reference.ll +++ b/test/COFF/lto-lazy-reference.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llc -mtriple=i686-pc-windows-msvc -filetype=obj -o %T/lto-lazy-reference-quadruple.obj %S/Inputs/lto-lazy-reference-quadruple.ll ; RUN: llvm-as -o %T/lto-lazy-reference-dummy.bc %S/Inputs/lto-lazy-reference-dummy.ll ; RUN: rm -f %t.lib diff --git a/test/COFF/lto-linker-opts.ll b/test/COFF/lto-linker-opts.ll index 1d788754a773..1fc4f5eb0484 100644 --- a/test/COFF/lto-linker-opts.ll +++ b/test/COFF/lto-linker-opts.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %T/lto-linker-opts.obj %s ; RUN: env LIB=%S/Inputs lld-link /out:%T/lto-linker-opts.exe /entry:main /subsystem:console %T/lto-linker-opts.obj diff --git a/test/COFF/lto-new-symbol.ll b/test/COFF/lto-new-symbol.ll index d9e14eb93264..5223f73f07fa 100644 --- a/test/COFF/lto-new-symbol.ll +++ b/test/COFF/lto-new-symbol.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s ; RUN: lld-link /out:%t.exe /entry:foo /subsystem:console %t.obj diff --git a/test/COFF/lto-opt-level.ll b/test/COFF/lto-opt-level.ll index cacd0637731a..92f88ea9e98d 100644 --- a/test/COFF/lto-opt-level.ll +++ b/test/COFF/lto-opt-level.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s ; RUN: lld-link /out:%t0.exe /entry:main /subsystem:console /opt:lldlto=0 /lldmap:%t0.map %t.obj ; RUN: FileCheck --check-prefix=CHECK-O0 %s < %t0.map diff --git a/test/COFF/lto-parallel.ll b/test/COFF/lto-parallel.ll index 449e3a01a853..7a38a39d77d9 100644 --- a/test/COFF/lto-parallel.ll +++ b/test/COFF/lto-parallel.ll @@ -1,11 +1,13 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t.obj %s -; RUN: lld-link /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=2 /subsystem:console /lldmap:%t.map %t.obj +; RUN: lld-link -opt:noicf /out:%t.exe /entry:foo /include:bar /opt:lldltopartitions=2 /subsystem:console /lldmap:%t.map %t.obj ; RUN: FileCheck %s < %t.map target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-windows-msvc" ; CHECK: lto.tmp +; CHECK: lto.tmp ; CHECK-NEXT: foo define void @foo() { call void @bar() @@ -13,6 +15,7 @@ define void @foo() { } ; CHECK: lto.tmp +; CHECK: lto.tmp ; CHECK: bar define void @bar() { call void @foo() diff --git a/test/COFF/lto-reloc-model.ll b/test/COFF/lto-reloc-model.ll index bea19e9ce3e9..9ac32ae3677f 100644 --- a/test/COFF/lto-reloc-model.ll +++ b/test/COFF/lto-reloc-model.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %t %s ; RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t ; RUN: llvm-objdump -d %t.exe | FileCheck %s diff --git a/test/COFF/lto.ll b/test/COFF/lto.ll index 587ca5ddcf13..c83a151f115b 100644 --- a/test/COFF/lto.ll +++ b/test/COFF/lto.ll @@ -1,3 +1,4 @@ +; REQUIRES: x86 ; RUN: llvm-as -o %T/main.lto.obj %s ; RUN: llvm-as -o %T/foo.lto.obj %S/Inputs/lto-dep.ll ; RUN: rm -f %T/foo.lto.lib @@ -52,7 +53,7 @@ ; TEXT-11-NEXT: movl $2, %eax ; TEXT-11-NEXT: retq -; HEADERS-01: AddressOfEntryPoint: 0x2000 +; HEADERS-01: AddressOfEntryPoint: 0x1000 ; TEXT-01: Disassembly of section .text: ; TEXT-01-NEXT: .text: ; TEXT-01-NEXT: subq $40, %rsp @@ -78,7 +79,7 @@ ; TEXT-01-NEXT: int3 ; TEXT-01-NEXT: retq -; HEADERS-10: AddressOfEntryPoint: 0x2020 +; HEADERS-10: AddressOfEntryPoint: 0x1020 ; TEXT-10: Disassembly of section .text: ; TEXT-10-NEXT: .text: ; TEXT-10-NEXT: retq diff --git a/test/COFF/manifestinput-error.test b/test/COFF/manifestinput-error.test index eca7d0d03927..22ddc6719104 100644 --- a/test/COFF/manifestinput-error.test +++ b/test/COFF/manifestinput-error.test @@ -7,4 +7,4 @@ # RUN: /manifestuac:"level='requireAdministrator'" \ # RUN: /manifestinput:%p/Inputs/manifestinput.test %t.obj 2>&1 | FileCheck %s -# CHECK: error: unable to find mt.exe in PATH: No such file or directory +# CHECK: error: unable to find mt.exe in PATH: {{[Nn]}}o such file or directory diff --git a/test/COFF/manifestinput.test b/test/COFF/manifestinput.test index 51c189098261..33f14d8434ba 100644 --- a/test/COFF/manifestinput.test +++ b/test/COFF/manifestinput.test @@ -8,8 +8,8 @@ # RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s \ # RUN: -check-prefix TEST_EMBED -TEST_EMBED: ResourceTableRVA: 0x1000 -TEST_EMBED-NEXT: ResourceTableSize: 0x298 +TEST_EMBED: ResourceTableRVA: 0x2000 +TEST_EMBED-NEXT: ResourceTableSize: 0x2A0 TEST_EMBED-DAG: Resources [ TEST_EMBED-NEXT: Total Number of Resources: 1 TEST_EMBED-DAG: Number of String Entries: 0 diff --git a/test/COFF/merge.test b/test/COFF/merge.test index 4b5c1007f9fb..10a567243106 100644 --- a/test/COFF/merge.test +++ b/test/COFF/merge.test @@ -3,9 +3,35 @@ # RUN: /merge:.foo=.abc /merge:.bar=.def %t.obj /debug # RUN: llvm-readobj -sections %t.exe | FileCheck %s +# RUN: lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /merge:.foo=.bar /merge:.bar=.abc %t.obj /debug +# RUN: llvm-readobj -sections %t.exe | FileCheck --check-prefix=CHECK2 %s + +# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /merge:.rsrc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s +# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /merge:.foo=.rsrc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RSRC %s +# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /merge:.reloc=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s +# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /merge:.foo=.reloc %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-RELOC %s +# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /merge:.foo=.foo1 /merge:.foo1=.foo %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s +# RUN: not lld-link /out:%t.exe /entry:main /subsystem:console /force \ +# RUN: /merge:.foo=.foo1 /merge:.foo1=.foo2 /merge:.foo2=.foo1 %t.obj /debug 2>&1 | FileCheck --check-prefix=NO-CYCLE %s + # CHECK: Name: .def # CHECK: Name: .abc +# CHECK2-NOT: Name: .bar +# CHECK2: Name: .abc +# CHECK2-NOT: Name: .bar + +# NO-RSRC: /merge: cannot merge '.rsrc' with any section +# NO-RELOC: /merge: cannot merge '.reloc' with any section + +# NO-CYCLE: /merge: cycle found for section '.foo' + --- !COFF header: Machine: IMAGE_FILE_MACHINE_AMD64 diff --git a/test/COFF/nodefaultlib.test b/test/COFF/nodefaultlib.test index c0f8d50fc7ed..8f4da3a21efe 100644 --- a/test/COFF/nodefaultlib.test +++ b/test/COFF/nodefaultlib.test @@ -21,7 +21,8 @@ CHECK1: error: could not open hello64.obj: {{[Nn]}}o such file or directory CHECK2: error: could not open hello64: {{[Nn]}}o such file or directory -CHECK3: error: {{.*}}hello64.obj: undefined symbol: MessageBoxA +CHECK3: error: undefined symbol: MessageBoxA +CHECK3-NEXT: >>> referenced by {{.*}}hello64.obj:(main) # RUN: lld-link /libpath:%T /out:%t.exe /entry:main \ # RUN: /subsystem:console hello64.obj /defaultlib:std64.lib diff --git a/test/COFF/opt.test b/test/COFF/opt.test index a8b0e2eb97ba..ed43b6048085 100644 --- a/test/COFF/opt.test +++ b/test/COFF/opt.test @@ -1,18 +1,24 @@ # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /out:%t.exe /entry:main %t.obj \ -# RUN: /verbose >& %t.log -### FileCheck doesn't like empty input, so write something. -# RUN: echo dummy >> %t.log -# RUN: FileCheck -check-prefix=CHECK1 %s < %t.log +# RUN: /verbose 2>&1 | FileCheck -check-prefix=REF %s + +# /debug disables the /opt:ref default... +# RUN: lld-link /out:%t.exe /debug /entry:main %t.obj \ +# RUN: /verbose 2>&1 | FileCheck -check-prefix=NOREF %s + +# ...unless /profile is passed as well. +# RUN: lld-link /out:%t.exe /profile /debug /entry:main %t.obj \ +# RUN: /verbose 2>&1 | FileCheck -check-prefix=REF %s + +# RUN: lld-link /out:%t.exe /opt:ref /debug /entry:main %t.obj \ +# RUN: /verbose 2>&1 | FileCheck -check-prefix=REF %s # RUN: lld-link /out:%t.exe /entry:main %t.obj \ -# RUN: /verbose /opt:noref >& %t.log -# RUN: echo dummy >> %t.log -# RUN: FileCheck -check-prefix=CHECK2 %s < %t.log +# RUN: /verbose /opt:noref /profile 2>&1 | FileCheck -check-prefix=NOREF %s -# CHECK1: Discarded unused -# CHECK2-NOT: Discarded unused +# REF: Discarded unused +# NOREF-NOT: Discarded unused --- !COFF header: diff --git a/test/COFF/options.test b/test/COFF/options.test index 39f944beddbc..6b9f2ca06fab 100644 --- a/test/COFF/options.test +++ b/test/COFF/options.test @@ -30,6 +30,16 @@ ENT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOENT %s NOENT-NOT: IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA +# RUN: lld-link /out:%t.exe /entry:main /integritycheck %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=INT %s +INT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY + +# RUN: lld-link /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s +# RUN: lld-link /out:%t.exe /integritycheck:no /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOINT %s +NOINT-NOT: IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY + # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NXCOMPAT %s # RUN: lld-link /out:%t.exe /entry:main /nxcompat %t.obj @@ -48,4 +58,8 @@ TSAWARE: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE # RUN: lld-link /tsaware:no /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=NOTSAWARE %s +# RUN: lld-link /dll /out:%t.dll /entry:main %t.obj +# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s +# RUN: lld-link /tsaware /dll /out:%t.dll /entry:main %t.obj +# RUN: llvm-readobj -file-headers %t.dll | FileCheck -check-prefix=NOTSAWARE %s NOTSAWARE-NOT: IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE diff --git a/test/COFF/order-i386.test b/test/COFF/order-i386.test new file mode 100644 index 000000000000..4cde5fa813f7 --- /dev/null +++ b/test/COFF/order-i386.test @@ -0,0 +1,69 @@ +# RUN: yaml2obj < %s > %t.obj + +# RUN: echo fn1 > %t.order +# RUN: echo fn2 >> %t.order + +# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \ +# RUN: -lldmap:- -out:%t.exe -order:@%t.order | FileCheck %s +# CHECK: fn1 +# CHECK: fn2 + +# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref %t.obj \ +# RUN: -lldmap:- -out:%t.exe | FileCheck -check-prefix=DEFAULT %s +# DEFAULT: fn2 +# DEFAULT: fn1 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_I386 + Characteristics: [ ] +sections: + - Name: '.text' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: CC + - Name: '.text' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: CC +symbols: + - Name: '.text' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: '.text' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: _fn2 + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: _fn1 + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... + diff --git a/test/COFF/order.test b/test/COFF/order.test index bb0a6e5740c0..0006550e56ae 100644 --- a/test/COFF/order.test +++ b/test/COFF/order.test @@ -1,15 +1,121 @@ -# RUN: yaml2obj < %p/Inputs/include1a.yaml > %t1.obj -# RUN: yaml2obj < %p/Inputs/include1b.yaml > %t2.obj -# RUN: yaml2obj < %p/Inputs/include1c.yaml > %t3.obj -# RUN: rm -f %t2.lib %t3.lib -# RUN: llvm-ar cru %t2.lib %t2.obj -# RUN: llvm-ar cru %t3.lib %t3.obj -# RUN: lld-link /out:%t.exe /entry:main \ -# RUN: %t1.obj %t2.lib %t3.obj %t3.lib /verbose >& %t.log -# RUN: FileCheck %s < %t.log - -CHECK: order.test.tmp1.obj -CHECK: order.test.tmp2.lib -CHECK: order.test.tmp3.obj -CHECK: order.test.tmp3.lib -CHECK: order.test.tmp2.lib(order.test.tmp2.obj) for foo +# RUN: yaml2obj < %s > %t1.obj +# RUN: yaml2obj < %p/Inputs/order.yaml > %t2.obj + +# RUN: echo fn1 > %t.order +# RUN: echo fn2 >> %t.order +# RUN: echo fn3 >> %t.order +# RUN: echo fn4 >> %t.order + +# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref -debug %t1.obj %t2.obj \ +# RUN: -lldmap:- -out:%t.exe -order:@%t.order | FileCheck %s +# CHECK: fn1 +# CHECK: fn2 +# CHECK: fn3 +# CHECK: fn4 +# CHECK: unrelated1 +# CHECK: unrelated2 + +# RUN: lld-link -entry:fn1 -subsystem:console -opt:noref -debug %t1.obj %t2.obj \ +# RUN: -lldmap:- -ignore:4037 -out:%t.exe | FileCheck -check-prefix=DEFAULT %s +# DEFAULT: fn2 +# DEFAULT: fn3 +# DEFAULT: unrelated1 +# DEFAULT: unrelated2 +# DEFAULT: fn4 +# DEFAULT: fn1 + +# RUN: echo fn1 > %t2.order +# RUN: echo fn2 >> %t2.order +# RUN: echo fn3 >> %t2.order +# RUN: echo fn4 >> %t2.order +# RUN: echo foo >> %t2.order +# RUN: lld-link -entry:fn1 -subsystem:console -debug %t1.obj %t2.obj \ +# RUN: -out:%t.exe -order:@%t2.order 2>&1 | FileCheck -check-prefix=WARN %s +# WARN: warning: /order:{{.*}} missing symbol: foo +# WARN-NOT: f2 +# WARN-NOT: f3 +# WARN-NOT: f4 +# RUN: lld-link -entry:fn1 -subsystem:console -debug %t1.obj %t2.obj \ +# RUN: -out:%t.exe -order:@%t2.order -ignore:4037 2>&1 | \ +# RUN: FileCheck -allow-empty -check-prefix=NOWARN %s +# NOWARN-NOT: warning: /order:{{.*}} missing symbol: foo +# NOWARN-NOT: f2 +# NOWARN-NOT: f3 +# NOWARN-NOT: f4 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_LNK_COMDAT, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: C3 +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: fn2 + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .text + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 2 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: fn3 + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .text + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 1 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 3 + Selection: IMAGE_COMDAT_SELECT_NODUPLICATES + - Name: unrelated1 + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/output-chars.test b/test/COFF/output-chars.test new file mode 100644 index 000000000000..2ccb084364ce --- /dev/null +++ b/test/COFF/output-chars.test @@ -0,0 +1,109 @@ +# RUN: yaml2obj %s > %t.obj +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj +# RUN: llvm-readobj -sections %t.dll | FileCheck %s +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /section:.foo,rwe +# RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=SECTION %s +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar +# RUN: llvm-readobj -sections -section-data %t.dll | FileCheck --check-prefix=MERGE %s +# RUN: lld-link /out:%t.dll /entry:__ImageBase /dll %t.obj /merge:.foo=.bar /section:.foo,rwe +# RUN: llvm-readobj -sections %t.dll | FileCheck --check-prefix=MERGE-SECTION %s + +# CHECK: Name: .foo +# CHECK: Characteristics [ +# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# CHECK-NEXT: IMAGE_SCN_MEM_READ +# CHECK-NEXT: ] + +# CHECK: Name: .foo +# CHECK: Characteristics [ +# CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# CHECK-NEXT: IMAGE_SCN_MEM_READ +# CHECK-NEXT: IMAGE_SCN_MEM_WRITE +# CHECK-NEXT: ] + +# SECTION: Name: .foo +# SECTION: Characteristics [ +# SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE +# SECTION-NEXT: IMAGE_SCN_MEM_READ +# SECTION-NEXT: IMAGE_SCN_MEM_WRITE +# SECTION-NEXT: ] + +# SECTION: Name: .foo +# SECTION: Characteristics [ +# SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE +# SECTION-NEXT: IMAGE_SCN_MEM_READ +# SECTION-NEXT: IMAGE_SCN_MEM_WRITE +# SECTION-NEXT: ] + +# MERGE: Name: .bar +# MERGE: Characteristics [ +# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# MERGE-NEXT: IMAGE_SCN_MEM_READ +# MERGE-NEXT: ] +# MERGE-NEXT: SectionData ( +# MERGE-NEXT: 0000: 0301 + +# MERGE: Name: .bar +# MERGE: Characteristics [ +# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# MERGE-NEXT: IMAGE_SCN_MEM_READ +# MERGE-NEXT: IMAGE_SCN_MEM_WRITE +# MERGE-NEXT: ] +# MERGE-NEXT: SectionData ( +# MERGE-NEXT: 0000: 04 + +# MERGE: Name: .foo +# MERGE: Characteristics [ +# MERGE-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# MERGE-NEXT: IMAGE_SCN_MEM_READ +# MERGE-NEXT: IMAGE_SCN_MEM_WRITE +# MERGE-NEXT: ] +# MERGE-NEXT: SectionData ( +# MERGE-NEXT: 0000: 02 + +# MERGE-SECTION: Name: .bar +# MERGE-SECTION: Characteristics [ +# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ +# MERGE-SECTION-NEXT: ] + +# MERGE-SECTION: Name: .bar +# MERGE-SECTION: Characteristics [ +# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ +# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_WRITE +# MERGE-SECTION-NEXT: ] + +# MERGE-SECTION: Name: .foo +# MERGE-SECTION: Characteristics [ +# MERGE-SECTION-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_EXECUTE +# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_READ +# MERGE-SECTION-NEXT: IMAGE_SCN_MEM_WRITE +# MERGE-SECTION-NEXT: ] + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: .foo + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 01 + - Name: .foo + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 1 + SectionData: 02 + - Name: .bar + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 03 + - Name: .bar + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ] + Alignment: 1 + SectionData: 04 +symbols: +... diff --git a/test/COFF/pdata-arm64.yaml b/test/COFF/pdata-arm64.yaml index f21749b9253f..4f5210c4da81 100644 --- a/test/COFF/pdata-arm64.yaml +++ b/test/COFF/pdata-arm64.yaml @@ -3,7 +3,7 @@ # RUN: lld-link /out:%t.exe /entry:func1 /subsystem:console %t.obj # RUN: llvm-objdump -s -section=.pdata %t.exe | FileCheck -check-prefix=PDATA %s -# PDATA: 00200000 2500a100 24200000 31002201 +# PDATA: 00100000 2500a100 24100000 31002201 --- !COFF header: diff --git a/test/COFF/pdb-comdat.test b/test/COFF/pdb-comdat.test index 655f215e0199..2c402739162d 100644 --- a/test/COFF/pdb-comdat.test +++ b/test/COFF/pdb-comdat.test @@ -43,10 +43,10 @@ CHECK-NEXT: ============================================================ CHECK-NEXT: Records CHECK-NEXT: 84 | S_PROCREF [size = 20] `main` CHECK-NEXT: module = 1, sum name = 0, offset = 120 -CHECK-NEXT: 128 | S_PROCREF [size = 20] `foo` -CHECK-NEXT: module = 1, sum name = 0, offset = 208 CHECK-NEXT: 148 | S_PROCREF [size = 20] `bar` CHECK-NEXT: module = 2, sum name = 0, offset = 120 +CHECK-NEXT: 128 | S_PROCREF [size = 20] `foo` +CHECK-NEXT: module = 1, sum name = 0, offset = 208 CHECK-NEXT: 104 | S_GDATA32 [size = 24] `global` CHECK-NEXT: type = 0x0074 (int), addr = 0000:0000 CHECK-NEXT: 168 | S_GDATA32 [size = 24] `global` @@ -61,7 +61,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable CHECK: 120 | S_GPROC32 [size = 44] `main` -CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 24 +CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 24 CHECK: debug start = 4, debug end = 19, flags = none CHECK: 164 | S_FRAMEPROC [size = 32] CHECK: size = 40, padding size = 0, offset to padding = 0 @@ -70,7 +70,7 @@ CHECK: flags = has async eh | opt speed CHECK: 196 | S_END [size = 4] CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `0x100A` CHECK: 208 | S_GPROC32 [size = 44] `foo` -CHECK: parent = 0, end = 284, addr = 0002:0032, code size = 15 +CHECK: parent = 0, end = 284, addr = 0001:0032, code size = 15 CHECK: debug start = 0, debug end = 14, flags = none CHECK: 252 | S_FRAMEPROC [size = 32] CHECK: size = 0, padding size = 0, offset to padding = 0 @@ -84,7 +84,7 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compiler, l CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable CHECK: 120 | S_GPROC32 [size = 44] `bar` -CHECK: parent = 0, end = 196, addr = 0002:0048, code size = 14 +CHECK: parent = 0, end = 196, addr = 0001:0048, code size = 14 CHECK: debug start = 4, debug end = 9, flags = none CHECK: 164 | S_FRAMEPROC [size = 32] CHECK: size = 40, padding size = 0, offset to padding = 0 diff --git a/test/COFF/pdb-diff.test b/test/COFF/pdb-diff.test deleted file mode 100644 index 17d26b60353e..000000000000 --- a/test/COFF/pdb-diff.test +++ /dev/null @@ -1,215 +0,0 @@ -This test verifies that we produce PDBs compatible with MSVC in various ways. -We check in a cl-generated object file, PDB, and original source which serve -as the "baseline" for us to measure against. Then we link the same object -file with LLD and compare the two PDBs. Since the baseline object file and -PDB are already checked in, we just run LLD on the object file. - -RUN: rm -f %T/pdb-diff-lld.pdb %T/pdb-diff-lld.exe -RUN: lld-link /debug /pdb:%T/pdb-diff-lld.pdb /out:%T/pdb-diff-lld.exe /nodefaultlib \ -RUN: /entry:main %S/Inputs/pdb-diff.obj -RUN: llvm-pdbutil diff -result -values=false -left-bin-root=%S -right-bin-root=D:/src/llvm-mono/lld/test/COFF/ \ -RUN: %T/pdb-diff-lld.pdb %S/Inputs/pdb-diff-cl.pdb | FileCheck %s - -CHECK: ---------------------- -CHECK-NEXT: | MSF Super Block | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Block Size | I | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Block Count | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Unknown 1 | I | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: | Directory Size | -CHECK-NEXT: |----------------+---| -CHECK-NEXT: ------------------------------------ -CHECK-NEXT: | Stream Directory | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Stream Count | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Old MSF Directory | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | PDB Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | TPI Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | DBI Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | IPI Stream | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | New FPO Data | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Section Header Data | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Named Stream "/names" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Named Stream "/LinkInfo" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Module "* Linker *" | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | TPI Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | IPI Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Public Symbol Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Global Symbol Hash | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Symbol Records | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: ------------------------------------ -CHECK-NEXT: | String Table | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Number of Strings | D | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Hash Version | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Byte Size | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Signature | I | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | Empty Strings | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | {{.*}}pdb-diff.cpp | {{[EI]}} | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | $T0 $ebp = $...p $T0 8 + = | D | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: | d:\src\llvm-...er internal) | D | -CHECK-NEXT: |------------------------------+---| -CHECK-NEXT: ---------------------------- -CHECK-NEXT: | PDB Stream | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Stream Size | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Age | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Guid | D | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Signature | D | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Version | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Features (set) | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Feature | I | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Named Stream Size | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | Named Streams (map) | {{[EI]}} | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | /names | {{[EI]}} | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: | /LinkInfo | {{[EI]}} | -CHECK-NEXT: |----------------------+---| -CHECK-NEXT: ---------------------------------------------- -CHECK-NEXT: | DBI Stream | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | File | | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Dbi Version | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Age | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Machine | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Flags | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Build Major | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Build Minor | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Build Number | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | PDB DLL Version | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | PDB DLL RBLD | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (FPO) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Exception) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Fixup) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (OmapToSrc) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (OmapFromSrc) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (SectionHdr) | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (TokenRidMap) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Xdata) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (Pdata) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (NewFPO) | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | DBG (SectionHdrOrig) | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Globals Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Publics Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Symbol Records | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Has CTypes | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Is Incrementally Linked | D | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Is Stripped | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Module Count | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Source File Count | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Module "Inputs\pdb-diff.obj" | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Modi | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Obj File Name | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Debug Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C11 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C13 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - # of files | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Pdb File Path Index | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Source File Name Index | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Symbol Byte Size | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | Module "* Linker *" | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Modi | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Obj File Name | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Debug Stream | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C11 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - C13 Byte Size | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - # of files | I | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Pdb File Path Index | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Source File Name Index | {{[EI]}} | -CHECK-NEXT: |----------------------------------------+---| -CHECK-NEXT: | - Symbol Byte Size | -CHECK-NEXT: |----------------------------------------+---| - - diff --git a/test/COFF/pdb-exe-path-dots.test b/test/COFF/pdb-exe-path-dots.test new file mode 100644 index 000000000000..131898122545 --- /dev/null +++ b/test/COFF/pdb-exe-path-dots.test @@ -0,0 +1,10 @@ +RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj +RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj +RUN: rm -rf %t +RUN: mkdir %t +RUN: mkdir %t/foo +RUN: lld-link /debug /pdb:%t/foo/./out.pdb /out:%t/out.exe /entry:main /nodefaultlib \ +RUN: %t1.obj %t2.obj +RUN: llvm-readobj -coff-debug-directory %t/out.exe | FileCheck %s + +CHECK: PDBFileName: {{.*}}tmp{{/|\\}}foo{{/|\\}}out.pdb
\ No newline at end of file diff --git a/test/COFF/pdb-file-static.test b/test/COFF/pdb-file-static.test new file mode 100644 index 000000000000..f08f717b40af --- /dev/null +++ b/test/COFF/pdb-file-static.test @@ -0,0 +1,51 @@ +# RUN: yaml2obj %S/Inputs/pdb-file-statics-a.yaml > %t.a.obj +# RUN: yaml2obj %S/Inputs/pdb-file-statics-b.yaml > %t.b.obj +# RUN: lld-link %t.a.obj %t.b.obj /nodefaultlib /entry:main /debug /pdb:%t.pdb +# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +# S_FILESTATIC records are unique in that they refer to the string table, but +# they do *not* go through the file checksums table. They refer directly to +# the string table. This makes for special handling in the linker, so it +# deserves a custom test. + +# Clang doesn't currently generate these records, but MSVC does, so we have to +# be able to correctly link them. These records are only generated when +# optimizations are turned on. + +# // a.cpp +# // cl.exe /Z7 /O1 /c a.cpp +# static int x = 0; +# +# void b(int); +# +# void a(int) { +# if (x) +# b(x); +# } +# +# int main(int argc, char **argv) { +# a(argc); +# return x; +# } +# +# // b.cpp +# // cl.exe /Z7 /O1 /c a.cpp +# void a(int); +# +# static int y = 0; +# +# void b(int) { +# if (y) +# a(y); +# } + +# CHECK: Symbols +# CHECK: ============================================================ +# CHECK-LABEL: Mod 0000 | `{{.*}}a.obj`: +# CHECK: 232 | S_FILESTATIC [size = 16] `x` +# CHECK-NEXT: type = 0x0074 (int), file name = 2 (D:\src\llvmbuild\cl\Debug\x64\a.obj), flags = enreg global | enreg static +# CHECK: Mod 0001 | `{{.*}}b.obj`: +# CHECK: 232 | S_FILESTATIC [size = 16] `y` +# CHECK-NEXT: type = 0x0074 (int), file name = 74 (D:\src\llvmbuild\cl\Debug\x64\b.obj), flags = enreg global | enreg static +# CHECK-LABEL: Mod 0002 | `* Linker *`: + diff --git a/test/COFF/pdb-global-gc.yaml b/test/COFF/pdb-global-gc.yaml index f2c4450809b0..7206196fae2d 100644 --- a/test/COFF/pdb-global-gc.yaml +++ b/test/COFF/pdb-global-gc.yaml @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj %s -o %t.obj # RUN: llvm-mc %S/Inputs/pdb-global-gc.s -triple x86_64-windows-msvc -filetype=obj -o %t2.obj # RUN: lld-link %t.obj %t2.obj -debug -entry:main \ diff --git a/test/COFF/pdb-global-hashes.test b/test/COFF/pdb-global-hashes.test index b47e43826537..238613cef69c 100644 --- a/test/COFF/pdb-global-hashes.test +++ b/test/COFF/pdb-global-hashes.test @@ -83,7 +83,7 @@ CHECK-NEXT: ============================================================ CHECK-NEXT: Showing 6 records CHECK-NEXT: 0x1000 | LF_FUNC_ID [size = 20] CHECK-NEXT: name = main, type = 0x1002, parent scope = <no type> -CHECK-NEXT: 0x1001 | LF_STRING_ID [size = 48] ID: <no type>, String: D:\src\llvmbuild\clang\Debug\x86\obj.h +CHECK-NEXT: 0x1001 | LF_STRING_ID [size = {{.*}}] ID: <no type>, String: {{.*}}obj.h CHECK-NEXT: 0x1002 | LF_UDT_SRC_LINE [size = 16] CHECK-NEXT: udt = 0x1008, file = 4097, line = 2 CHECK-NEXT: 0x1003 | LF_MFUNC_ID [size = 16] diff --git a/test/COFF/pdb-globals-dia-func-collision3.test b/test/COFF/pdb-globals-dia-func-collision3.test new file mode 100644 index 000000000000..532bdd47f13d --- /dev/null +++ b/test/COFF/pdb-globals-dia-func-collision3.test @@ -0,0 +1,81 @@ +REQUIRES: diasdk + +Input object file reconstruction: + +; // foo.cpp +; void LJPwNRh() {} +; void HGfxvKdQO() {} +; void wuN() {} +; void tEo() {} +; void VUo() {} +; void teO() {} +; void bqSuLGQgWa() {} +; void SyJYcL() {} +; void OUV() {} +; void quH() {} +; void rbEaPKrlrRwk() {} +; void oet() {} +; void tuM() {} +; void LuU() {} +; void loxueqJLH() {} +; void QplRJuDs() {} +; void rWDokkLG() {} +; void sEH() {} +; void pui() {} +; void xoZvxw() {} +; +; int main(int argc, char **argv) { +; return 0; +; } + +clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-func-collision3.obj + +RUN: lld-link /debug /nodefaultlib /incremental:no /entry:main /out:%t.exe %S/Inputs/globals-dia-func-collision3.obj +RUN: llvm-pdbutil pretty -with-name=LuU -with-name=oet -with-name=OUV -with-name=pui \ +RUN: -with-name=quH -with-name=sEH -with-name=teO -with-name=tEo \ +RUN: -with-name=tuM -with-name=VUo -with-name=wuN -with-name=SyJYcL \ +RUN: -with-name=xoZvxw -with-name=LJPwNRh -with-name=QplRJuDs -with-name=rWDokkLG \ +RUN: -with-name=HGfxvKdQO -with-name=loxueqJLH -with-name=bqSuLGQgWa -with-name=rbEaPKrlrRwk \ +RUN: %t.pdb | FileCheck %s + + +CHECK: [1 occurrences] - LuU +CHECK-NEXT: func [0x000010d0+ 0 - 0x000010d1- 1 | sizeof= 1] (FPO) void __cdecl LuU() +CHECK-NEXT: [1 occurrences] - oet +CHECK-NEXT: func [0x000010b0+ 0 - 0x000010b1- 1 | sizeof= 1] (FPO) void __cdecl oet() +CHECK-NEXT: [1 occurrences] - OUV +CHECK-NEXT: func [0x00001080+ 0 - 0x00001081- 1 | sizeof= 1] (FPO) void __cdecl OUV() +CHECK-NEXT: [1 occurrences] - pui +CHECK-NEXT: func [0x00001120+ 0 - 0x00001121- 1 | sizeof= 1] (FPO) void __cdecl pui() +CHECK-NEXT: [1 occurrences] - quH +CHECK-NEXT: func [0x00001090+ 0 - 0x00001091- 1 | sizeof= 1] (FPO) void __cdecl quH() +CHECK-NEXT: [1 occurrences] - sEH +CHECK-NEXT: func [0x00001110+ 0 - 0x00001111- 1 | sizeof= 1] (FPO) void __cdecl sEH() +CHECK-NEXT: [1 occurrences] - teO +CHECK-NEXT: func [0x00001050+ 0 - 0x00001051- 1 | sizeof= 1] (FPO) void __cdecl teO() +CHECK-NEXT: [1 occurrences] - tEo +CHECK-NEXT: func [0x00001030+ 0 - 0x00001031- 1 | sizeof= 1] (FPO) void __cdecl tEo() +CHECK-NEXT: [1 occurrences] - tuM +CHECK-NEXT: func [0x000010c0+ 0 - 0x000010c1- 1 | sizeof= 1] (FPO) void __cdecl tuM() +CHECK-NEXT: [1 occurrences] - VUo +CHECK-NEXT: func [0x00001040+ 0 - 0x00001041- 1 | sizeof= 1] (FPO) void __cdecl VUo() +CHECK-NEXT: [1 occurrences] - wuN +CHECK-NEXT: func [0x00001020+ 0 - 0x00001021- 1 | sizeof= 1] (FPO) void __cdecl wuN() +CHECK-NEXT: [1 occurrences] - SyJYcL +CHECK-NEXT: func [0x00001070+ 0 - 0x00001071- 1 | sizeof= 1] (FPO) void __cdecl SyJYcL() +CHECK-NEXT: [1 occurrences] - xoZvxw +CHECK-NEXT: func [0x00001130+ 0 - 0x00001131- 1 | sizeof= 1] (FPO) void __cdecl xoZvxw() +CHECK-NEXT: [1 occurrences] - LJPwNRh +CHECK-NEXT: func [0x00001000+ 0 - 0x00001001- 1 | sizeof= 1] (FPO) void __cdecl LJPwNRh() +CHECK-NEXT: [1 occurrences] - QplRJuDs +CHECK-NEXT: func [0x000010f0+ 0 - 0x000010f1- 1 | sizeof= 1] (FPO) void __cdecl QplRJuDs() +CHECK-NEXT: [1 occurrences] - rWDokkLG +CHECK-NEXT: func [0x00001100+ 0 - 0x00001101- 1 | sizeof= 1] (FPO) void __cdecl rWDokkLG() +CHECK-NEXT: [1 occurrences] - HGfxvKdQO +CHECK-NEXT: func [0x00001010+ 0 - 0x00001011- 1 | sizeof= 1] (FPO) void __cdecl HGfxvKdQO() +CHECK-NEXT: [1 occurrences] - loxueqJLH +CHECK-NEXT: func [0x000010e0+ 0 - 0x000010e1- 1 | sizeof= 1] (FPO) void __cdecl loxueqJLH() +CHECK-NEXT: [1 occurrences] - bqSuLGQgWa +CHECK-NEXT: func [0x00001060+ 0 - 0x00001061- 1 | sizeof= 1] (FPO) void __cdecl bqSuLGQgWa() +CHECK-NEXT: [1 occurrences] - rbEaPKrlrRwk +CHECK-NEXT: func [0x000010a0+ 0 - 0x000010a1- 1 | sizeof= 1] (FPO) void __cdecl rbEaPKrlrRwk() diff --git a/test/COFF/pdb-globals-dia-vfunc-collision.test b/test/COFF/pdb-globals-dia-vfunc-collision.test new file mode 100644 index 000000000000..964901882703 --- /dev/null +++ b/test/COFF/pdb-globals-dia-vfunc-collision.test @@ -0,0 +1,42 @@ +REQUIRES: diasdk + +Input object file reconstruction: + +; // main.cpp +; struct S { +; // Function names are chosen specifically to generate hash collisions in the +; // GSI hash table. +; virtual int A307() { return 102; } +; virtual int A400() { return 12; } +; virtual int A206() { return 201; } +; virtual int A105() { return 300; } +; }; +; +; struct T : public S { +; int A105() override { return 300; } +; int A307() override { return 102; } +; int A206() override { return 201; } +; int A400() override { return 12; } +; }; +; +; int main(int argc, char **argv) { +; T s; +; return s.A105() + s.A206() + s.A307() + s.A400(); +; } + +clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-vfunc-collision.obj + +RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe %S/Inputs/globals-dia-vfunc-collision.obj +RUN: llvm-pdbutil pretty -classes %t.pdb | FileCheck %s + +CHECK: struct T +CHECK: func [0x000010c0+ 0 - 0x000010dd-29 | sizeof= 29] (FPO) virtual {{.*}}A105() +CHECK: func [0x00001100+ 0 - 0x0000111b-27 | sizeof= 27] (FPO) virtual {{.*}}A307() +CHECK: func [0x000010e0+ 0 - 0x000010fd-29 | sizeof= 29] (FPO) virtual {{.*}}A206() +CHECK: func [0x00001120+ 0 - 0x0000113b-27 | sizeof= 27] (FPO) virtual {{.*}}A400() + +CHECK: struct S +CHECK: func [0x00001160+ 0 - 0x0000116c-12 | sizeof= 12] (FPO) virtual {{.*}}A307() +CHECK: func [0x00001170+ 0 - 0x0000117c-12 | sizeof= 12] (FPO) virtual {{.*}}A400() +CHECK: func [0x00001180+ 0 - 0x0000118c-12 | sizeof= 12] (FPO) virtual {{.*}}A206() +CHECK: func [0x00001190+ 0 - 0x0000119c-12 | sizeof= 12] (FPO) virtual {{.*}}A105() diff --git a/test/COFF/pdb-globals-dia-vfunc-collision2.test b/test/COFF/pdb-globals-dia-vfunc-collision2.test new file mode 100644 index 000000000000..cfbc445b37b4 --- /dev/null +++ b/test/COFF/pdb-globals-dia-vfunc-collision2.test @@ -0,0 +1,25 @@ +REQUIRES: diasdk + +Input object file reconstruction: + +; // main.cpp +; struct S { +; // Function names are chosen specifically to generate hash collisions in the +; // GSI hash table. +; virtual int A132() { return 102; } +; virtual int A1001() { return 300; } +; }; +; +; int main(int argc, char **argv) { +; S s; +; return s.A132(); +; } + +clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-vfunc-collision2.obj + +RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe %S/Inputs/globals-dia-vfunc-collision2.obj +RUN: llvm-pdbutil pretty -classes %t.pdb | FileCheck %s + +CHECK: struct S +CHECK: func [0x00001060+ 0 - 0x0000106c-12 | sizeof= 12] (FPO) virtual {{.*}}A132() +CHECK: func [0x00001070+ 0 - 0x0000107c-12 | sizeof= 12] (FPO) virtual {{.*}}A1001() diff --git a/test/COFF/pdb-globals-dia-vfunc-simple.test b/test/COFF/pdb-globals-dia-vfunc-simple.test new file mode 100644 index 000000000000..00d95ad7ef00 --- /dev/null +++ b/test/COFF/pdb-globals-dia-vfunc-simple.test @@ -0,0 +1,26 @@ +REQUIRES: diasdk + +Input object file reconstruction: + +; // main.cpp +; struct Base { +; virtual int V2() { return 42; } +; }; +; +; struct Derived : public Base { +; int V2() override { return 42; } +; }; +; +; int main() +; { +; Derived D; +; return D.V2(); +; } + +clang-cl /Z7 /GS- /GR- /c main.cpp /Foglobals-dia-vfunc-simple.obj + +RUN: lld-link /debug /nodefaultlib /entry:main /out:%t.exe %S/Inputs/globals-dia-vfunc-simple.obj +RUN: llvm-pdbutil pretty -classes %t.pdb | FileCheck %s + +CHECK: func [0x00001070+ 0 - 0x0000107c-12 | sizeof= 12] (FPO) virtual {{.*}}V2() +CHECK: func [0x000010a0+ 0 - 0x000010ac-12 | sizeof= 12] (FPO) virtual {{.*}}V2() diff --git a/test/COFF/pdb-globals.test b/test/COFF/pdb-globals.test index b5e4f49cb458..db0d3f6d7e8d 100644 --- a/test/COFF/pdb-globals.test +++ b/test/COFF/pdb-globals.test @@ -15,20 +15,20 @@ RUN: llvm-pdbutil dump -symbols -globals %t.pdb | FileCheck %s CHECK-LABEL: Global Symbols CHECK-NEXT: ============================================================ CHECK-NEXT: Records +CHECK-NEXT: 208 | S_LPROCREF [size = 24] `LocalFunc` +CHECK-NEXT: module = 1, sum name = 0, offset = 292 CHECK-NEXT: 160 | S_PROCREF [size = 28] `GlobalFunc` CHECK-NEXT: module = 1, sum name = 0, offset = 52 CHECK-NEXT: 188 | S_PROCREF [size = 20] `main` CHECK-NEXT: module = 1, sum name = 0, offset = 108 -CHECK-NEXT: 208 | S_LPROCREF [size = 24] `LocalFunc` -CHECK-NEXT: module = 1, sum name = 0, offset = 292 -CHECK-NEXT: 312 | S_PROCREF [size = 40] `HelloPoint::HelloPoint` -CHECK-NEXT: module = 1, sum name = 0, offset = 376 CHECK-NEXT: 232 | S_GDATA32 [size = 28] `__purecall` -CHECK-NEXT: type = 0x0403 (void*), addr = 0000:0000 +CHECK-NEXT: type = 0x0403 (void*), addr = 0003:0004 CHECK-NEXT: 260 | S_GDATA32 [size = 24] `GlobalVar` -CHECK-NEXT: type = 0x100B (const int*), addr = 0001:0000 +CHECK-NEXT: type = 0x100B (const int*), addr = 0003:0000 CHECK-NEXT: 284 | S_LDATA32 [size = 28] `ConstantVar` CHECK-NEXT: type = 0x100A (const int), addr = 0002:0000 +CHECK-NEXT: 312 | S_PROCREF [size = 40] `HelloPoint::HelloPoint` +CHECK-NEXT: module = 1, sum name = 0, offset = 376 CHECK-LABEL: Symbols CHECK-NEXT: ============================================================ diff --git a/test/COFF/pdb-heapsite.yaml b/test/COFF/pdb-heapsite.yaml index 966ae4284890..bfdd7b4dc555 100644 --- a/test/COFF/pdb-heapsite.yaml +++ b/test/COFF/pdb-heapsite.yaml @@ -69,7 +69,7 @@ sections: RegRelativeSym: Offset: 8 Type: 35 - Register: RSP + Register: CVRegRSP VarName: __formal - Kind: S_PROC_ID_END ScopeEndSym: diff --git a/test/COFF/pdb-lib.s b/test/COFF/pdb-lib.s index 319d4bc0fb80..c970f0ba1980 100644 --- a/test/COFF/pdb-lib.s +++ b/test/COFF/pdb-lib.s @@ -13,15 +13,15 @@ # CHECK-NEXT: ============================================================ # CHECK-NEXT: Mod 0000 | `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]foo.obj}}`: -# CHECK-NEXT: debug stream: 9, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false # CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0001 | `bar.obj`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`: -# CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false # CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0002 | `* Linker *`: # CHECK-NEXT: Obj: ``: -# CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false +# CHECK-NEXT: debug stream: 12, # files: 0, has ec info: false # CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 `` .def _main; diff --git a/test/COFF/pdb-linker-module.test b/test/COFF/pdb-linker-module.test index 1bb57298f96e..022a447e4d55 100644 --- a/test/COFF/pdb-linker-module.test +++ b/test/COFF/pdb-linker-module.test @@ -1,10 +1,11 @@ -RUN: lld-link /debug /pdb:%t.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj +RUN: echo "/nodefaultlib" > %t.rsp +RUN: lld-link /debug /pdb:%t.pdb @%t.rsp /entry:main %S/Inputs/pdb-diff.obj RUN: llvm-pdbutil dump -modules %t.pdb | FileCheck --check-prefix=MODS %s RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck --check-prefix=SYMS %s MODS: Mod 0001 | `* Linker *` MODS-NEXT: Obj: ``: -MODS-NEXT: debug stream: 10, # files: 0, has ec info: false +MODS-NEXT: debug stream: 12, # files: 0, has ec info: false MODS-NEXT: pdb file ni: 1 `{{.*}}pdb-linker-module.test.tmp.pdb`, src file ni: 0 `` SYMS: Mod 0001 | `* Linker *` diff --git a/test/COFF/pdb-natvis.test b/test/COFF/pdb-natvis.test new file mode 100644 index 000000000000..2db68b6bc71a --- /dev/null +++ b/test/COFF/pdb-natvis.test @@ -0,0 +1,26 @@ +REQUIRES: diasdk + +RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj +RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/natvis-1.natvis \ +RUN: /NATVIS:%p/Inputs/natvis-2.natvis /NATVIS:%p/Inputs/natvis-3.natvis /OUT:%t.exe \ +RUN: /PDB:%t.pdb +RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \ +RUN: --check-prefix=CHECK-FIRST %s +RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \ +RUN: --check-prefix=CHECK-SECOND %s +RUN: llvm-pdbutil pretty -injected-sources -injected-source-content %t.pdb | FileCheck \ +RUN: --check-prefix=CHECK-THIRD %s + +RUN: lld-link /DEBUG %t.obj /nodefaultlib /entry:main /NATVIS:%p/Inputs/test2.natvis \ +RUN: /OUT:%t.exe /PDB:%t.pdb 2>&1 | FileCheck --check-prefix=CHECK-MISSING %s + +CHECK-FIRST: {{.*}}natvis-1.natvis (16 bytes): obj=<null>, vname={{.*}}natvis-1.natvis, crc=355285096, compression=None +CHECK-FIRST-NEXT: 1st Natvis Test + +CHECK-SECOND: {{.*}}natvis-2.natvis (19 bytes): obj=<null>, vname={{.*}}natvis-2.natvis, crc=4252640062, compression=None +CHECK-SECOND-NEXT: Second Natvis Test + +CHECK-THIRD: {{.*}}natvis-3.natvis (18 bytes): obj=<null>, vname={{.*}}natvis-3.natvis, crc=2069719849, compression=None +CHECK-THIRD-NEXT: Third Natvis Test + +CHECK-MISSING: Cannot open input file: {{.*}}test2.natvis
\ No newline at end of file diff --git a/test/COFF/pdb-procid-remapping.test b/test/COFF/pdb-procid-remapping.test index cb612400a650..e42616dae47d 100644 --- a/test/COFF/pdb-procid-remapping.test +++ b/test/COFF/pdb-procid-remapping.test @@ -9,7 +9,7 @@ CHECK: Symbols CHECK-NEXT: ============================================================ CHECK-LABEL: Mod 0000 | CHECK: 92 | S_GPROC32 [size = 44] `main` -CHECK-NEXT: parent = 0, end = 168, addr = 0002:0000, code size = 14 +CHECK-NEXT: parent = 0, end = 168, addr = 0001:0000, code size = 14 CHECK-NEXT: type = `0x1004 (int (<no type>))`, debug start = 4, debug end = 9, flags = none CHECK-NEXT: 136 | S_FRAMEPROC [size = 32] CHECK-NEXT: size = 40, padding size = 0, offset to padding = 0 @@ -18,7 +18,7 @@ CHECK-NEXT: flags = has async eh | opt speed CHECK-NEXT: 168 | S_END [size = 4] CHECK-LABEL: Mod 0001 | CHECK: 92 | S_GPROC32 [size = 44] `foo` -CHECK-NEXT: parent = 0, end = 168, addr = 0002:0016, code size = 6 +CHECK-NEXT: parent = 0, end = 168, addr = 0001:0016, code size = 6 CHECK-NEXT: type = `0x1001 (int ())`, debug start = 0, debug end = 5, flags = none CHECK-NEXT: 136 | S_FRAMEPROC [size = 32] CHECK-NEXT: size = 0, padding size = 0, offset to padding = 0 diff --git a/test/COFF/pdb-publics-import.test b/test/COFF/pdb-publics-import.test index 1c75e905ed46..a1fe7d00a08c 100644 --- a/test/COFF/pdb-publics-import.test +++ b/test/COFF/pdb-publics-import.test @@ -6,7 +6,8 @@ RUN: yaml2obj < %p/Inputs/export.yaml > %t1.obj RUN: lld-link /out:%t1.dll /dll %t1.obj /implib:%t1.lib \ RUN: /export:exportfn1 /export:exportfn2 RUN: yaml2obj < %p/Inputs/import.yaml > %t2.obj -RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /debug /entry:main %t2.obj %t1.lib +RUN: lld-link /out:%t2.exe /pdb:%t2.pdb /pdbaltpath:test.pdb \ +RUN: /debug /entry:main %t2.obj %t1.lib RUN: llvm-pdbutil dump %t2.pdb -publics -section-contribs | FileCheck %s CHECK: Public Symbols @@ -19,9 +20,9 @@ CHECK-NEXT: flags = function, addr = 0001:0016 CHECK-NEXT: 88 | S_PUB32 [size = 24] `exportfn2` CHECK-NEXT: flags = function, addr = 0001:0032 CHECK-NEXT: 32 | S_PUB32 [size = 32] `__imp_exportfn2` -CHECK-NEXT: flags = none, addr = 0003:0072 +CHECK-NEXT: flags = none, addr = 0002:0136 CHECK-NEXT: 0 | S_PUB32 [size = 32] `__imp_exportfn1` -CHECK-NEXT: flags = none, addr = 0003:0064 +CHECK-NEXT: flags = none, addr = 0002:0128 CHECK: Section Contributions CHECK-NEXT: ============================================================ @@ -38,5 +39,5 @@ CHECK-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_S .rdata debug directory data chunks CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0000, size = 28, data crc = 0, reloc crc = 0 CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ -CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = {{.*}}, data crc = 0, reloc crc = 0 +CHECK-NEXT: SC[.rdata] | mod = 1, 0002:0028, size = 33, data crc = 0, reloc crc = 0 CHECK-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ diff --git a/test/COFF/pdb-relative-source-lines.test b/test/COFF/pdb-relative-source-lines.test new file mode 100644 index 000000000000..8c0894c21801 --- /dev/null +++ b/test/COFF/pdb-relative-source-lines.test @@ -0,0 +1,45 @@ +Test the linker line tables on roughly the following example: + +==> foo.h <== +void bar(void); +inline void foo(void) { + bar(); +} +==> pdb_lines_1.c <== +#include "foo.h" +int main(void) { + foo(); + return 42; +} +==> pdb_lines_2.c <== +void bar(void) { +} + +$ clang-cl -Xclang -fdebug-compilation-dir -Xclang . -c -Z7 pdb_lines*.c + +RUN: yaml2obj %S/Inputs/pdb_lines_1_relative.yaml -o %t.pdb_lines_1_relative.obj +RUN: yaml2obj %S/Inputs/pdb_lines_2_relative.yaml -o %t.pdb_lines_2_relative.obj +RUN: rm -f %t.exe %t.pdb +RUN: lld-link -debug -pdbsourcepath:c:\\src -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb %t.pdb_lines_1_relative.obj %t.pdb_lines_2_relative.obj +RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | FileCheck %s + +CHECK-LABEL: - Module: {{.*}}pdb_lines_1_relative.obj +CHECK-NEXT: ObjFile: {{.*}}pdb_lines_1_relative.obj +CHECK: SourceFiles: +CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_1.c' +CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}foo.h' +CHECK: Subsections: +CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_1.c' +CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}foo.h' +CHECK: - !FileChecksums +CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_1.c' +CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}foo.h' + +CHECK-LABEL: - Module: {{.*}}pdb_lines_2_relative.obj +CHECK-NEXT: ObjFile: {{.*}}pdb_lines_2_relative.obj +CHECK: SourceFiles: +CHECK-NEXT: - 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c' +CHECK: Subsections: +CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c' +CHECK: - !FileChecksums +CHECK: - FileName: 'c:{{[\\/]}}src{{[\\/]}}pdb_lines_2.c' diff --git a/test/COFF/pdb-same-name.test b/test/COFF/pdb-same-name.test index 76db69fabbd6..352bfc9f9942 100644 --- a/test/COFF/pdb-same-name.test +++ b/test/COFF/pdb-same-name.test @@ -15,9 +15,9 @@ RAW: Modules RAW-NEXT: ============================================================ RAW-NEXT: Mod 0000 | `foo.obj`: RAW-NEXT: Obj: `{{.*}}1\foo.lib`: -RAW-NEXT: debug stream: 9, # files: 1, has ec info: false +RAW-NEXT: debug stream: 11, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0001 | `foo.obj`: RAW-NEXT: Obj: `{{.*}}2\foo.lib`: -RAW-NEXT: debug stream: 10, # files: 1, has ec info: false +RAW-NEXT: debug stream: 12, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` diff --git a/test/COFF/pdb-scopes.test b/test/COFF/pdb-scopes.test index 2649167e900f..f0381f16e5c0 100644 --- a/test/COFF/pdb-scopes.test +++ b/test/COFF/pdb-scopes.test @@ -35,39 +35,39 @@ RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`: CHECK: 104 | S_GPROC32 [size = 44] `g` -CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 5 +CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 5 CHECK: debug start = 4, debug end = 4, flags = none CHECK: 180 | S_REGREL32 [size = 16] `x` CHECK: 196 | S_END [size = 4] CHECK: 200 | S_GPROC32 [size = 44] `main` -CHECK: parent = 0, end = 384, addr = 0002:0016, code size = 58 +CHECK: parent = 0, end = 384, addr = 0001:0016, code size = 58 CHECK: debug start = 8, debug end = 53, flags = none CHECK: 276 | S_REGREL32 [size = 20] `argc` CHECK: 296 | S_BLOCK32 [size = 24] `` CHECK: parent = 200, end = 336 -CHECK: code size = 17, addr = 0002:0031 +CHECK: code size = 17, addr = 0001:0031 CHECK: 320 | S_REGREL32 [size = 16] `x` CHECK: 336 | S_END [size = 4] CHECK: 340 | S_BLOCK32 [size = 24] `` CHECK: parent = 200, end = 380 -CHECK: code size = 17, addr = 0002:0050 +CHECK: code size = 17, addr = 0001:0050 CHECK: 364 | S_REGREL32 [size = 16] `y` CHECK: 380 | S_END [size = 4] CHECK: 384 | S_END [size = 4] CHECK-LABEL: Mod 0001 | `{{.*}}pdb-scopes.test.tmp-b.obj`: CHECK: 104 | S_GPROC32 [size = 44] `f` -CHECK: parent = 0, end = 284, addr = 0002:0080, code size = 62 +CHECK: parent = 0, end = 284, addr = 0001:0080, code size = 62 CHECK: debug start = 8, debug end = 57, flags = none CHECK: 180 | S_REGREL32 [size = 16] `x` CHECK: 196 | S_BLOCK32 [size = 24] `` CHECK: parent = 104, end = 236 -CHECK: code size = 20, addr = 0002:0095 +CHECK: code size = 20, addr = 0001:0095 CHECK: 220 | S_REGREL32 [size = 16] `y` CHECK: 236 | S_END [size = 4] CHECK: 240 | S_BLOCK32 [size = 24] `` CHECK: parent = 104, end = 280 -CHECK: code size = 20, addr = 0002:0117 +CHECK: code size = 20, addr = 0001:0117 CHECK: 264 | S_REGREL32 [size = 16] `w` CHECK: 280 | S_END [size = 4] CHECK: 284 | S_END [size = 4] diff --git a/test/COFF/pdb-source-lines.test b/test/COFF/pdb-source-lines.test index 389d91f20efb..416cab02fd26 100644 --- a/test/COFF/pdb-source-lines.test +++ b/test/COFF/pdb-source-lines.test @@ -26,11 +26,11 @@ RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | CHECK-LABEL: DbiStream: CHECK-NEXT: VerHeader: V70 CHECK-NEXT: Age: 1 -CHECK-NEXT: BuildNumber: 0 +CHECK-NEXT: BuildNumber: 36363 CHECK-NEXT: PdbDllVersion: 0 CHECK-NEXT: PdbDllRbld: 0 CHECK-NEXT: Flags: 0 -CHECK-NEXT: MachineType: x86 +CHECK-NEXT: MachineType: Amd64 CHECK-NEXT: Modules: CHECK-LABEL: - Module: {{.*}}pdb_lines_1.obj @@ -43,7 +43,7 @@ CHECK-NEXT: - !Lines CHECK-NEXT: CodeSize: 19 CHECK-NEXT: Flags: [ ] CHECK-NEXT: RelocOffset: 0 -CHECK-NEXT: RelocSegment: 2 +CHECK-NEXT: RelocSegment: 1 CHECK-NEXT: Blocks: CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c' CHECK-NEXT: Lines: @@ -64,19 +64,11 @@ CHECK-NEXT: LineStart: 5 CHECK-NEXT: IsStatement: true CHECK-NEXT: EndDelta: 0 CHECK-NEXT: Columns: -CHECK-NEXT: - !FileChecksums -CHECK-NEXT: Checksums: -CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c' -CHECK-NEXT: Kind: MD5 -CHECK-NEXT: Checksum: 4EB19DCD86C3BA2238A255C718572E7B -CHECK-NEXT: - FileName: '{{.*}}foo.h' -CHECK-NEXT: Kind: MD5 -CHECK-NEXT: Checksum: 061EB73ABB642532857A4F1D9CBAC323 CHECK-NEXT: - !Lines CHECK-NEXT: CodeSize: 14 CHECK-NEXT: Flags: [ ] CHECK-NEXT: RelocOffset: 32 -CHECK-NEXT: RelocSegment: 2 +CHECK-NEXT: RelocSegment: 1 CHECK-NEXT: Blocks: CHECK-NEXT: - FileName: '{{.*}}foo.h' CHECK-NEXT: Lines: @@ -93,6 +85,14 @@ CHECK-NEXT: LineStart: 4 CHECK-NEXT: IsStatement: true CHECK-NEXT: EndDelta: 0 CHECK-NEXT: Columns: +CHECK-NEXT: - !FileChecksums +CHECK-NEXT: Checksums: +CHECK-NEXT: - FileName: '{{.*}}pdb_lines_1.c' +CHECK-NEXT: Kind: MD5 +CHECK-NEXT: Checksum: 4EB19DCD86C3BA2238A255C718572E7B +CHECK-NEXT: - FileName: '{{.*}}foo.h' +CHECK-NEXT: Kind: MD5 +CHECK-NEXT: Checksum: 061EB73ABB642532857A4F1D9CBAC323 CHECK-LABEL: - Module: {{.*}}pdb_lines_2.obj CHECK-NEXT: ObjFile: {{.*}}pdb_lines_2.obj @@ -103,7 +103,7 @@ CHECK-NEXT: - !Lines CHECK-NEXT: CodeSize: 1 CHECK-NEXT: Flags: [ ] CHECK-NEXT: RelocOffset: 48 -CHECK-NEXT: RelocSegment: 2 +CHECK-NEXT: RelocSegment: 1 CHECK-NEXT: Blocks: CHECK-NEXT: - FileName: '{{.*}}pdb_lines_2.c' CHECK-NEXT: Lines: diff --git a/test/COFF/pdb-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml index 9dad72d3cc2f..0ed1215ec8ee 100644 --- a/test/COFF/pdb-symbol-types.yaml +++ b/test/COFF/pdb-symbol-types.yaml @@ -19,7 +19,7 @@ # CHECK-NEXT: 48 | S_PROCREF [size = 20] `main` # CHECK-NEXT: module = 1, sum name = 0, offset = 116 # CHECK-NEXT: 68 | S_GDATA32 [size = 28] `global_foo` -# CHECK-NEXT: type = 0x1004 (Foo), addr = 0001:0000 +# CHECK-NEXT: type = 0x1004 (Foo), addr = 0003:0000 # CHECK: Symbols # CHECK: ============================================================ @@ -30,7 +30,7 @@ # CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 # CHECK: flags = security checks | hot patchable # CHECK: 116 | S_GPROC32 [size = 44] `main` -# CHECK: parent = 0, end = 192, addr = 0002:0000, code size = 7 +# CHECK: parent = 0, end = 192, addr = 0001:0000, code size = 7 # CHECK: debug start = 0, debug end = 6, flags = none # CHECK: 160 | S_FRAMEPROC [size = 32] # CHECK: size = 0, padding size = 0, offset to padding = 0 diff --git a/test/COFF/pdb-thunk.yaml b/test/COFF/pdb-thunk.yaml index 6435a17e8f62..444800ff9e57 100644 --- a/test/COFF/pdb-thunk.yaml +++ b/test/COFF/pdb-thunk.yaml @@ -84,7 +84,7 @@ sections: RegRelativeSym: Offset: 8 Type: 4097 - Register: RSP + Register: CVRegRSP VarName: this - Kind: S_PROC_ID_END ScopeEndSym: @@ -124,7 +124,7 @@ sections: RegRelativeSym: Offset: 8 Type: 4121 - Register: RSP + Register: CVRegRSP VarName: this - Kind: S_PROC_ID_END ScopeEndSym: @@ -164,7 +164,7 @@ sections: RegRelativeSym: Offset: 48 Type: 4143 - Register: RSP + Register: CVRegRSP VarName: this - Kind: S_PROC_ID_END ScopeEndSym: @@ -208,7 +208,7 @@ sections: RegRelativeSym: Offset: 8 Type: 4143 - Register: RSP + Register: CVRegRSP VarName: this - Kind: S_PROC_ID_END ScopeEndSym: @@ -2176,7 +2176,7 @@ sections: RegRelativeSym: Offset: 8 Type: 4097 - Register: RSP + Register: CVRegRSP VarName: this - Kind: S_PROC_ID_END ScopeEndSym: @@ -2222,7 +2222,7 @@ sections: RegRelativeSym: Offset: 8 Type: 4121 - Register: RSP + Register: CVRegRSP VarName: this - Kind: S_PROC_ID_END ScopeEndSym: diff --git a/test/COFF/pdb-type-server-missing.yaml b/test/COFF/pdb-type-server-missing.yaml index 91bb04f5622f..fbbb46f6b4fd 100644 --- a/test/COFF/pdb-type-server-missing.yaml +++ b/test/COFF/pdb-type-server-missing.yaml @@ -1,13 +1,10 @@ # This is an object compiled with /Zi (see the LF_TYPESERVER2 record) without an # adjacent type server PDB. Test that LLD fails gracefully on it. -# FIXME: Ideally we'd do what MSVC does, which is to warn and drop all debug -# info in the object with the missing PDB. - # RUN: yaml2obj %s -o %t.obj -# RUN: not lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s +# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main 2>&1 | FileCheck %s -# CHECK: error: Type server PDB was not found +# CHECK: warning: Type server PDB for {{.*}}.obj is invalid, ignoring debug info. --- !COFF header: diff --git a/test/COFF/pdb-type-server-simple.test b/test/COFF/pdb-type-server-simple.test index 898c5d4aa130..51a92db8df7a 100644 --- a/test/COFF/pdb-type-server-simple.test +++ b/test/COFF/pdb-type-server-simple.test @@ -72,7 +72,7 @@ CHECK: ============================================================ CHECK-LABEL: Mod 0000 | `{{.*}}a.obj`: CHECK: 4 | S_OBJNAME [size = 40] sig=0, `C:\src\llvm-project\build\a.obj` CHECK: 104 | S_GPROC32 [size = 44] `main` -CHECK: parent = 0, end = 196, addr = 0002:0000, code size = 27 +CHECK: parent = 0, end = 196, addr = 0001:0000, code size = 27 CHECK: type = {{.*}}, debug start = 4, debug end = 22, flags = none CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[A_BUILD]]` CHECK-LABEL: Mod 0001 | `{{.*}}b.obj`: @@ -82,14 +82,14 @@ CHECK: machine = intel x86-x64, Ver = Microsoft (R) Optimizing Compil CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 CHECK: flags = security checks | hot patchable CHECK: 104 | S_GPROC32 [size = 44] `g` -CHECK: parent = 0, end = 196, addr = 0002:0032, code size = 13 +CHECK: parent = 0, end = 196, addr = 0001:0032, code size = 13 CHECK: type = {{.*}}, debug start = 5, debug end = 12, flags = none CHECK: 148 | S_FRAMEPROC [size = 32] CHECK: size = 0, padding size = 0, offset to padding = 0 CHECK: bytes of callee saved registers = 0, exception handler addr = 0000:0000 CHECK: flags = has async eh | opt speed CHECK: 180 | S_REGREL32 [size = 16] `p` -CHECK: type = [[FOO_PTR]] (Foo*), register = RSP, offset = 8 +CHECK: type = [[FOO_PTR]] (Foo*), register = CVRegRSP, offset = 8 CHECK: 196 | S_END [size = 4] CHECK: 200 | S_BUILDINFO [size = 8] BuildId = `[[B_BUILD]]` CHECK-LABEL: Mod 0002 | `* Linker *`: diff --git a/test/COFF/pdb.test b/test/COFF/pdb.test index dad6de25db58..a7b2a215ec6b 100644 --- a/test/COFF/pdb.test +++ b/test/COFF/pdb.test @@ -1,8 +1,8 @@ # RUN: yaml2obj < %p/Inputs/pdb1.yaml > %t1.obj # RUN: yaml2obj < %p/Inputs/pdb2.yaml > %t2.obj # RUN: rm -f %t.dll %t.pdb -# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:main /nodefaultlib \ -# RUN: %t1.obj %t2.obj +# RUN: lld-link /debug /pdb:%t.pdb /pdbaltpath:test.pdb /dll /out:%t.dll \ +# RUN: /entry:main /nodefaultlib %t1.obj %t2.obj # RUN: llvm-pdbutil pdb2yaml -stream-metadata -stream-directory -pdb-stream \ # RUN: -dbi-stream -ipi-stream -tpi-stream %t.pdb | FileCheck %s @@ -14,7 +14,7 @@ # CHECK: MSF: # CHECK-NEXT: SuperBlock: # CHECK-NEXT: BlockSize: 4096 -# CHECK-NEXT: FreeBlockMap: 1 +# CHECK-NEXT: FreeBlockMap: 2 # CHECK-NEXT: NumBlocks: # CHECK-NEXT: NumDirectoryBytes: # CHECK-NEXT: Unknown1: 0 @@ -34,11 +34,11 @@ # CHECK-NEXT: DbiStream: # CHECK-NEXT: VerHeader: V70 # CHECK-NEXT: Age: 1 -# CHECK-NEXT: BuildNumber: 0 +# CHECK-NEXT: BuildNumber: 36363 # CHECK-NEXT: PdbDllVersion: 0 # CHECK-NEXT: PdbDllRbld: 0 # CHECK-NEXT: Flags: 0 -# CHECK-NEXT: MachineType: x86 +# CHECK-NEXT: MachineType: Amd64 # CHECK-NEXT: TpiStream: # CHECK-NEXT: Version: VC80 # CHECK-NEXT: Records: @@ -120,16 +120,24 @@ RAW: Modules RAW-NEXT: ============================================================ RAW-NEXT: Mod 0000 | `{{.*}}pdb.test.tmp1.obj`: +RAW-NEXT: SC[.text] | mod = 0, 0001:0000, size = 14, data crc = 1682752513, reloc crc = 0 +RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | +RAW-NEXT: IMAGE_SCN_MEM_READ RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`: -RAW-NEXT: debug stream: 9, # files: 1, has ec info: false +RAW-NEXT: debug stream: 11, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0001 | `{{.*}}pdb.test.tmp2.obj`: +RAW-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 2139436471, reloc crc = 0 +RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | +RAW-NEXT: IMAGE_SCN_MEM_READ RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`: -RAW-NEXT: debug stream: 10, # files: 1, has ec info: false +RAW-NEXT: debug stream: 12, # files: 1, has ec info: false RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0002 | `* Linker *`: +RAW-NEXT: SC[???] | mod = 2, 0000:0000, size = 0, data crc = 0, reloc crc = 0 +RAW-NEXT: none RAW-NEXT: Obj: ``: -RAW-NEXT: debug stream: 11, # files: 0, has ec info: false +RAW-NEXT: debug stream: 13, # files: 0, has ec info: false RAW-NEXT: pdb file ni: 1 `{{.*pdb.test.tmp.pdb}}`, src file ni: 0 `` RAW: Types (TPI Stream) RAW-NEXT: ============================================================ @@ -181,10 +189,29 @@ RAW-NEXT: GSI Header RAW-NEXT: sig = 0xFFFFFFFF, hdr = 0xF12F091A, hr size = 16, num buckets = 524 RAW-NEXT: Records RAW-NEXT: 20 | S_PUB32 [size = 20] `main` -RAW-NEXT: flags = function, addr = 0002:0000 +RAW-NEXT: flags = function, addr = 0001:0000 RAW-NEXT: 0 | S_PUB32 [size = 20] `foo` -RAW-NEXT: flags = function, addr = 0002:0016 +RAW-NEXT: flags = function, addr = 0001:0016 RAW-NOT: S_PUB32 +RAW-NEXT: Hash Bitmap ( +RAW-NEXT: 0000: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0020: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0040: 00000000 20000000 00000000 00000000 00000000 00000000 00000000 00000000 |.... ...........................| +RAW-NEXT: 0060: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0080: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 00A0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 00C0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 00E0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0100: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0120: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0140: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0160: 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0180: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 01A0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 01C0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 01E0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 |................................| +RAW-NEXT: 0200: 00000000 |....| +RAW-NEXT: ) RAW-NEXT: Hash Entries RAW-NEXT: off = 21, refcnt = 1 RAW-NEXT: off = 1, refcnt = 1 @@ -196,93 +223,80 @@ RAW-NEXT: off = 20 RAW-NEXT: off = 0 RAW: Section Headers RAW-NEXT: ============================================================ + RAW: SECTION HEADER #1 -RAW-NEXT: .pdata name -RAW-NEXT: virtual size -RAW-NEXT: 1000 virtual address -RAW-NEXT: 200 size of raw data -RAW-NEXT: 400 file pointer to raw data -RAW-NEXT: 0 file pointer to relocation table -RAW-NEXT: 0 file pointer to line numbers -RAW-NEXT: 0 number of relocations -RAW-NEXT: 0 number of line numbers -RAW-NEXT: 40000040 flags -RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA -RAW-NEXT: IMAGE_SCN_MEM_READ +RAW-NEXT: .text name +RAW-NEXT: 16 virtual size +RAW-NEXT: 1000 virtual address +RAW-NEXT: 200 size of raw data +RAW-NEXT: 400 file pointer to raw data +RAW-NEXT: 0 file pointer to relocation table +RAW-NEXT: 0 file pointer to line numbers +RAW-NEXT: 0 number of relocations +RAW-NEXT: 0 number of line numbers +RAW-NEXT: 60000020 flags +RAW-NEXT: IMAGE_SCN_CNT_CODE +RAW-NEXT: IMAGE_SCN_MEM_EXECUTE +RAW-NEXT: IMAGE_SCN_MEM_READ RAW: SECTION HEADER #2 -RAW-NEXT: .text name -RAW-NEXT: virtual size -RAW-NEXT: 2000 virtual address -RAW-NEXT: 200 size of raw data -RAW-NEXT: 600 file pointer to raw data -RAW-NEXT: 0 file pointer to relocation table -RAW-NEXT: 0 file pointer to line numbers -RAW-NEXT: 0 number of relocations -RAW-NEXT: 0 number of line numbers -RAW-NEXT: 60000020 flags -RAW-NEXT: IMAGE_SCN_CNT_CODE -RAW-NEXT: IMAGE_SCN_MEM_EXECUTE -RAW-NEXT: IMAGE_SCN_MEM_READ +RAW-NEXT: .rdata name +RAW-NEXT: virtual size +RAW-NEXT: 2000 virtual address +RAW-NEXT: 200 size of raw data +RAW-NEXT: 600 file pointer to raw data +RAW-NEXT: 0 file pointer to relocation table +RAW-NEXT: 0 file pointer to line numbers +RAW-NEXT: 0 number of relocations +RAW-NEXT: 0 number of line numbers +RAW-NEXT: 40000040 flags +RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +RAW-NEXT: IMAGE_SCN_MEM_READ RAW: SECTION HEADER #3 -RAW-NEXT: .xdata name -RAW-NEXT: virtual size -RAW-NEXT: 3000 virtual address -RAW-NEXT: 200 size of raw data -RAW-NEXT: 800 file pointer to raw data -RAW-NEXT: 0 file pointer to relocation table -RAW-NEXT: 0 file pointer to line numbers -RAW-NEXT: 0 number of relocations -RAW-NEXT: 0 number of line numbers -RAW-NEXT: 40000040 flags -RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA -RAW-NEXT: IMAGE_SCN_MEM_READ -RAW: SECTION HEADER #4 -RAW-NEXT: .rdata name -RAW-NEXT: virtual size -RAW-NEXT: 4000 virtual address -RAW-NEXT: 200 size of raw data -RAW-NEXT: A00 file pointer to raw data -RAW-NEXT: 0 file pointer to relocation table -RAW-NEXT: 0 file pointer to line numbers -RAW-NEXT: 0 number of relocations -RAW-NEXT: 0 number of line numbers -RAW-NEXT: 40000040 flags -RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA -RAW-NEXT: IMAGE_SCN_MEM_READ +RAW-NEXT: .pdata name +RAW-NEXT: C virtual size +RAW-NEXT: 3000 virtual address +RAW-NEXT: 200 size of raw data +RAW-NEXT: 800 file pointer to raw data +RAW-NEXT: 0 file pointer to relocation table +RAW-NEXT: 0 file pointer to line numbers +RAW-NEXT: 0 number of relocations +RAW-NEXT: 0 number of line numbers +RAW-NEXT: 40000040 flags +RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA +RAW-NEXT: IMAGE_SCN_MEM_READ RAW: Original Section Headers RAW-NEXT: ============================================================ RAW-NEXT: PDB does not contain the requested image section header type RAW: Section Contributions RAW-NEXT: ============================================================ -RAW-NEXT: SC[.pdata] | mod = 0, 0001:0000, size = 12, data crc = 361370162, reloc crc = 0 -RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ -RAW-NEXT: SC[.text] | mod = 0, 0002:0000, size = 14, data crc = 1682752513, reloc crc = 0 + +RAW-NEXT: SC[.text] | mod = 0, 0001:0000, size = 14, data crc = 1682752513, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | RAW-NEXT: IMAGE_SCN_MEM_READ -RAW-NEXT: SC[.text] | mod = 1, 0002:0016, size = 6, data crc = 2139436471, reloc crc = 0 +RAW-NEXT: SC[.text] | mod = 1, 0001:0016, size = 6, data crc = 2139436471, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_CODE | IMAGE_SCN_ALIGN_16BYTES | IMAGE_SCN_MEM_EXECUTE | RAW-NEXT: IMAGE_SCN_MEM_READ -RAW-NEXT: SC[.xdata] | mod = 0, 0003:0000, size = 8, data crc = 264583633, reloc crc = 0 -RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ -RAW-NEXT: SC[???] | mod = 2, 0004:0000, size = {{[0-9]+}}, data crc = 0, reloc crc = 0 +RAW-NEXT: SC[.rdata] | mod = 2, 0002:0000, size = {{[0-9]+}}, data crc = 0, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ -RAW-NEXT: SC[???] | mod = 2, 0004:0028, size = {{[0-9]+}}, data crc = 0, reloc crc = 0 +RAW-NEXT: SC[.rdata] | mod = 2, 0002:0028, size = {{[0-9]+}}, data crc = 0, reloc crc = 0 RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ +RAW-NEXT: SC[.rdata] | mod = 0, 0002:0064, size = {{[0-9]+}}, data crc = 264583633, reloc crc = 0 +RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ +RAW-NEXT: SC[.pdata] | mod = 0, 0003:0000, size = 12, data crc = 361370162, reloc crc = 0 +RAW-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_MEM_READ RAW-NOT: SC[ RAW: Section Map RAW-NEXT: ============================================================ + RAW-NEXT: Section 0000 | ovl = 0, group = 0, frame = 1, name = 65535 RAW-NEXT: class = 65535, offset = 0, size = -RAW-NEXT: flags = read | 32 bit addr | selector +RAW-NEXT: flags = read | execute | 32 bit addr | selector RAW-NEXT: Section 0001 | ovl = 0, group = 0, frame = 2, name = 65535 RAW-NEXT: class = 65535, offset = 0, size = -RAW-NEXT: flags = read | execute | 32 bit addr | selector +RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0002 | ovl = 0, group = 0, frame = 3, name = 65535 RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0003 | ovl = 0, group = 0, frame = 4, name = 65535 -RAW-NEXT: class = 65535, offset = 0, size = -RAW-NEXT: flags = read | 32 bit addr | selector -RAW-NEXT: Section 0004 | ovl = 0, group = 0, frame = 5, name = 65535 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = 4294967295 RAW-NEXT: flags = 32 bit addr | absolute addr diff --git a/test/COFF/pending-comdat.s b/test/COFF/pending-comdat.s new file mode 100644 index 000000000000..b10dce1f1ea4 --- /dev/null +++ b/test/COFF/pending-comdat.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -triple=x86_64-windows-gnu %s -filetype=obj -o %t.obj + +# RUN: not lld-link -lldmingw -out:%t.exe -entry:main -subsystem:console %t.obj 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: other + +# Check that the comdat section without a symbol isn't left pending once we iterate symbols +# to print source of the undefined symbol. + + .text + .globl main +main: + call other + ret + + .section .data$pending,"w" + .linkonce discard +.Llocal: + .byte 0 diff --git a/test/COFF/reloc-arm.test b/test/COFF/reloc-arm.test index 872e6d53c8aa..87d93ed76bf2 100644 --- a/test/COFF/reloc-arm.test +++ b/test/COFF/reloc-arm.test @@ -3,14 +3,14 @@ # RUN: llvm-objdump -s %t.exe | FileCheck %s # CHECK: .text: -# CHECK: 402000 01104000 00000000 00000000 00000000 -# CHECK: 402010 01100000 00000000 00000000 00000000 -# CHECK: 402020 41f20009 c0f24009 00000000 00000000 -# CHECK: 402030 fe07e62f 00000000 00000000 00000000 -# CHECK: 402040 3e04de2f 00000000 00000000 00000000 -# CHECK: 402050 fe07d62f 00000000 00000000 00000000 -# CHECK: 402060 fef0cef7 00000000 00000000 00000000 -# CHECK: 402070 00005000 00000000 00000000 00000000 +# CHECK: 401000 01204000 00000000 00000000 00000000 +# CHECK: 401010 01200000 00000000 00000000 00000000 +# CHECK: 401020 42f20009 c0f24009 00000000 00000000 +# CHECK: 401030 0000e62f 00000000 00000000 00000000 +# CHECK: 401040 0000de07 00000000 00000000 00000000 +# CHECK: 401050 0000d62f 00000000 00000000 00000000 +# CHECK: 401060 00f1cef7 00000000 00000000 00000000 +# CHECK: 401070 00005000 00000000 00000000 00000000 --- !COFF header: diff --git a/test/COFF/reloc-discarded-dwarf.s b/test/COFF/reloc-discarded-dwarf.s index 14dc5948b32a..960f3b308a97 100644 --- a/test/COFF/reloc-discarded-dwarf.s +++ b/test/COFF/reloc-discarded-dwarf.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t1.obj %s # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t2.obj %s diff --git a/test/COFF/reloc-discarded-early.s b/test/COFF/reloc-discarded-early.s index 6d1043dbfa74..181859db9e64 100644 --- a/test/COFF/reloc-discarded-early.s +++ b/test/COFF/reloc-discarded-early.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s # RUN: lld-link -entry:__ImageBase -subsystem:console -debug %t.obj diff --git a/test/COFF/reloc-discarded-early2.s b/test/COFF/reloc-discarded-early2.s index 18e200008721..c5589dc89935 100644 --- a/test/COFF/reloc-discarded-early2.s +++ b/test/COFF/reloc-discarded-early2.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s # RUN: not lld-link -entry:__ImageBase -subsystem:console %t.obj 2>&1 | FileCheck %s diff --git a/test/COFF/reloc-discarded.s b/test/COFF/reloc-discarded.s index 0be4e110b4db..aa8fb3c3447a 100644 --- a/test/COFF/reloc-discarded.s +++ b/test/COFF/reloc-discarded.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: echo -e '.section .bss,"bw",discard,main_global\n.global main_global\n main_global:\n .long 0' | \ # RUN: llvm-mc - -filetype=obj -o %t1.obj -triple x86_64-windows-msvc # RUN: llvm-mc %s -filetype=obj -o %t2.obj -triple x86_64-windows-msvc diff --git a/test/COFF/reloc-x64.test b/test/COFF/reloc-x64.test index 7af8fb24bd38..21d78428ffeb 100644 --- a/test/COFF/reloc-x64.test +++ b/test/COFF/reloc-x64.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /out:%t.exe /entry:main %t.obj # RUN: llvm-objdump -d %t.exe | FileCheck %s diff --git a/test/COFF/reloc-x86.test b/test/COFF/reloc-x86.test index 5e1406913756..bd500be164a7 100644 --- a/test/COFF/reloc-x86.test +++ b/test/COFF/reloc-x86.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /out:%t.exe /entry:main /base:0x400000 %t.obj # RUN: llvm-objdump -d %t.exe | FileCheck %s diff --git a/test/COFF/resource.test b/test/COFF/resource.test index 53242cdcb63a..4108957f6f68 100644 --- a/test/COFF/resource.test +++ b/test/COFF/resource.test @@ -10,11 +10,11 @@ EXE: {{H.e.l.l.o}} # RUN: llvm-readobj -file-headers -coff-resources -section-data %t.exe | \ # RUN: FileCheck --check-prefix=RESOURCE_INFO %s -RESOURCE_INFO: ResourceTableRVA: 0x1000 -RESOURCE_INFO-NEXT: ResourceTableSize: 0x88 +RESOURCE_INFO: ResourceTableRVA: 0x2000 +RESOURCE_INFO-NEXT: ResourceTableSize: 0x90 RESOURCE_INFO-DAG: Resources [ RESOURCE_INFO-NEXT: Total Number of Resources: 1 -RESOURCE_INFO-NEXT: Base Table Address: 0x400 +RESOURCE_INFO-NEXT: Base Table Address: 0x600 RESOURCE_INFO-DAG: Number of String Entries: 0 RESOURCE_INFO-NEXT: Number of ID Entries: 1 RESOURCE_INFO-NEXT: Type: kRT_STRING (ID 6) [ @@ -36,9 +36,9 @@ RESOURCE_INFO-NEXT: 0000: 00000000 00000000 00000000 00000100 |................ RESOURCE_INFO-NEXT: 0010: 06000000 18000080 00000000 00000000 |................| RESOURCE_INFO-NEXT: 0020: 00000000 00000100 01000000 30000080 |............0...| RESOURCE_INFO-NEXT: 0030: 00000000 00000000 00000000 00000100 |................| -RESOURCE_INFO-NEXT: 0040: 09040000 48000000 58100000 2A000000 |....H...X...*...| -RESOURCE_INFO-NEXT: 0050: 00000000 00000000 00000500 48006500 |............H.e.| -RESOURCE_INFO-NEXT: 0060: 6C006C00 6F000000 00000000 00000000 |l.l.o...........| +RESOURCE_INFO-NEXT: 0040: 09040000 48000000 60200000 2A000000 |....H...` ..*...| +RESOURCE_INFO-NEXT: 0050: 00000000 00000000 00000000 00000000 |................| +RESOURCE_INFO-NEXT: 0060: 00000500 48006500 6C006C00 6F000000 |....H.e.l.l.o...| RESOURCE_INFO-NEXT: 0070: 00000000 00000000 00000000 00000000 |................| -RESOURCE_INFO-NEXT: 0080: 00000000 00000000 |........| +RESOURCE_INFO-NEXT: 0080: 00000000 00000000 00000000 00000000 |................| RESOURCE_INFO-NEXT: ) diff --git a/test/COFF/rsds.test b/test/COFF/rsds.test index 176597786848..6ce92a9c5b03 100644 --- a/test/COFF/rsds.test +++ b/test/COFF/rsds.test @@ -1,16 +1,16 @@ # RUN: yaml2obj %s > %t.obj # RUN: rm -f %t.dll %t.pdb -# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: lld-link /debug /pdbaltpath:test1.pdb /dll /out:%t.dll /entry:DllMain %t.obj # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.1.txt -# RUN: lld-link /debug /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: lld-link /debug /pdbaltpath:test2.pdb /dll /out:%t.dll /entry:DllMain %t.obj # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.2.txt # RUN: cat %t.1.txt %t.2.txt | FileCheck %s # RUN: rm -f %t.dll %t.pdb -# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: lld-link /debug /pdb:%t1.pdb /dll /out:%t.dll /entry:DllMain %t.obj # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.3.txt -# RUN: lld-link /debug /pdb:%t.pdb /dll /out:%t.dll /entry:DllMain %t.obj +# RUN: lld-link /debug /pdb:%t2.pdb /dll /out:%t.dll /entry:DllMain %t.obj # RUN: llvm-readobj -coff-debug-directory %t.dll > %t.4.txt # RUN: cat %t.3.txt %t.4.txt | FileCheck %s @@ -18,7 +18,7 @@ # CHECK: DebugDirectory [ # CHECK: DebugEntry { # CHECK: Characteristics: 0x0 -# CHECK: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +# CHECK: TimeDateStamp: # CHECK: MajorVersion: 0x0 # CHECK: MinorVersion: 0x0 # CHECK: Type: CodeView (0x2) @@ -29,7 +29,7 @@ # CHECK: PDBSignature: 0x53445352 # CHECK: PDBGUID: [[GUID:\(([A-Za-z0-9]{2} ?){16}\)]] # CHECK: PDBAge: 1 -# CHECK: PDBFileName: {{.*}}.pdb +# CHECK: PDBFileName: {{.*}}1.pdb # CHECK: } # CHECK: } # CHECK: ] @@ -37,7 +37,7 @@ # CHECK: DebugDirectory [ # CHECK: DebugEntry { # CHECK: Characteristics: 0x0 -# CHECK: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +# CHECK: TimeDateStamp: # CHECK: MajorVersion: 0x0 # CHECK: MinorVersion: 0x0 # CHECK: Type: CodeView (0x2) @@ -48,7 +48,7 @@ # CHECK: PDBSignature: 0x53445352 # CHECK: PDBGUID: [[GUID]] # CHECK: PDBAge: 2 -# CHECK: PDBFileName: {{.*}}.pdb +# CHECK: PDBFileName: {{.*}}2.pdb # CHECK: } # CHECK: } # CHECK: ] diff --git a/test/COFF/safeseh-md.s b/test/COFF/safeseh-md.s index ae731b5211df..b762457a9bb9 100644 --- a/test/COFF/safeseh-md.s +++ b/test/COFF/safeseh-md.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj # RUN: lld-link %t.obj %S/Inputs/except_handler3.lib -safeseh -out:%t.exe -opt:noref -entry:main # RUN: llvm-readobj -coff-load-config %t.exe | FileCheck %s diff --git a/test/COFF/safeseh-notable.s b/test/COFF/safeseh-notable.s new file mode 100644 index 000000000000..8a9d4296dad6 --- /dev/null +++ b/test/COFF/safeseh-notable.s @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj +# RUN: lld-link %t.obj -safeseh -out:%t.exe -entry:main +# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s + +# This object lacks a _load_config_used global, so we set +# IMAGE_DLL_CHARACTERISTICS_NO_SEH even though there is an exception handler. +# This is a more secure default. If someone wants to use a CRT without a load +# config and they want to use 32-bit SEH, they will need to provide a +# safeseh-compatible load config. + +# CHECK-LABEL: Characteristics [ +# CHECK: IMAGE_DLL_CHARACTERISTICS_NO_SEH +# CHECK: ] + +# CHECK-LABEL: DataDirectory { +# CHECK: LoadConfigTableRVA: 0x0 +# CHECK: LoadConfigTableSize: 0x0 +# CHECK: } + +# CHECK-NOT: LoadConfig +# CHECK-NOT: SEHTable + + .def @feat.00; + .scl 3; + .type 0; + .endef + .globl @feat.00 +@feat.00 = 1 + + .text + .def _main; .scl 2; .type 32; .endef + .globl _main +_main: + pushl $_my_handler + movl $42, %eax + popl %ecx + ret + + .def _my_handler; .scl 3; .type 32; .endef +_my_handler: + ret + +.safeseh _my_handler diff --git a/test/COFF/safeseh.s b/test/COFF/safeseh.s index 35f54c590d13..ee6a60d0df21 100644 --- a/test/COFF/safeseh.s +++ b/test/COFF/safeseh.s @@ -1,27 +1,36 @@ +# REQUIRES: x86 # RUN: llvm-mc -triple i686-windows-msvc %s -filetype=obj -o %t.obj # RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main # RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC +# RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:noref -entry:main -debug:dwarf +# RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-NOGC # RUN: lld-link %t.obj -safeseh -out:%t.exe -opt:ref -entry:main # RUN: llvm-readobj -coff-basereloc -coff-load-config -file-headers %t.exe | FileCheck %s --check-prefix=CHECK-GC # __safe_se_handler_table needs to be relocated against ImageBase. # check that the relocation is present. +# # CHECK-NOGC-NOT: IMAGE_DLL_CHARACTERISTICS_NO_SEH # CHECK-NOGC: BaseReloc [ # CHECK-NOGC: Entry { # CHECK-NOGC: Type: HIGHLOW # CHECK-NOGC: LoadConfig [ # CHECK-NOGC: Size: 0x48 -# CHECK-NOGC: SEHandlerTable: 0x401048 +# CHECK-NOGC: SEHandlerTable: 0x # CHECK-NOGC: SEHandlerCount: 1 # CHECK-NOGC: ] # CHECK-NOGC: SEHTable [ -# CHECK-NOGC-NEXT: 0x402006 +# CHECK-NOGC-NEXT: 0x401006 # CHECK-NOGC-NEXT: ] -# Without the SEH table, the address is absolute, so check that we do -# not have a relocation for it. -# CHECK-GC-NOT: IMAGE_DLL_CHARACTERISTICS_NO_SEH +# If we enable GC, the exception handler should be removed, and we should add +# the DLL characteristic flag that indicates that there are no exception +# handlers in this DLL. The exception handler table in the load config should +# be empty and there should be no relocations for it. +# +# CHECK-GC: Characteristics [ +# CHECK-GC: IMAGE_DLL_CHARACTERISTICS_NO_SEH +# CHECK-GC: ] # CHECK-GC: BaseReloc [ # CHECK-GC-NEXT: ] # CHECK-GC: LoadConfig [ diff --git a/test/COFF/secidx-absolute.s b/test/COFF/secidx-absolute.s index bfe7136b31d2..0b467bbb09bf 100644 --- a/test/COFF/secidx-absolute.s +++ b/test/COFF/secidx-absolute.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj # RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe # RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s @@ -16,17 +17,17 @@ ret # CHECK: Sections [ # CHECK: Section { # CHECK: Number: 1 -# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00) +# CHECK: Name: .text (2E 74 65 78 74 00 00 00) +# CHECK: VirtualSize: 0x1 # CHECK: SectionData ( -# CHECK: 0000: 0300 |..| +# CHECK: 0000: C3 |.| # CHECK: ) # CHECK: } # CHECK: Section { # CHECK: Number: 2 -# CHECK: Name: .text (2E 74 65 78 74 00 00 00) -# CHECK: VirtualSize: 0x1 +# CHECK: Name: .rdata (2E 72 64 61 74 61 00 00) # CHECK: SectionData ( -# CHECK: 0000: C3 |.| +# CHECK: 0000: 0300 |..| # CHECK: ) # CHECK: } # CHECK-NOT: Section diff --git a/test/COFF/secrel-absolute.s b/test/COFF/secrel-absolute.s index bc61fb94b6b0..630af6e72276 100644 --- a/test/COFF/secrel-absolute.s +++ b/test/COFF/secrel-absolute.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj # RUN: not lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe 2>&1 | FileCheck %s diff --git a/test/COFF/secrel-common.s b/test/COFF/secrel-common.s index 0188f6cb9674..0d3aafcad001 100644 --- a/test/COFF/secrel-common.s +++ b/test/COFF/secrel-common.s @@ -1,29 +1,31 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -filetype=obj -triple=x86_64-windows-msvc -o %t.obj # RUN: lld-link -entry:main -nodefaultlib %t.obj -out:%t.exe # RUN: llvm-readobj %t.exe -sections -section-data | FileCheck %s -# Section relocations against common symbols resolve to .bss. +# Section relocations against common symbols resolve to .bss (merged into .data). # CHECK: Sections [ # CHECK: Section { # CHECK: Number: 1 -# CHECK: Name: .bss (2E 62 73 73 00 00 00 00) -# CHECK: VirtualSize: 0x4 +# CHECK: Name: .text (2E 74 65 78 74 00 00 00) +# CHECK: VirtualSize: 0x1 +# CHECK: SectionData ( +# CHECK: 0000: C3 |.| +# CHECK: ) # CHECK: } # CHECK: Section { # CHECK: Number: 2 # CHECK: Name: .rdata (2E 72 64 61 74 61 00 00) # CHECK: SectionData ( -# CHECK: 0000: 00000000 01000000 |........| +# CHECK: 0000: 00020000 03000000 |........| # CHECK: ) # CHECK: } # CHECK: Section { # CHECK: Number: 3 -# CHECK: Name: .text (2E 74 65 78 74 00 00 00) -# CHECK: VirtualSize: 0x1 -# CHECK: SectionData ( -# CHECK: 0000: C3 |.| -# CHECK: ) +# CHECK: Name: .data (2E 64 61 74 61 00 00 00) +# CHECK: VirtualSize: 0x204 +# CHECK: RawDataSize: 512 # CHECK: } # CHECK-NOT: Section # CHECK: ] @@ -39,3 +41,6 @@ ret .secrel32 common_global .secidx common_global .short 0 + +.section .data,"drw" +.zero 512 diff --git a/test/COFF/section-order.test b/test/COFF/section-order.test new file mode 100644 index 000000000000..2e0279285b78 --- /dev/null +++ b/test/COFF/section-order.test @@ -0,0 +1,15 @@ +# RUN: yaml2obj < %p/Inputs/include1a.yaml > %t1.obj +# RUN: yaml2obj < %p/Inputs/include1b.yaml > %t2.obj +# RUN: yaml2obj < %p/Inputs/include1c.yaml > %t3.obj +# RUN: rm -f %t2.lib %t3.lib +# RUN: llvm-ar cru %t2.lib %t2.obj +# RUN: llvm-ar cru %t3.lib %t3.obj +# RUN: lld-link /out:%t.exe /entry:main \ +# RUN: %t1.obj %t2.lib %t3.obj %t3.lib /verbose >& %t.log +# RUN: FileCheck %s < %t.log + +CHECK: section-order.test.tmp1.obj +CHECK: section-order.test.tmp2.lib +CHECK: section-order.test.tmp3.obj +CHECK: section-order.test.tmp3.lib +CHECK: section-order.test.tmp2.lib(section-order.test.tmp2.obj) for foo diff --git a/test/COFF/section-size.s b/test/COFF/section-size.s index 28f3f4acbc9d..d971b6efa5e8 100644 --- a/test/COFF/section-size.s +++ b/test/COFF/section-size.s @@ -7,7 +7,7 @@ # Run: lld-link -entry:main %tmain.obj %t3.obj -out:%t.exe # RUN: not lld-link -entry:main %tmain.obj %t1.obj %t2.obj -out:%t.exe 2>&1 | FileCheck %s -# CHECK: error: section larger than 4 GiB: .bss +# CHECK: error: section larger than 4 GiB: .data .globl main main: diff --git a/test/COFF/section.test b/test/COFF/section.test index 591c04dde73f..5e1162e8f358 100644 --- a/test/COFF/section.test +++ b/test/COFF/section.test @@ -16,18 +16,22 @@ # RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=S %s # R: Characteristics [ +# R-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA # R-NEXT: IMAGE_SCN_MEM_READ # R-NEXT: ] # W: Characteristics [ +# W-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA # W-NEXT: IMAGE_SCN_MEM_WRITE # W-NEXT: ] # E: Characteristics [ +# E-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA # E-NEXT: IMAGE_SCN_MEM_EXECUTE # E-NEXT: ] # S: Characteristics [ +# S-NEXT: IMAGE_SCN_CNT_INITIALIZED_DATA # S-NEXT: IMAGE_SCN_MEM_SHARED # S-NEXT: ] diff --git a/test/COFF/sort-debug.test b/test/COFF/sort-debug.test index 3bad013a309a..5e2701b6610d 100644 --- a/test/COFF/sort-debug.test +++ b/test/COFF/sort-debug.test @@ -1,15 +1,28 @@ # RUN: yaml2obj < %s > %t.obj # RUN: lld-link /debug /out:%t.exe /entry:main %t.obj # RUN: llvm-readobj -sections %t.exe | FileCheck %s +# RUN: lld-link /debug:dwarf /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck %s +# RUN: lld-link /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=NODEBUG %s +# RUN: lld-link /debug:symtab /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -sections %t.exe | FileCheck -check-prefix=NODEBUG %s # CHECK: Name: .text +# CHECK: Name: .reloc # CHECK: Name: .debug_abbrev # CHECK: Name: .debug_info # CHECK: Name: .debug_line # CHECK: Name: .debug_pubnames # CHECK: Name: .debug_pubtypes -# CHECK: Name: .reloc +# NODEBUG: Name: .text +# NODEBUG: Name: .reloc +# NODEBUG-NOT: Name: .debug_abbrev +# NODEBUG-NOT: Name: .debug_info +# NODEBUG-NOT: Name: .debug_line +# NODEBUG-NOT: Name: .debug_pubnames +# NODEBUG-NOT: Name: .debug_pubtypes --- !COFF header: diff --git a/test/COFF/string-tail-merge.s b/test/COFF/string-tail-merge.s new file mode 100644 index 000000000000..2e3b735dbf90 --- /dev/null +++ b/test/COFF/string-tail-merge.s @@ -0,0 +1,106 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s +# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console +# RUN: llvm-objdump -s %t.exe | FileCheck %s +# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:noicf /opt:lldtailmerge +# RUN: llvm-objdump -s %t.exe | FileCheck %s +# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:noicf +# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=NOSTM %s +# RUN: lld-link %t.obj /out:%t.exe /entry:main /subsystem:console /opt:nolldtailmerge +# RUN: llvm-objdump -s %t.exe | FileCheck --check-prefix=NOSTM %s + +# CHECK: Contents of section .text: +# NOSTM: Contents of section .text: +.globl main +main: +# CHECK-NEXT: 140001000 11200040 01000000 17200040 01000000 +# NOSTM-NEXT: 140001000 00200040 01000000 0c200040 01000000 +.8byte "??_C@_0M@LACCCNMM@hello?5world?$AA@" +.8byte "??_C@_05MCBCHHEJ@world?$AA@" +# CHECK-NEXT: 140001010 2a200040 01000000 36200040 01000000 +# NOSTM-NEXT: 140001010 12200040 01000000 2a200040 01000000 +.8byte "??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@" +.8byte "??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@" +# CHECK-NEXT: 140001020 00200040 01000000 0c200040 01000000 +# NOSTM-NEXT: 140001020 36200040 01000000 42200040 01000000 +.8byte "??_D@not_a_string_literal" +.8byte "??_C@string_literal_with_relocs" +# CHECK-NEXT: 140001030 00300040 01000000 1e200040 01000000 +# NOSTM-NEXT: 140001030 00300040 01000000 48200040 01000000 +.8byte "??_C@string_literal_in_wrong_section" +.8byte "??_C@overaligned_string_literal" + +# CHECK: Contents of section .rdata: +# CHECK-NEXT: 140002000 68656c6c 6f20776f 726c6400 6f826ca4 hello world.o.l. +# CHECK-NEXT: 140002010 0068656c 6c6f2077 6f726c64 00006865 .hello world..he +# CHECK-NEXT: 140002020 6c6c6f20 776f726c 64006800 65006c00 llo world.h.e.l. +# CHECK-NEXT: 140002030 6c006f00 20007700 6f007200 6c006400 l.o. .w.o.r.l.d. +# CHECK-NEXT: 140002040 0000 .. + +# NOSTM: Contents of section .rdata: +# NOSTM-NEXT: 140002000 68656c6c 6f20776f 726c6400 776f726c hello world.worl +# NOSTM-NEXT: 140002010 64006800 65006c00 6c006f00 20007700 d.h.e.l.l.o. .w. +# NOSTM-NEXT: 140002020 6f007200 6c006400 00007700 6f007200 o.r.l.d...w.o.r. +# NOSTM-NEXT: 140002030 6c006400 00006865 6c6c6f20 776f726c l.d...hello worl +# NOSTM-NEXT: 140002040 64006f82 6ca40000 68656c6c 6f20776f d.o.l...hello wo +# NOSTM-NEXT: 140002050 726c6400 rld. + +.section .rdata,"dr",discard,"??_C@_0M@LACCCNMM@hello?5world?$AA@" +.globl "??_C@_0M@LACCCNMM@hello?5world?$AA@" +"??_C@_0M@LACCCNMM@hello?5world?$AA@": +.asciz "hello world" + +.section .rdata,"dr",discard,"??_C@_05MCBCHHEJ@world?$AA@" +.globl "??_C@_05MCBCHHEJ@world?$AA@" +"??_C@_05MCBCHHEJ@world?$AA@": +.asciz "world" + +.section .rdata,"dr",discard,"??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@" +.globl "??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@" +.p2align 1 +"??_C@_1BI@HHJHKLLN@?$AAh?$AAe?$AAl?$AAl?$AAo?$AA?5?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@": +.short 104 +.short 101 +.short 108 +.short 108 +.short 111 +.short 32 +.short 119 +.short 111 +.short 114 +.short 108 +.short 100 +.short 0 + +.section .rdata,"dr",discard,"??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@" +.globl "??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@" +.p2align 1 +"??_C@_1M@NBBDDHIO@?$AAw?$AAo?$AAr?$AAl?$AAd?$AA?$AA@": +.short 119 +.short 111 +.short 114 +.short 108 +.short 100 +.short 0 + +.section .data,"drw",discard,"??_C@string_literal_in_wrong_section" +.globl "??_C@string_literal_in_wrong_section" +"??_C@string_literal_in_wrong_section": +.asciz "hello world" + +.section .rdata,"dr",discard,"??_D@not_a_string_literal" +.globl "??_D@not_a_string_literal" +"??_D@not_a_string_literal": +.asciz "hello world" + +.section .rdata,"dr",discard,"??_C@string_literal_with_relocs" +.globl "??_C@string_literal_with_relocs" +"??_C@string_literal_with_relocs": +.4byte main + 111 + (114 << 8) + (108 << 16) + (100 << 24) # main + "orld" +.byte 0 + +.section .rdata,"dr",discard,"??_C@overaligned_string_literal" +.globl "??_C@overaligned_string_literal" +.p2align 1 +"??_C@overaligned_string_literal": +.asciz "hello world" diff --git a/test/COFF/symtab-gc.s b/test/COFF/symtab-gc.s new file mode 100644 index 000000000000..5552639908be --- /dev/null +++ b/test/COFF/symtab-gc.s @@ -0,0 +1,27 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc -o %tobject.obj %S/Inputs/object.s +# RUN: lld-link -dll -entry:f -out:%t.dll -implib:%t.lib %tobject.obj +# RUN: llvm-mc -filetype=obj -triple=x86_64-windows-msvc -o %tmain.obj %s +# RUN: lld-link -entry:main -out:%t.exe -opt:ref -debug:dwarf %tmain.obj %t.lib +# RUN: llvm-readobj -coff-imports %t.exe | FileCheck %s + +# CHECK-NOT: Symbol: f + + .def main; + .scl 2; + .type 32; + .endef + .section .text,"xr",one_only,main + .globl main +main: + retq + + .def stripped; + .scl 3; + .type 32; + .endef + .section .text,"xr",one_only,stripped +stripped: + callq __imp_f + retq diff --git a/test/COFF/symtab.test b/test/COFF/symtab.test index 4e46e3383a4a..bedcd2f601a2 100644 --- a/test/COFF/symtab.test +++ b/test/COFF/symtab.test @@ -3,6 +3,8 @@ # RUN: llvm-readobj -symbols %t.exe | FileCheck %s # RUN: lld-link /debug:dwarf /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib # RUN: llvm-readobj -symbols %t.exe | FileCheck %s +# RUN: lld-link /debug:symtab /opt:noref /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib +# RUN: llvm-readobj -symbols %t.exe | FileCheck %s # RUN: lld-link /debug /out:%t.exe /entry:main %t.obj %p/Inputs/std64.lib # RUN: llvm-readobj -symbols %t.exe | FileCheck -check-prefix=NO %s @@ -11,7 +13,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: .text # CHECK-NEXT: Value: 0 -# CHECK-NEXT: Section: .text (2) +# CHECK-NEXT: Section: .text (1) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) @@ -20,7 +22,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: .text2 # CHECK-NEXT: Value: 0 -# CHECK-NEXT: Section: .text (2) +# CHECK-NEXT: Section: .text (1) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) @@ -29,7 +31,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: .data # CHECK-NEXT: Value: 0 -# CHECK-NEXT: Section: .data (1) +# CHECK-NEXT: Section: .data (3) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) @@ -38,7 +40,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: MessageBoxA # CHECK-NEXT: Value: 80 -# CHECK-NEXT: Section: .text (2) +# CHECK-NEXT: Section: .text (1) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: External (0x2) @@ -47,7 +49,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: ExitProcess # CHECK-NEXT: Value: 64 -# CHECK-NEXT: Section: .text (2) +# CHECK-NEXT: Section: .text (1) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: External (0x2) @@ -56,7 +58,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: message # CHECK-NEXT: Value: 6 -# CHECK-NEXT: Section: .text2 (3) +# CHECK-NEXT: Section: .text2 # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) @@ -65,7 +67,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: main # CHECK-NEXT: Value: 0 -# CHECK-NEXT: Section: .text (2) +# CHECK-NEXT: Section: .text (1) # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: External (0x2) @@ -74,7 +76,7 @@ # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: caption # CHECK-NEXT: Value: 0 -# CHECK-NEXT: Section: .text2 (3) +# CHECK-NEXT: Section: .text2 # CHECK-NEXT: BaseType: Null (0x0) # CHECK-NEXT: ComplexType: Null (0x0) # CHECK-NEXT: StorageClass: Static (0x3) diff --git a/test/COFF/thunk-replace.s b/test/COFF/thunk-replace.s new file mode 100644 index 000000000000..2d47fcc64837 --- /dev/null +++ b/test/COFF/thunk-replace.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -triple=x86_64-win32 %s -filetype=obj -o %t.main.obj +# RUN: llvm-mc -triple=x86_64-win32 %p/Inputs/otherFunc.s -filetype=obj -o %t.other.obj +# RUN: llvm-ar rcs %t.other.lib %t.other.obj +# RUN: not lld-link -out:%t.exe -entry:main %t.main.obj %p/Inputs/std64.lib %t.other.lib -opt:noref 2>&1 | FileCheck %s +# CHECK: MessageBoxA was replaced + +.global main +.text +main: + callq MessageBoxA + callq ExitProcess + callq otherFunc + ret diff --git a/test/COFF/timestamp.test b/test/COFF/timestamp.test new file mode 100644 index 000000000000..7e5f79fde53b --- /dev/null +++ b/test/COFF/timestamp.test @@ -0,0 +1,18 @@ +rm %t.*.exe +RUN: yaml2obj %p/Inputs/generic.yaml > %t.obj +RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.1.exe +RUN: lld-link %t.obj /debug /Brepro /entry:main /nodefaultlib /out:%t.2.exe +RUN: lld-link %t.obj /debug /timestamp:0 /entry:main /nodefaultlib /out:%t.3.exe +RUN: llvm-readobj -file-headers -coff-debug-directory %t.1.exe | FileCheck %s --check-prefix=HASH +RUN: llvm-readobj -file-headers -coff-debug-directory %t.2.exe | FileCheck %s --check-prefix=HASH +RUN: llvm-readobj -file-headers -coff-debug-directory %t.3.exe | FileCheck %s --check-prefix=ZERO + +HASH: ImageFileHeader { +HASH: TimeDateStamp: [[STAMP:.*]] +HASH: DebugDirectory [ +HASH: TimeDateStamp: [[STAMP]] + +ZERO: ImageFileHeader { +ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0) +ZERO: DebugDirectory [ +ZERO: TimeDateStamp: 1970-01-01 00:00:00 (0x0) diff --git a/test/COFF/undefined-symbol-cv.s b/test/COFF/undefined-symbol-cv.s new file mode 100644 index 000000000000..31a44c384c75 --- /dev/null +++ b/test/COFF/undefined-symbol-cv.s @@ -0,0 +1,62 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s +# RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: ?foo@@YAHXZ +# CHECK-NEXT: >>> referenced by file1.cpp:1 +# CHECK-NEXT: >>> {{.*}}.obj:(main) +# CHECK-NEXT: >>> referenced by file1.cpp:2 +# CHECK-NEXT: >>> {{.*}}.obj:(main) + +# CHECK: error: undefined symbol: ?bar@@YAHXZ +# CHECK-NEXT: >>> referenced by file2.cpp:3 +# CHECK-NEXT: >>> {{.*}}.obj:(main) +# CHECK-NEXT: >>> referenced by file1.cpp:4 +# CHECK-NEXT: >>> {{.*}}.obj:(f1) + +# CHECK: error: undefined symbol: ?baz@@YAHXZ +# CHECK-NEXT: >>> referenced by file1.cpp:5 +# CHECK-NEXT: >>> {{.*}}.obj:(f2) + + .cv_file 1 "file1.cpp" "EDA15C78BB573E49E685D8549286F33C" 1 + .cv_file 2 "file2.cpp" "EDA15C78BB573E49E685D8549286F33D" 1 + + .section .text,"xr",one_only,main +.globl main +main: + .cv_func_id 0 + .cv_loc 0 1 1 0 is_stmt 0 + call "?foo@@YAHXZ" + .cv_loc 0 1 2 0 + call "?foo@@YAHXZ" + .cv_loc 0 2 3 0 + call "?bar@@YAHXZ" +.Lfunc_end0: + +f1: + .cv_func_id 1 + .cv_loc 1 1 4 0 is_stmt 0 + call "?bar@@YAHXZ" +.Lfunc_end1: + + .section .text,"xr",one_only,f2 +.globl f2 +f2: + .cv_func_id 2 + .cv_loc 2 1 5 0 is_stmt 0 + call "?baz@@YAHXZ" +.Lfunc_end2: + + .section .debug$S,"dr",associative,main + .long 4 + .cv_linetable 0, main, .Lfunc_end0 + .cv_linetable 1, f1, .Lfunc_end1 + + .section .debug$S,"dr",associative,f2 + .long 4 + .cv_linetable 2, f2, .Lfunc_end2 + + .section .debug$S,"dr" + .long 4 + .cv_filechecksums + .cv_stringtable diff --git a/test/COFF/undefined-symbol.s b/test/COFF/undefined-symbol.s new file mode 100644 index 000000000000..5d002d82d23c --- /dev/null +++ b/test/COFF/undefined-symbol.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple=x86_64-windows-msvc -filetype=obj -o %t.obj %s +# RUN: not lld-link /out:%t.exe %t.obj 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: ?foo@@YAHXZ +# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) +# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) + +# CHECK: error: undefined symbol: ?bar@@YAHXZ +# CHECK-NEXT: >>> referenced by {{.*}}.obj:(main) +# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f1) + +# CHECK: error: undefined symbol: ?baz@@YAHXZ +# CHECK-NEXT: >>> referenced by {{.*}}.obj:(f2) + + .section .text,"xr",one_only,main +.globl main +main: + call "?foo@@YAHXZ" + call "?foo@@YAHXZ" + call "?bar@@YAHXZ" + +f1: + call "?bar@@YAHXZ" +.Lfunc_end1: + + .section .text,"xr",one_only,f2 +.globl f2 +f2: + call "?baz@@YAHXZ" diff --git a/test/COFF/unwind.test b/test/COFF/unwind.test index 2415b0542ca5..5b74aa7c1bba 100644 --- a/test/COFF/unwind.test +++ b/test/COFF/unwind.test @@ -4,12 +4,24 @@ # RUN: llvm-readobj -file-headers %t.exe | FileCheck -check-prefix=HEADER %s # RUN: llvm-objdump -unwind-info %t.exe | FileCheck -check-prefix=UNWIND %s # -# HEADER: ExceptionTableRVA: 0x1000 +# RUN: lld-link /merge:.pdata=.rdata /out:%t.exe /entry:main %t.obj +# RUN: llvm-readobj -file-headers -sections %t.exe | FileCheck -check-prefix=HEADER-MERGE %s +# +# HEADER: ExceptionTableRVA: 0x3000 +# +# FIXME: llvm-readobj currently does not understand files with .pdata merged +# into .rdata. But we can at least check that the section headers look correct. +# +# HEADER-MERGE: ExceptionTableRVA: 0x2004 +# HEADER-MERGE-NEXT: ExceptionTableSize: 0x30 +# HEADER-MERGE: Name: .rdata +# HEADER-MERGE-NEXT: VirtualSize: 0x78 +# HEADER-MERGE-NEXT: VirtualAddress: 0x2000 # # UNWIND: Function Table: -# UNWIND: Start Address: 0x2000 -# UNWIND: End Address: 0x201b -# UNWIND: Unwind Info Address: 0x3000 +# UNWIND: Start Address: 0x1000 +# UNWIND: End Address: 0x101b +# UNWIND: Unwind Info Address: 0x2004 # UNWIND: Version: 1 # UNWIND: Flags: 1 UNW_ExceptionHandler # UNWIND: Size of prolog: 18 @@ -24,27 +36,27 @@ # UNWIND: 0x04: UOP_AllocSmall 24 # UNWIND: 0x00: UOP_PushMachFrame w/o error code # UNWIND: Function Table: -# UNWIND: Start Address: 0x2012 -# UNWIND: End Address: 0x2012 -# UNWIND: Unwind Info Address: 0x301c +# UNWIND: Start Address: 0x1012 +# UNWIND: End Address: 0x1012 +# UNWIND: Unwind Info Address: 0x2020 # UNWIND: Version: 1 # UNWIND: Flags: 4 UNW_ChainInfo # UNWIND: Size of prolog: 0 # UNWIND: Number of Codes: 0 # UNWIND: No frame pointer used # UNWIND: Function Table: -# UNWIND: Start Address: 0x201b -# UNWIND: End Address: 0x201c -# UNWIND: Unwind Info Address: 0x302c +# UNWIND: Start Address: 0x101b +# UNWIND: End Address: 0x101c +# UNWIND: Unwind Info Address: 0x2030 # UNWIND: Version: 1 # UNWIND: Flags: 0 # UNWIND: Size of prolog: 0 # UNWIND: Number of Codes: 0 # UNWIND: No frame pointer used # UNWIND: Function Table: -# UNWIND: Start Address: 0x201c -# UNWIND: End Address: 0x2039 -# UNWIND: Unwind Info Address: 0x3034 +# UNWIND: Start Address: 0x101c +# UNWIND: End Address: 0x1039 +# UNWIND: Unwind Info Address: 0x2038 # UNWIND: Version: 1 # UNWIND: Flags: 0 # UNWIND: Size of prolog: 14 @@ -122,6 +134,10 @@ sections: - VirtualAddress: 44 SymbolName: .xdata Type: IMAGE_REL_AMD64_ADDR32NB + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 00000000 symbols: - Name: .text Value: 0 diff --git a/test/COFF/weak-external.test b/test/COFF/weak-external.test index 7bdadd9b1c94..352b14f08381 100644 --- a/test/COFF/weak-external.test +++ b/test/COFF/weak-external.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj %s > %t.obj # RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external.ll # RUN: lld-link /out:%t1.exe /entry:g /subsystem:console %t.obj @@ -5,6 +6,7 @@ # RUN: FileCheck %s < %t2.map # CHECK: lto.tmp +# CHECK-NEXT: lto.tmp # CHECK-NEXT: 0 g --- !COFF diff --git a/test/COFF/weak-external2.test b/test/COFF/weak-external2.test index 30101d73096b..dd9662045676 100644 --- a/test/COFF/weak-external2.test +++ b/test/COFF/weak-external2.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj %s > %t.obj # RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external2.ll # RUN: lld-link /out:%t.exe /entry:g /subsystem:console %t.obj %t.lto.obj diff --git a/test/COFF/weak-external3.test b/test/COFF/weak-external3.test index a06ce48a61a6..480b09b2eb0f 100644 --- a/test/COFF/weak-external3.test +++ b/test/COFF/weak-external3.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: yaml2obj %s > %t.obj # RUN: llvm-as -o %t.lto.obj %S/Inputs/weak-external3.ll # RUN: lld-link /out:%t1.exe /entry:f /subsystem:console /lldmap:%t1.map %t.lto.obj @@ -6,6 +7,7 @@ # RUN: FileCheck --check-prefix=CHECK2 %s < %t2.map # CHECK1: lto.tmp +# CHECK1: lto.tmp # CHECK1-NEXT: 0 g # CHECK2: weak-external3.test.tmp.obj diff --git a/test/COFF/wholearchive.s b/test/COFF/wholearchive.s index da9976382b0d..6a601eba6b0d 100644 --- a/test/COFF/wholearchive.s +++ b/test/COFF/wholearchive.s @@ -1,4 +1,4 @@ -# REQEUIRES: x86 +# REQUIRES: x86 # RUN: yaml2obj < %p/Inputs/export.yaml > %t.archive.obj # RUN: llvm-ar rcs %t.archive.lib %t.archive.obj @@ -10,6 +10,14 @@ # RUN: lld-link -dll -out:%t.dll -entry:main %t.main.obj -wholearchive %t.archive.lib -implib:%t.lib # RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB +# RUN: lld-link -dll -out:%t.dll -entry:main %t.main.obj %t.archive.lib -wholearchive:%t.archive.lib -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB + +# RUN: mkdir -p %t.dir +# RUN: cp %t.archive.lib %t.dir/foo.lib +# RUN: lld-link -dll -out:%t.dll -entry:main -libpath:%t.dir %t.main.obj %t.dir/./foo.lib -wholearchive:foo.lib -implib:%t.lib +# RUN: llvm-readobj %t.lib | FileCheck %s -check-prefix CHECK-IMPLIB + # CHECK-IMPLIB: Symbol: __imp_exportfn3 # CHECK-IMPLIB: Symbol: exportfn3 diff --git a/test/ELF/Inputs/amdgpu-kernel-2.o b/test/ELF/Inputs/amdgpu-kernel-2.o Binary files differdeleted file mode 100644 index fa76151f8976..000000000000 --- a/test/ELF/Inputs/amdgpu-kernel-2.o +++ /dev/null diff --git a/test/ELF/Inputs/arm-long-thunk-converge.lds b/test/ELF/Inputs/arm-long-thunk-converge.lds new file mode 100644 index 000000000000..592d400c8dc6 --- /dev/null +++ b/test/ELF/Inputs/arm-long-thunk-converge.lds @@ -0,0 +1,4 @@ +SECTIONS { + .foo : { *(.foo) } + .bar 0x2000000 : { *(.bar) } +} diff --git a/test/ELF/Inputs/as-needed-lazy.s b/test/ELF/Inputs/as-needed-lazy.s new file mode 100644 index 000000000000..7f9c360dda20 --- /dev/null +++ b/test/ELF/Inputs/as-needed-lazy.s @@ -0,0 +1,3 @@ +.global foo +foo: + nop diff --git a/test/ELF/Inputs/comdat-discarded-reloc.s b/test/ELF/Inputs/comdat-discarded-reloc.s new file mode 100644 index 000000000000..9526f5ac95c0 --- /dev/null +++ b/test/ELF/Inputs/comdat-discarded-reloc.s @@ -0,0 +1,6 @@ +.section .text.bar1,"aG",@progbits,group,comdat + +.section .text.bar2 +.global bar +bar: + .quad .text.bar1 diff --git a/test/ELF/Inputs/compress-debug.s b/test/ELF/Inputs/compress-debug.s new file mode 100644 index 000000000000..5fd9d39a98a0 --- /dev/null +++ b/test/ELF/Inputs/compress-debug.s @@ -0,0 +1,5 @@ +.text +.fill 0x44 + +.section .debug_info,"",@progbits +.fill 0x43 diff --git a/test/ELF/Inputs/conflict-debug.s b/test/ELF/Inputs/conflict-debug.s index 03fb01331815..c38771efc20a 100644 --- a/test/ELF/Inputs/conflict-debug.s +++ b/test/ELF/Inputs/conflict-debug.s @@ -3,3 +3,24 @@ .loc 1 4 zed: nop + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits + .long .Lend0 - .Lbegin0 # Length of Unit +.Lbegin0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit + .long .debug_line # DW_AT_stmt_list +.Lend0: + .section .debug_line,"",@progbits diff --git a/test/ELF/Inputs/copy-rel-version.s b/test/ELF/Inputs/copy-rel-version.s new file mode 100644 index 000000000000..36bb1ba54c9f --- /dev/null +++ b/test/ELF/Inputs/copy-rel-version.s @@ -0,0 +1,11 @@ +.data +.global foo@v1 +.type foo@v1, @object +.size foo@v1, 4 +.global foo@@v2 +.type foo@@v2, @object +.size foo@@v2, 8 +foo@v1: +foo@@v2: +.int 0 +.int 0 diff --git a/test/ELF/Inputs/copy-relocation-zero-abs-addr.s b/test/ELF/Inputs/copy-relocation-zero-abs-addr.s new file mode 100644 index 000000000000..da81e0372d8b --- /dev/null +++ b/test/ELF/Inputs/copy-relocation-zero-abs-addr.s @@ -0,0 +1,7 @@ +.globl ver1 +.globl ver2 + ver1 = 0x0 + ver2 = 0x0 + +.type foo,@object +.comm foo,16,16 diff --git a/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.s b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.s new file mode 100644 index 000000000000..26ac7bed195b --- /dev/null +++ b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.s @@ -0,0 +1,7 @@ +.balign 1024 +.type foo,@object +.globl foo +goo: +foo: + .long 0 + .size foo,4 diff --git a/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.script b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.script new file mode 100644 index 000000000000..a5807231acd6 --- /dev/null +++ b/test/ELF/Inputs/copy-relocation-zero-nonabs-addr.script @@ -0,0 +1,3 @@ +SECTIONS { + goo = 0; +}; diff --git a/test/ELF/Inputs/eh-frame-pcrel-overflow.s b/test/ELF/Inputs/eh-frame-pcrel-overflow.s new file mode 100644 index 000000000000..7b3cff88b466 --- /dev/null +++ b/test/ELF/Inputs/eh-frame-pcrel-overflow.s @@ -0,0 +1,25 @@ +.text +.global foo +foo: + ret + +.section .eh_frame, "a" + .long 12 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x52 # Augmentation string: 'R','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x00 # DW_EH_PE_absptr + + .byte 0xFF + + .long 12 # Size + .long 0x14 # ID + .quad foo + 0x90000000 diff --git a/test/ELF/Inputs/exclude-libs.ll b/test/ELF/Inputs/exclude-libs.ll new file mode 100644 index 000000000000..8bd947085f31 --- /dev/null +++ b/test/ELF/Inputs/exclude-libs.ll @@ -0,0 +1,3 @@ +@fn2 = global void()* null; + +target triple = "x86_64-unknown-linux" diff --git a/test/ELF/Inputs/exclude-libs.s b/test/ELF/Inputs/exclude-libs.s index 6d05c5e3aa91..eeacae6bccf2 100644 --- a/test/ELF/Inputs/exclude-libs.s +++ b/test/ELF/Inputs/exclude-libs.s @@ -1,3 +1,5 @@ .globl fn fn: nop + +.globl foo diff --git a/test/ELF/Inputs/far-long-arm-abs.s b/test/ELF/Inputs/far-long-arm-abs.s new file mode 100644 index 000000000000..10d9d0292eab --- /dev/null +++ b/test/ELF/Inputs/far-long-arm-abs.s @@ -0,0 +1,13 @@ +.global far +.type far,%function +far = 0x201001c + +.global too_far1 +.type too_far1,%function +too_far1 = 0x2020014 +.global too_far2 +.type too_far2,%function +too_far2 = 0x2020020 +.global too_far3 +.type too_far3,%function +too_far3 = 0x202002c diff --git a/test/ELF/Inputs/gdb-index.s b/test/ELF/Inputs/gdb-index.s index 907a66d350b0..794995c150f9 100644 --- a/test/ELF/Inputs/gdb-index.s +++ b/test/ELF/Inputs/gdb-index.s @@ -1,8 +1,8 @@ .text .Ltext0: -.globl main2 -.type main2, @function -main2: +.globl aaaaaaaaaaaaaaaa +.type aaaaaaaaaaaaaaaa, @function +aaaaaaaaaaaaaaaa: nop nop .Letext0: @@ -59,7 +59,7 @@ main2: .long 0x33 .long 0x18 .byte 0x30 -.string "main2" +.string "aaaaaaaaaaaaaaaa" .long 0 .section .debug_gnu_pubtypes,"",@progbits diff --git a/test/ELF/Inputs/hexagon.s b/test/ELF/Inputs/hexagon.s new file mode 100644 index 000000000000..921a0c409b57 --- /dev/null +++ b/test/ELF/Inputs/hexagon.s @@ -0,0 +1,6 @@ +.global _start +_start: + nop +.global foo +foo: + jumpr lr diff --git a/test/ELF/Inputs/hidden-shared-err.s b/test/ELF/Inputs/hidden-shared-err.s new file mode 100644 index 000000000000..ade79556db7b --- /dev/null +++ b/test/ELF/Inputs/hidden-shared-err.s @@ -0,0 +1,2 @@ +.global foo +foo: diff --git a/test/ELF/Inputs/hidden-shared-err2.s b/test/ELF/Inputs/hidden-shared-err2.s new file mode 100644 index 000000000000..aedd19d396fb --- /dev/null +++ b/test/ELF/Inputs/hidden-shared-err2.s @@ -0,0 +1 @@ +.quad foo diff --git a/test/ELF/Inputs/i386-pic-plt.s b/test/ELF/Inputs/i386-pic-plt.s new file mode 100644 index 000000000000..a7a812194fa3 --- /dev/null +++ b/test/ELF/Inputs/i386-pic-plt.s @@ -0,0 +1,4 @@ + .global foo + .type foo, @function +foo: + nop diff --git a/test/ELF/Inputs/icf-safe.s b/test/ELF/Inputs/icf-safe.s new file mode 100644 index 000000000000..02393f3bbda5 --- /dev/null +++ b/test/ELF/Inputs/icf-safe.s @@ -0,0 +1,9 @@ +.section .text.non_addrsig1,"ax",@progbits +.globl non_addrsig1 +non_addrsig1: +ret + +.section .text.non_addrsig2,"ax",@progbits +.globl non_addrsig2 +non_addrsig2: +ret diff --git a/test/ELF/Inputs/map-file2.s b/test/ELF/Inputs/map-file2.s index d46b06f7345a..b830bbc41d2e 100644 --- a/test/ELF/Inputs/map-file2.s +++ b/test/ELF/Inputs/map-file2.s @@ -1,5 +1,7 @@ foo: +.cfi_startproc nop +.cfi_endproc .global bar bar: nop diff --git a/test/ELF/Inputs/mips-64-got-load.s b/test/ELF/Inputs/mips-64-got-load.s new file mode 100644 index 000000000000..dffc6fb335c9 --- /dev/null +++ b/test/ELF/Inputs/mips-64-got-load.s @@ -0,0 +1,8 @@ + .text + .global foo1 +foo1: + ld $2, %got_disp(local1)($gp) + + .bss +local1: + .word 0 diff --git a/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s new file mode 100644 index 000000000000..42bd32a1e73a --- /dev/null +++ b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.s @@ -0,0 +1,14 @@ +# Source file for mips-gp-dips-corrupt-ver.so +# +# % cat gpdisp.ver +# LLD_1.0.0 { global: foo; }; +# +# % as mips-gp-dips-corrupt-ver.s -o mips-gp-dips-corrupt-ver.o +# % ld -shared -o mips-gp-dips-corrupt-ver.so \ +# --version-script gpdisp.ver mips-gp-dips-corrupt-ver.o + + .global foo + .text +foo: + lui $t0, %hi(_gp_disp) + addi $t0, $t0, %lo(_gp_disp) diff --git a/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so Binary files differnew file mode 100755 index 000000000000..289ffa538f0c --- /dev/null +++ b/test/ELF/Inputs/mips-gp-dips-corrupt-ver.so diff --git a/test/ELF/Inputs/mips-mgot-1.s b/test/ELF/Inputs/mips-mgot-1.s new file mode 100644 index 000000000000..def6e5821154 --- /dev/null +++ b/test/ELF/Inputs/mips-mgot-1.s @@ -0,0 +1,10 @@ + .text + .global foo1 +foo1: + addiu $2, $2, %gottprel(tls0) # tls got entry + addiu $2, $2, %gottprel(tls1) # tls got entry + + .section .tdata,"awT",%progbits + .global tls1 +tls1: + .word 0 diff --git a/test/ELF/Inputs/mips-mgot-2.s b/test/ELF/Inputs/mips-mgot-2.s new file mode 100644 index 000000000000..4f6a92d36ffd --- /dev/null +++ b/test/ELF/Inputs/mips-mgot-2.s @@ -0,0 +1,17 @@ + .text + .global foo2 +foo2: + lw $2, %got(.data)($gp) # page entry + addi $2, $2, %lo(.data) + lw $2, %call16(foo0)($gp) # global entry + lw $2, %call16(foo2)($gp) # global entry + addiu $2, $2, %tlsgd(tls0) # tls gd entry + addiu $2, $2, %gottprel(tls0) # tls got entry + + .data + .space 0x20000 + + .section .tdata,"awT",%progbits + .global tls2 +tls2: + .word 0 diff --git a/test/ELF/Inputs/mips-micro-gp0-non-zero.o b/test/ELF/Inputs/mips-micro-gp0-non-zero.o Binary files differnew file mode 100644 index 000000000000..abd67bcd262a --- /dev/null +++ b/test/ELF/Inputs/mips-micro-gp0-non-zero.o diff --git a/test/ELF/Inputs/mips-n32-rels.o b/test/ELF/Inputs/mips-n32-rels.o Binary files differdeleted file mode 100644 index 88cbce699e6d..000000000000 --- a/test/ELF/Inputs/mips-n32-rels.o +++ /dev/null diff --git a/test/ELF/Inputs/mips-n64-gp0-non-zero.o b/test/ELF/Inputs/mips-n64-gp0-non-zero.o Binary files differnew file mode 100644 index 000000000000..43b930b9d9fd --- /dev/null +++ b/test/ELF/Inputs/mips-n64-gp0-non-zero.o diff --git a/test/ELF/Inputs/multiple-cu.s b/test/ELF/Inputs/multiple-cu.s new file mode 100644 index 000000000000..ff29d36a7e0a --- /dev/null +++ b/test/ELF/Inputs/multiple-cu.s @@ -0,0 +1,24 @@ + .file 1 "test2.c" + .loc 1 2 0 + jmp bar + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits + .long .Lend0 - .Lbegin0 # Length of Unit +.Lbegin0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit + .long .debug_line # DW_AT_stmt_list +.Lend0: + .section .debug_line,"",@progbits diff --git a/test/ELF/Inputs/ppc64-func-global-entry.s b/test/ELF/Inputs/ppc64-func-global-entry.s new file mode 100644 index 000000000000..5987db6b5c53 --- /dev/null +++ b/test/ELF/Inputs/ppc64-func-global-entry.s @@ -0,0 +1,35 @@ + .text + .abiversion 2 + .globl foo_external_diff # -- Begin function foo_external_diff + .p2align 4 + .type foo_external_diff,@function +foo_external_diff: # @foo_external_diff +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry foo_external_diff, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: # %entry + addis 5, 2, .LC0@toc@ha + add 3, 4, 3 + ld 5, .LC0@toc@l(5) + lwz 5, 0(5) + add 3, 3, 5 + extsw 3, 3 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size foo_external_diff, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section .toc,"aw",@progbits +.LC0: + .tc glob2[TC],glob2 + .type glob2,@object # @glob2 + .data + .globl glob2 + .p2align 2 +glob2: + .long 10 # 0xa + .size glob2, 4 diff --git a/test/ELF/Inputs/ppc64-func-local-entry.s b/test/ELF/Inputs/ppc64-func-local-entry.s new file mode 100644 index 000000000000..fc0a72df762d --- /dev/null +++ b/test/ELF/Inputs/ppc64-func-local-entry.s @@ -0,0 +1,16 @@ + .text + .abiversion 2 + .globl foo_external_same # -- Begin function foo_external_same + .p2align 4 + .type foo_external_same,@function +foo_external_same: # @foo_external_same +.Lfunc_begin0: +# %bb.0: # %entry + add 3, 4, 3 + extsw 3, 3 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size foo_external_same, .Lfunc_end0-.Lfunc_begin0 + # -- End function diff --git a/test/ELF/Inputs/ppc64-func.s b/test/ELF/Inputs/ppc64-func.s new file mode 100644 index 000000000000..745faf870e6b --- /dev/null +++ b/test/ELF/Inputs/ppc64-func.s @@ -0,0 +1,14 @@ + .text + .abiversion 2 + .globl foo_not_shared + .p2align 4 + .type foo_not_shared,@function + +foo_not_shared: +.Lfunc_begin0: + li 3, 55 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size foo_not_shared, .Lfunc_end0-.Lfunc_begin0 diff --git a/test/ELF/Inputs/ppc64-tls.s b/test/ELF/Inputs/ppc64-tls.s new file mode 100644 index 000000000000..11d1d1240962 --- /dev/null +++ b/test/ELF/Inputs/ppc64-tls.s @@ -0,0 +1,20 @@ + .text + .abiversion 2 + .type a,@object # @a + .type b,@object # @a + .type c,@object # @a + .section .tdata,"awT",@progbits + .globl a +a: + .long 10 # 0xa + .size a, 4 + + .globl b +b: + .long 10 # 0xa + .size b, 4 + + .globl c +c: + .long 10 # 0xa + .size c, 4 diff --git a/test/ELF/Inputs/print-icf.s b/test/ELF/Inputs/print-icf.s new file mode 100644 index 000000000000..df9bcbc0989d --- /dev/null +++ b/test/ELF/Inputs/print-icf.s @@ -0,0 +1,9 @@ +.section .text.f6, "ax" +f6: + mov $60, %rax + mov $42, %rdi + syscall + + .section .text.f7, "ax" +f7: + mov $0, %rax diff --git a/test/ELF/Inputs/protected-data-access.s b/test/ELF/Inputs/protected-data-access.s new file mode 100644 index 000000000000..50a1c461fd84 --- /dev/null +++ b/test/ELF/Inputs/protected-data-access.s @@ -0,0 +1,7 @@ + .section .rodata,"a" + .global foo + .protected foo + .type foo, @object + .size foo, 8 +foo: + .quad 42 diff --git a/test/ELF/Inputs/protected-function-access.s b/test/ELF/Inputs/protected-function-access.s new file mode 100644 index 000000000000..4dfffe512956 --- /dev/null +++ b/test/ELF/Inputs/protected-function-access.s @@ -0,0 +1,5 @@ + .global foo + .protected foo + .type foo, @function +foo: + ret diff --git a/test/ELF/Inputs/shared-ppc64.s b/test/ELF/Inputs/shared-ppc64.s index b0117ac42963..0e1ecf7ce849 100644 --- a/test/ELF/Inputs/shared-ppc64.s +++ b/test/ELF/Inputs/shared-ppc64.s @@ -1,9 +1,14 @@ -.section ".opd","aw" -.global bar -bar: -.quad .Lbar,.TOC.@tocbase,0 -.quad .Lbar,0,0 + .text + .abiversion 2 + .globl foo + .p2align 4 + .type foo,@function -.text -.Lbar: - blr +foo: +.Lfunc_begin0: + li 3, 55 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size foo, .Lfunc_end0-.Lfunc_begin0 diff --git a/test/ELF/Inputs/shlib-undefined-ref.s b/test/ELF/Inputs/shlib-undefined-ref.s new file mode 100644 index 000000000000..cfb7c60ebc01 --- /dev/null +++ b/test/ELF/Inputs/shlib-undefined-ref.s @@ -0,0 +1,4 @@ +.globl f +f: + call should_not_be_exported@PLT + ret diff --git a/test/ELF/Inputs/symbol-ordering-file-warnings1.s b/test/ELF/Inputs/symbol-ordering-file-warnings1.s new file mode 100644 index 000000000000..9250a6d42705 --- /dev/null +++ b/test/ELF/Inputs/symbol-ordering-file-warnings1.s @@ -0,0 +1,19 @@ +# This is a "bad" (absolute) instance of the symbol +multi = 1234 + +.text +.global shared +.type shared, @function +shared: + movq %rax, multi + ret + +.section .text.comdat,"axG",@progbits,comdat,comdat +.weak comdat +comdat: + ret + +.section .text.glob_or_wk,"ax",@progbits +.global glob_or_wk +glob_or_wk: + ret diff --git a/test/ELF/Inputs/symbol-ordering-file-warnings2.s b/test/ELF/Inputs/symbol-ordering-file-warnings2.s new file mode 100644 index 000000000000..4d914b240f17 --- /dev/null +++ b/test/ELF/Inputs/symbol-ordering-file-warnings2.s @@ -0,0 +1,6 @@ +.text +.global missing +missing: + callq undefined + # This is a "bad" (undefined) instance of the symbol + callq multi diff --git a/test/ELF/Inputs/undef-bad-debug.s b/test/ELF/Inputs/undef-bad-debug.s new file mode 100644 index 000000000000..e3e9f5edb9db --- /dev/null +++ b/test/ELF/Inputs/undef-bad-debug.s @@ -0,0 +1,134 @@ +.section .text,"ax" +sym: + .quad zed6 +sym2: + .quad zed7 + +.section .debug_line,"",@progbits +.Lunit: + .long .Lunit_end - .Lunit_start # unit length +.Lunit_start: + .short 4 # version + .long .Lprologue_end - .Lprologue_start # prologue length +.Lprologue_start: + .byte 1 # minimum instruction length + .byte 1 # maximum operatiosn per instruction + .byte 1 # default is_stmt + .byte -5 # line base + .byte 14 # line range + .byte 13 # opcode base + .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths + .asciz "dir" # include directories + .byte 0 + .asciz "undef-bad-debug.s" # file names + .byte 1, 0, 0 + .byte 0 + .byte 0 # extraneous byte +.Lprologue_end: + .byte 0, 9, 2 # DW_LNE_set_address + .quad sym + .byte 3 # DW_LNS_advance_line + .byte 10 + .byte 1 # DW_LNS_copy + .byte 2 # DW_LNS_advance_pc + .byte 8 + .byte 0, 1, 1 # DW_LNE_end_sequence +.Lunit_end: + +.Lunit2: + .long .Lunit2_end - .Lunit2_start # unit length +.Lunit2_start: + .short 4 # version + .long .Lprologue2_end - .Lprologue2_start # prologue length +.Lprologue2_start: + .byte 1 # minimum instruction length + .byte 1 # maximum operatiosn per instruction + .byte 1 # default is_stmt + .byte -5 # line base + .byte 14 # line range + .byte 13 # opcode base + .byte 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1 # standard opcode lengths + .asciz "dir2" # include directories + .byte 0 + .asciz "undef-bad-debug2.s" # file names + .byte 1, 0, 0 + .byte 0 +.Lprologue2_end: + .byte 0, 9, 2 # DW_LNE_set_address + .quad sym2 + .byte 3 # DW_LNS_advance_line + .byte 10 + .byte 1 # DW_LNS_copy + .byte 2 # DW_LNS_advance_pc + .byte 8 + .byte 0, 1, 1 # DW_LNE_end_sequence + .byte 0, 9, 2 # DW_LNE_set_address + .quad 0x0badbeef + .byte 3 # DW_LNS_advance_line + .byte 99 + .byte 1 # DW_LNS_copy + .byte 99 # DW_LNS_advance_pc + .byte 119 + # Missing end of sequence. +.Lunit2_end: + +.section .debug_info,"",@progbits + .long .Lcu_end - .Lcu_start # Length of Unit +.Lcu_start: + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x79 DW_TAG_compile_unit + .long .Lunit # DW_AT_stmt_list + .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable + .long .Linfo_string # DW_AT_name + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 0 # End Of Children Mark +.Lcu_end: + + .long .Lcu2_end - .Lcu2_start # Length of Unit +.Lcu2_start: + .short 4 # DWARF version number + .long .Lsection_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x79 DW_TAG_compile_unit + .long .Lunit2 # DW_AT_stmt_list + .byte 2 # Abbrev [2] 0x2a:0x15 DW_TAG_variable + .long .Linfo2_string # DW_AT_name + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .byte 0 # End Of Children Mark +.Lcu2_end: + +.section .debug_abbrev,"",@progbits +.Lsection_abbrev: + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + +.section .debug_str,"MS",@progbits,1 +.Linfo_string: + .asciz "sym" +.Linfo2_string: + .asciz "sym2" diff --git a/test/ELF/Inputs/undef-debug.s b/test/ELF/Inputs/undef-debug.s index db8aaf16e6bd..46c1c92d2b1f 100644 --- a/test/ELF/Inputs/undef-debug.s +++ b/test/ELF/Inputs/undef-debug.s @@ -9,3 +9,24 @@ .section .text.2,"ax" .loc 1 11 .quad zed5 + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits + .long .Lend0 - .Lbegin0 # Length of Unit +.Lbegin0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit + .long .debug_line # DW_AT_stmt_list +.Lend0: + .section .debug_line,"",@progbits diff --git a/test/ELF/Inputs/undef-shared2.s b/test/ELF/Inputs/undef-shared2.s new file mode 100644 index 000000000000..8742073726e5 --- /dev/null +++ b/test/ELF/Inputs/undef-shared2.s @@ -0,0 +1,2 @@ +.data +.quad foo diff --git a/test/ELF/Inputs/versiondef.s b/test/ELF/Inputs/versiondef.s new file mode 100644 index 000000000000..911cc146706f --- /dev/null +++ b/test/ELF/Inputs/versiondef.s @@ -0,0 +1,9 @@ +.text +.globl func_impl +func_impl: + ret +.globl func_impl2 +func_impl2: + ret +.symver func_impl, func@@VER2 +.symver func_impl2, func@VER diff --git a/test/ELF/Inputs/weak-and-strong-undef.s b/test/ELF/Inputs/weak-and-strong-undef.s deleted file mode 100644 index a5e476d43160..000000000000 --- a/test/ELF/Inputs/weak-and-strong-undef.s +++ /dev/null @@ -1 +0,0 @@ - .weak foo diff --git a/test/ELF/Inputs/x86-64-split-stack-main.s b/test/ELF/Inputs/x86-64-split-stack-main.s new file mode 100644 index 000000000000..3be9facf51e9 --- /dev/null +++ b/test/ELF/Inputs/x86-64-split-stack-main.s @@ -0,0 +1,16 @@ + .text + + .global non_split + .type non_split,@function +non_split: + retq + .size non_split,. - non_split + + .global non_function_text_symbol +non_function_text_symbol: + .byte 0x01 + .type non_function_text_symbol,@STT_OBJECT + .size non_function_text_symbol, 1 + + + .section .note.GNU-stack,"",@progbits diff --git a/test/ELF/Inputs/ztext-text-notext.s b/test/ELF/Inputs/ztext.s index f66b3ee1e29b..f66b3ee1e29b 100644 --- a/test/ELF/Inputs/ztext-text-notext.s +++ b/test/ELF/Inputs/ztext.s diff --git a/test/ELF/aarch64-call26-thunk.s b/test/ELF/aarch64-call26-thunk.s index 0fe99cec974d..067f6dbc2f7e 100644 --- a/test/ELF/aarch64-call26-thunk.s +++ b/test/ELF/aarch64-call26-thunk.s @@ -1,8 +1,8 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t // RUN: ld.lld %t %tabs -o %t2 2>&1 // RUN: llvm-objdump -d -triple=aarch64-pc-freebsd %t2 | FileCheck %s -// REQUIRES: aarch64 .text .globl _start diff --git a/test/ELF/aarch64-condb-reloc.s b/test/ELF/aarch64-condb-reloc.s index 23c16c2db898..8a7581480544 100644 --- a/test/ELF/aarch64-condb-reloc.s +++ b/test/ELF/aarch64-condb-reloc.s @@ -1,3 +1,4 @@ +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-condb-reloc.s -o %t1 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t2 # RUN: ld.lld %t1 %t2 -o %t @@ -5,7 +6,6 @@ # RUN: ld.lld -shared %t1 %t2 -o %t3 # RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s # RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s -# REQUIRES: aarch64 # 0x11024 - 36 = 0x11000 # 0x11028 - 24 = 0x11010 diff --git a/test/ELF/aarch64-copy.s b/test/ELF/aarch64-copy.s index ffecf2f8a283..32e1c76df771 100644 --- a/test/ELF/aarch64-copy.s +++ b/test/ELF/aarch64-copy.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/relocation-copy.s -o %t2.o -// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld -shared %t2.o -soname fixed-length-string.so -o %t2.so // RUN: ld.lld %t.o %t2.so -o %t3 // RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s // RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=CODE %s @@ -90,4 +90,4 @@ _start: // RODATA: Contents of section .rodata: // S(z) = 0x40014 -// RODATA-NEXT: 101c8 14000400 +// RODATA-NEXT: 102e0 14000400 diff --git a/test/ELF/aarch64-cortex-a53-843419-address.s b/test/ELF/aarch64-cortex-a53-843419-address.s index e9f6ff4c38db..6c1f04d49fa1 100644 --- a/test/ELF/aarch64-cortex-a53-843419-address.s +++ b/test/ELF/aarch64-cortex-a53-843419-address.s @@ -4,7 +4,8 @@ // RUN: .text : { *(.text) *(.text.*) *(.newisd) } \ // RUN: .text2 : { *.(newos) } \ // RUN: .data : { *(.data) } }" > %t.script -// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 | FileCheck -check-prefix=CHECK-PRINT %s +// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-PRINT %s // RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 | FileCheck %s // Test cases for Cortex-A53 Erratum 843419 that involve interactions diff --git a/test/ELF/aarch64-cortex-a53-843419-cli.s b/test/ELF/aarch64-cortex-a53-843419-cli.s index 30abc8f06d20..9c1d4858b3a7 100644 --- a/test/ELF/aarch64-cortex-a53-843419-cli.s +++ b/test/ELF/aarch64-cortex-a53-843419-cli.s @@ -1,6 +1,6 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -// RUN: not ld.lld %t -fix-cortex-a53-843419 -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -fix-cortex-a53-843419 -o /dev/null 2>&1 | FileCheck %s // CHECK: --fix-cortex-a53-843419 is only supported on AArch64 targets. .globl entry diff --git a/test/ELF/aarch64-cortex-a53-843419-nopatch.s b/test/ELF/aarch64-cortex-a53-843419-nopatch.s index 389bf4505735..4f34ea26da7f 100644 --- a/test/ELF/aarch64-cortex-a53-843419-nopatch.s +++ b/test/ELF/aarch64-cortex-a53-843419-nopatch.s @@ -1,6 +1,6 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o -// RUN: ld.lld -fix-cortex-a53-843419 -verbose -t %t.o -o %t2 | FileCheck %s +// RUN: ld.lld -fix-cortex-a53-843419 -verbose -t %t.o -o /dev/null | FileCheck %s // Test cases for Cortex-A53 Erratum 843419 that we don't expect to recognize // as needing a patch as one or more of the conditions isn't satisfied. // See ARM-EPM-048406 Cortex_A53_MPCore_Software_Developers_Errata_Notice.pdf diff --git a/test/ELF/aarch64-cortex-a53-843419-recognize.s b/test/ELF/aarch64-cortex-a53-843419-recognize.s index 3674dd2744da..174f18164bce 100644 --- a/test/ELF/aarch64-cortex-a53-843419-recognize.s +++ b/test/ELF/aarch64-cortex-a53-843419-recognize.s @@ -1,8 +1,8 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t.o -// RUN: ld.lld -fix-cortex-a53-843419 -verbose %t.o -o %t2 | FileCheck -check-prefix CHECK-PRINT %s +// RUN: ld.lld -fix-cortex-a53-843419 -verbose %t.o -o %t2 2>&1 | FileCheck -check-prefix CHECK-PRINT %s // RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 | FileCheck %s -check-prefixes=CHECK,CHECK-FIX -// RUN: ld.lld -verbose %t.o -o %t3 +// RUN: ld.lld %t.o -o %t3 // RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t3 | FileCheck %s -check-prefixes=CHECK,CHECK-NOFIX // Test cases for Cortex-A53 Erratum 843419 // See ARM-EPM-048406 Cortex_A53_MPCore_Software_Developers_Errata_Notice.pdf @@ -30,7 +30,7 @@ // CHECK: t3_ff8_ldr: // CHECK-NEXT: 21ff8: e0 01 00 f0 adrp x0, #258048 // CHECK-NEXT: 21ffc: 21 00 40 f9 ldr x1, [x1] -// CHECK-FIX: 22000: 03 b8 00 14 b #188428 +// CHECK-FIX: 22000: 03 c8 00 14 b #204812 // CHECK-NOFIX: 22000: 00 00 40 f9 ldr x0, [x0] // CHECK-NEXT: 22004: c0 03 5f d6 ret .section .text.01, "ax", %progbits @@ -48,7 +48,7 @@ t3_ff8_ldr: // CHECK: t3_ff8_ldrsimd: // CHECK-NEXT: 23ff8: e0 01 00 b0 adrp x0, #249856 // CHECK-NEXT: 23ffc: 21 00 40 bd ldr s1, [x1] -// CHECK-FIX: 24000: 05 b0 00 14 b #180244 +// CHECK-FIX: 24000: 05 c0 00 14 b #196628 // CHECK-NOFIX: 24000: 02 04 40 f9 ldr x2, [x0, #8] // CHECK-NEXT: 24004: c0 03 5f d6 ret .section .text.02, "ax", %progbits @@ -66,7 +66,7 @@ t3_ff8_ldrsimd: // CHECK: t3_ffc_ldrpost: // CHECK-NEXT: 25ffc: c0 01 00 f0 adrp x0, #241664 // CHECK-NEXT: 26000: 21 84 40 bc ldr s1, [x1], #8 -// CHECK-FIX: 26004: 06 a8 00 14 b #172056 +// CHECK-FIX: 26004: 06 b8 00 14 b #188440 // CHECK-NOFIX: 26004: 03 08 40 f9 ldr x3, [x0, #16] // CHECK-NEXT: 26008: c0 03 5f d6 ret .section .text.03, "ax", %progbits @@ -84,7 +84,7 @@ t3_ffc_ldrpost: // CHECK: t3_ff8_strpre: // CHECK-NEXT: 27ff8: c0 01 00 b0 adrp x0, #233472 // CHECK-NEXT: 27ffc: 21 8c 00 bc str s1, [x1, #8]! -// CHECK-FIX: 28000: 09 a0 00 14 b #163876 +// CHECK-FIX: 28000: 09 b0 00 14 b #180260 // CHECK-NOFIX: 28000: 02 00 40 f9 ldr x2, [x0] // CHECK-NEXT: 28004: c0 03 5f d6 ret .section .text.04, "ax", %progbits @@ -102,7 +102,7 @@ t3_ff8_strpre: // CHECK: t3_ffc_str: // CHECK-NEXT: 29ffc: bc 01 00 f0 adrp x28, #225280 // CHECK-NEXT: 2a000: 42 00 00 f9 str x2, [x2] -// CHECK-FIX: 2a004: 0a 98 00 14 b #155688 +// CHECK-FIX: 2a004: 0a a8 00 14 b #172072 // CHECK-NOFIX: 2a004: 9c 07 00 f9 str x28, [x28, #8] // CHECK-NEXT: 2a008: c0 03 5f d6 ret .section .text.05, "ax", %progbits @@ -120,7 +120,7 @@ t3_ffc_str: // CHECK: t3_ffc_strsimd: // CHECK-NEXT: 2bffc: bc 01 00 b0 adrp x28, #217088 // CHECK-NEXT: 2c000: 44 00 00 b9 str w4, [x2] -// CHECK-FIX: 2c004: 0c 90 00 14 b #147504 +// CHECK-FIX: 2c004: 0c a0 00 14 b #163888 // CHECK-NOFIX: 2c004: 84 0b 00 f9 str x4, [x28, #16] // CHECK-NEXT: 2c008: c0 03 5f d6 ret .section .text.06, "ax", %progbits @@ -138,7 +138,7 @@ t3_ffc_strsimd: // CHECK: t3_ff8_ldrunpriv: // CHECK-NEXT: 2dff8: 9d 01 00 f0 adrp x29, #208896 // CHECK-NEXT: 2dffc: 41 08 40 38 ldtrb w1, [x2] -// CHECK-FIX: 2e000: 0f 88 00 14 b #139324 +// CHECK-FIX: 2e000: 0f 98 00 14 b #155708 // CHECK-NOFIX: 2e000: bd 03 40 f9 ldr x29, [x29] // CHECK-NEXT: 2e004: c0 03 5f d6 ret .section .text.07, "ax", %progbits @@ -156,7 +156,7 @@ t3_ff8_ldrunpriv: // CHECK: t3_ffc_ldur: // CHECK-NEXT: 2fffc: 9d 01 00 b0 adrp x29, #200704 // CHECK-NEXT: 30000: 42 40 40 b8 ldur w2, [x2, #4] -// CHECK-FIX: 30004: 10 80 00 14 b #131136 +// CHECK-FIX: 30004: 10 90 00 14 b #147520 // CHECK-NOFIX: 30004: bd 07 40 f9 ldr x29, [x29, #8] // CHECK-NEXT: 30008: c0 03 5f d6 ret .balign 4096 @@ -173,8 +173,8 @@ t3_ffc_ldur: // CHECK: t3_ffc_sturh: // CHECK-NEXT: 31ffc: 72 01 00 f0 adrp x18, #192512 // CHECK-NEXT: 32000: 43 40 00 78 sturh w3, [x2, #4] -// CHECK-FIX: 32004: 12 78 00 14 b #122952 -// CHECK-NOFIX: 32004: 41 0a 40 f9 ldr x1, [x18, #16] +// CHECK-FIX: 32004: 12 88 00 14 b #139336 +// CHECK-NOFIX: 32004: 41 0a 40 f9 ldr x1, [x18, #16] // CHECK-NEXT: 32008: c0 03 5f d6 ret .section .text.09, "ax", %progbits .balign 4096 @@ -191,7 +191,7 @@ t3_ffc_sturh: // CHECK: t3_ff8_literal: // CHECK-NEXT: 33ff8: 72 01 00 b0 adrp x18, #184320 // CHECK-NEXT: 33ffc: e3 ff ff 58 ldr x3, #-4 -// CHECK-FIX: 34000: 15 70 00 14 b #114772 +// CHECK-FIX: 34000: 15 80 00 14 b #131156 // CHECK-NOFIX: 34000: 52 02 40 f9 ldr x18, [x18] // CHECK-NEXT: 34004: c0 03 5f d6 ret .section .text.10, "ax", %progbits @@ -209,7 +209,7 @@ t3_ff8_literal: // CHECK: t3_ffc_register: // CHECK-NEXT: 35ffc: 4f 01 00 f0 adrp x15, #176128 // CHECK-NEXT: 36000: 43 68 61 f8 ldr x3, [x2, x1] -// CHECK-FIX: 36004: 16 68 00 14 b #106584 +// CHECK-FIX: 36004: 16 78 00 14 b #122968 // CHECK-NOFIX: 36004: ea 05 40 f9 ldr x10, [x15, #8] // CHECK-NEXT: 36008: c0 03 5f d6 ret .section .text.11, "ax", %progbits @@ -227,7 +227,7 @@ t3_ffc_register: // CHECK: t3_ff8_stp: // CHECK-NEXT: 37ff8: 50 01 00 b0 adrp x16, #167936 // CHECK-NEXT: 37ffc: 61 08 00 a9 stp x1, x2, [x3] -// CHECK-FIX: 38000: 19 60 00 14 b #98404 +// CHECK-FIX: 38000: 19 70 00 14 b #114788 // CHECK-NOFIX: 38000: 0d 0a 40 f9 ldr x13, [x16, #16] // CHECK-NEXT: 38004: c0 03 5f d6 ret .section .text.12, "ax", %progbits @@ -245,7 +245,7 @@ t3_ff8_stp: // CHECK: t3_ffc_stnp: // CHECK-NEXT: 39ffc: 27 01 00 f0 adrp x7, #159744 // CHECK-NEXT: 3a000: 61 08 00 a8 stnp x1, x2, [x3] -// CHECK-FIX: 3a004: 1a 58 00 14 b #90216 +// CHECK-FIX: 3a004: 1a 68 00 14 b #106600 // CHECK-NOFIX: 3a004: e9 00 40 f9 ldr x9, [x7] // CHECK-NEXT: 3a008: c0 03 5f d6 ret .section .text.13, "ax", %progbits @@ -262,8 +262,8 @@ t3_ffc_stnp: // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 3BFFC in unpatched output. // CHECK: t3_ffc_st1singlepost: // CHECK-NEXT: 3bffc: 37 01 00 b0 adrp x23, #151552 -// CHECK-NEXT: 3c000: 20 70 82 4c st1 { v0.16b }, [x1], x2 -// CHECK-FIX: 3c004: 1c 50 00 14 b #82032 +// CHECK-NEXT: 3c000: 20 04 82 0d st1 { v0.b }[1], [x1], x2 +// CHECK-FIX: 3c004: 1c 60 00 14 b #98416 // CHECK-NOFIX: 3c004: f6 06 40 f9 ldr x22, [x23, #8] // CHECK-NEXT: 3c008: c0 03 5f d6 ret .section .text.14, "ax", %progbits @@ -273,7 +273,7 @@ t3_ffc_stnp: .space 4096 - 4 t3_ffc_st1singlepost: adrp x23, dat2 - st1 { v0.16b }, [x1], x2 + st1 { v0.b }[1], [x1], x2 ldr x22, [x23, :lo12:dat2] ret @@ -281,7 +281,7 @@ t3_ffc_st1singlepost: // CHECK: t3_ff8_st1multiple: // CHECK-NEXT: 3dff8: 17 01 00 f0 adrp x23, #143360 // CHECK-NEXT: 3dffc: 20 a0 00 4c st1 { v0.16b, v1.16b }, [x1] -// CHECK-FIX: 3e000: 1f 48 00 14 b #73852 +// CHECK-FIX: 3e000: 1f 58 00 14 b #90236 // CHECK-NOFIX: 3e000: f8 0a 40 f9 ldr x24, [x23, #16] // CHECK-NEXT: 3e004: c0 03 5f d6 ret .section .text.15, "ax", %progbits @@ -300,7 +300,7 @@ t3_ff8_st1multiple: // CHECK-NEXT: 3fff8: 00 01 00 b0 adrp x0, #135168 // CHECK-NEXT: 3fffc: 21 00 40 f9 ldr x1, [x1] // CHECK-NEXT: 40000: 42 00 00 8b add x2, x2, x0 -// CHECK-FIX: 40004: 20 40 00 14 b #65664 +// CHECK-FIX: 40004: 20 50 00 14 b #82048 // CHECK-NOFIX: 40004: 02 00 40 f9 ldr x2, [x0] // CHECK-NEXT: 40008: c0 03 5f d6 ret .section .text.16, "ax", %progbits @@ -320,7 +320,7 @@ t4_ff8_ldr: // CHECK-NEXT: 41ffc: fc 00 00 f0 adrp x28, #126976 // CHECK-NEXT: 42000: 42 00 00 f9 str x2, [x2] // CHECK-NEXT: 42004: 20 00 02 cb sub x0, x1, x2 -// CHECK-FIX: 42008: 21 38 00 14 b #57476 +// CHECK-FIX: 42008: 21 48 00 14 b #73860 // CHECK-NOFIX: 42008: 9b 07 00 f9 str x27, [x28, #8] // CHECK-NEXT: 4200c: c0 03 5f d6 ret .section .text.17, "ax", %progbits @@ -340,7 +340,7 @@ t4_ffc_str: // CHECK-NEXT: 43ff8: f0 00 00 b0 adrp x16, #118784 // CHECK-NEXT: 43ffc: 61 08 00 a9 stp x1, x2, [x3] // CHECK-NEXT: 44000: 03 7e 10 9b mul x3, x16, x16 -// CHECK-FIX: 44004: 24 30 00 14 b #49296 +// CHECK-FIX: 44004: 24 40 00 14 b #65680 // CHECK-NOFIX: 44004: 0e 0a 40 f9 ldr x14, [x16, #16] // CHECK-NEXT: 44008: c0 03 5f d6 ret .section .text.18, "ax", %progbits @@ -360,7 +360,7 @@ t4_ff8_stp: // CHECK-NEXT: 45ff8: d0 00 00 f0 adrp x16, #110592 // CHECK-NEXT: 45ffc: 61 08 81 a9 stp x1, x2, [x3, #16]! // CHECK-NEXT: 46000: 03 7e 10 9b mul x3, x16, x16 -// CHECK-FIX: 46004: 26 28 00 14 b #41112 +// CHECK-FIX: 46004: 26 38 00 14 b #57496 // CHECK-NOFIX: 46004: 0e 06 40 f9 ldr x14, [x16, #8] // CHECK-NEXT: 46008: c0 03 5f d6 ret .section .text.19, "ax", %progbits @@ -380,7 +380,7 @@ t4_ff8_stppre: // CHECK-NEXT: 47ff8: d0 00 00 b0 adrp x16, #102400 // CHECK-NEXT: 47ffc: 61 08 81 a8 stp x1, x2, [x3], #16 // CHECK-NEXT: 48000: 03 7e 10 9b mul x3, x16, x16 -// CHECK-FIX: 48004: 28 20 00 14 b #32928 +// CHECK-FIX: 48004: 28 30 00 14 b #49312 // CHECK-NOFIX: 48004: 0e 06 40 f9 ldr x14, [x16, #8] // CHECK-NEXT: 48008: c0 03 5f d6 ret .section .text.20, "ax", %progbits @@ -400,7 +400,7 @@ t4_ff8_stppost: // CHECK-NEXT: 49ffc: b0 00 00 f0 adrp x16, #94208 // CHECK-NEXT: 4a000: 61 08 00 ad stp q1, q2, [x3] // CHECK-NEXT: 4a004: 03 7e 10 9b mul x3, x16, x16 -// CHECK-FIX: 4a008: 29 18 00 14 b #24740 +// CHECK-FIX: 4a008: 29 28 00 14 b #41124 // CHECK-NOFIX: 4a008: 0e 06 40 f9 ldr x14, [x16, #8] // CHECK-NEXT: 4a00c: c0 03 5f d6 ret .section .text.21, "ax", %progbits @@ -420,7 +420,7 @@ t4_ffc_stpsimd: // CHECK-NEXT: 4bffc: a7 00 00 b0 adrp x7, #86016 // CHECK-NEXT: 4c000: 61 08 00 a8 stnp x1, x2, [x3] // CHECK-NEXT: 4c004: 1f 20 03 d5 nop -// CHECK-FIX: 4c008: 2b 10 00 14 b #16556 +// CHECK-FIX: 4c008: 2b 20 00 14 b #32940 // CHECK-NOFIX: 4c008: ea 00 40 f9 ldr x10, [x7] // CHECK-NEXT: 4c00c: c0 03 5f d6 ret .section .text.22, "ax", %progbits @@ -438,9 +438,9 @@ t4_ffc_stnp: // CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 4DFFC in unpatched output. // CHECK: t4_ffc_st1: // CHECK-NEXT: 4dffc: 98 00 00 f0 adrp x24, #77824 -// CHECK-NEXT: 4e000: 20 70 00 4c st1 { v0.16b }, [x1] +// CHECK-NEXT: 4e000: 20 80 00 4d st1 { v0.s }[2], [x1] // CHECK-NEXT: 4e004: f6 06 40 f9 ldr x22, [x23, #8] -// CHECK-FIX: 4e008: 2d 08 00 14 b #8372 +// CHECK-FIX: 4e008: 2d 18 00 14 b #24756 // CHECK-NOFIX: 4e008: 18 ff 3f f9 str x24, [x24, #32760] // CHECK-NEXT: 4e00c: c0 03 5f d6 ret .section .text.23, "ax", %progbits @@ -450,7 +450,7 @@ t4_ffc_stnp: .space 4096 - 4 t4_ffc_st1: adrp x24, dat2 - st1 { v0.16b }, [x1] + st1 { v0.s }[2], [x1] ldr x22, [x23, :got_lo12:dat2] str x24, [x24, #32760] ret @@ -459,7 +459,7 @@ t4_ffc_st1: // CHECK: t3_ff8_ldr_once: // CHECK-NEXT: 4fff8: 80 00 00 b0 adrp x0, #69632 // CHECK-NEXT: 4fffc: 20 70 82 4c st1 { v0.16b }, [x1], x2 -// CHECK-FIX: 50000: 31 00 00 14 b #196 +// CHECK-FIX: 50000: 31 10 00 14 b #16580 // CHECK-NOFIX: 50000: 01 08 40 f9 ldr x1, [x0, #16] // CHECK-NEXT: 50004: 02 08 40 f9 ldr x2, [x0, #16] // CHECK-NEXT: 50008: c0 03 5f d6 ret @@ -475,6 +475,46 @@ t3_ff8_ldr_once: ldr x2, [x0, #16] ret +// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 51FF8 in unpatched output. +// CHECK: t3_ff8_ldxr: +// CHECK-NEXT: 51ff8: 60 00 00 f0 adrp x0, #61440 +// CHECK-NEXT: 51ffc: 03 7c 5f c8 ldxr x3, [x0] +// CHECK-FIX: 52000: 33 08 00 14 b #8396 +// CHECK-NOFIX: 52000: 01 08 40 f9 ldr x1, [x0, #16] +// CHECK: 52004: 02 08 40 f9 ldr x2, [x0, #16] +// CHECK-NEXT: 52008: c0 03 5f d6 ret + .section .text.25, "ax", %progbits + .balign 4096 + .globl t3_ff8_ldxr + .type t3_ff8_ldxr, %function + .space 4096 - 8 +t3_ff8_ldxr: + adrp x0, dat3 + ldxr x3, [x0] + ldr x1, [x0, #16] + ldr x2, [x0, #16] + ret + +// CHECK-PRINT: detected cortex-a53-843419 erratum sequence starting at 53FF8 in unpatched output. +// CHECK: t3_ff8_stxr: +// CHECK-NEXT: 53ff8: 60 00 00 b0 adrp x0, #53248 +// CHECK-NEXT: 53ffc: 03 7c 04 c8 stxr w4, x3, [x0] +// CHECK-FIX: 54000: 35 00 00 14 b #212 +// CHECK-NOFIX: 54000: 01 08 40 f9 ldr x1, [x0, #16] +// CHECK: 54004: 02 08 40 f9 ldr x2, [x0, #16] +// CHECK-NEXT: 54008: c0 03 5f d6 ret + .section .text.26, "ax", %progbits + .balign 4096 + .globl t3_ff8_stxr + .type t3_ff8_stxr, %function + .space 4096 - 8 +t3_ff8_stxr: + adrp x0, dat3 + stxr w4, x3, [x0] + ldr x1, [x0, #16] + ldr x2, [x0, #16] + ret + .text .globl _start .type _start, %function @@ -482,78 +522,83 @@ _start: ret // CHECK-FIX: __CortexA53843419_22000: -// CHECK-FIX-NEXT: 5000c: 00 00 40 f9 ldr x0, [x0] -// CHECK-FIX-NEXT: 50010: fd 47 ff 17 b #-188428 +// CHECK-FIX-NEXT: 5400c: 00 00 40 f9 ldr x0, [x0] +// CHECK-FIX-NEXT: 54010: fd 37 ff 17 b #-204812 // CHECK-FIX: __CortexA53843419_24000: -// CHECK-FIX-NEXT: 50014: 02 04 40 f9 ldr x2, [x0, #8] -// CHECK-FIX-NEXT: 50018: fb 4f ff 17 b #-180244 +// CHECK-FIX-NEXT: 54014: 02 04 40 f9 ldr x2, [x0, #8] +// CHECK-FIX-NEXT: 54018: fb 3f ff 17 b #-196628 // CHECK-FIX: __CortexA53843419_26004: -// CHECK-FIX-NEXT: 5001c: 03 08 40 f9 ldr x3, [x0, #16] -// CHECK-FIX-NEXT: 50020: fa 57 ff 17 b #-172056 +// CHECK-FIX-NEXT: 5401c: 03 08 40 f9 ldr x3, [x0, #16] +// CHECK-FIX-NEXT: 54020: fa 47 ff 17 b #-188440 // CHECK-FIX: __CortexA53843419_28000: -// CHECK-FIX-NEXT: 50024: 02 00 40 f9 ldr x2, [x0] -// CHECK-FIX-NEXT: 50028: f7 5f ff 17 b #-163876 +// CHECK-FIX-NEXT: 54024: 02 00 40 f9 ldr x2, [x0] +// CHECK-FIX-NEXT: 54028: f7 4f ff 17 b #-180260 // CHECK-FIX: __CortexA53843419_2A004: -// CHECK-FIX-NEXT: 5002c: 9c 07 00 f9 str x28, [x28, #8] -// CHECK-FIX-NEXT: 50030: f6 67 ff 17 b #-155688 +// CHECK-FIX-NEXT: 5402c: 9c 07 00 f9 str x28, [x28, #8] +// CHECK-FIX-NEXT: 54030: f6 57 ff 17 b #-172072 // CHECK-FIX: __CortexA53843419_2C004: -// CHECK-FIX-NEXT: 50034: 84 0b 00 f9 str x4, [x28, #16] -// CHECK-FIX-NEXT: 50038: f4 6f ff 17 b #-147504 +// CHECK-FIX-NEXT: 54034: 84 0b 00 f9 str x4, [x28, #16] +// CHECK-FIX-NEXT: 54038: f4 5f ff 17 b #-163888 // CHECK-FIX: __CortexA53843419_2E000: -// CHECK-FIX-NEXT: 5003c: bd 03 40 f9 ldr x29, [x29] -// CHECK-FIX-NEXT: 50040: f1 77 ff 17 b #-139324 +// CHECK-FIX-NEXT: 5403c: bd 03 40 f9 ldr x29, [x29] +// CHECK-FIX-NEXT: 54040: f1 67 ff 17 b #-155708 // CHECK-FIX: __CortexA53843419_30004: -// CHECK-FIX-NEXT: 50044: bd 07 40 f9 ldr x29, [x29, #8] -// CHECK-FIX-NEXT: 50048: f0 7f ff 17 b #-131136 +// CHECK-FIX-NEXT: 54044: bd 07 40 f9 ldr x29, [x29, #8] +// CHECK-FIX-NEXT: 54048: f0 6f ff 17 b #-147520 // CHECK-FIX: __CortexA53843419_32004: -// CHECK-FIX-NEXT: 5004c: 41 0a 40 f9 ldr x1, [x18, #16] -// CHECK-FIX-NEXT: 50050: ee 87 ff 17 b #-122952 +// CHECK-FIX-NEXT: 5404c: 41 0a 40 f9 ldr x1, [x18, #16] +// CHECK-FIX-NEXT: 54050: ee 77 ff 17 b #-139336 // CHECK-FIX: __CortexA53843419_34000: -// CHECK-FIX-NEXT: 50054: 52 02 40 f9 ldr x18, [x18] -// CHECK-FIX-NEXT: 50058: eb 8f ff 17 b #-114772 +// CHECK-FIX-NEXT: 54054: 52 02 40 f9 ldr x18, [x18] +// CHECK-FIX-NEXT: 54058: eb 7f ff 17 b #-131156 // CHECK-FIX: __CortexA53843419_36004: -// CHECK-FIX-NEXT: 5005c: ea 05 40 f9 ldr x10, [x15, #8] -// CHECK-FIX-NEXT: 50060: ea 97 ff 17 b #-106584 +// CHECK-FIX-NEXT: 5405c: ea 05 40 f9 ldr x10, [x15, #8] +// CHECK-FIX-NEXT: 54060: ea 87 ff 17 b #-122968 // CHECK-FIX: __CortexA53843419_38000: -// CHECK-FIX-NEXT: 50064: 0d 0a 40 f9 ldr x13, [x16, #16] -// CHECK-FIX-NEXT: 50068: e7 9f ff 17 b #-98404 +// CHECK-FIX-NEXT: 54064: 0d 0a 40 f9 ldr x13, [x16, #16] +// CHECK-FIX-NEXT: 54068: e7 8f ff 17 b #-114788 // CHECK-FIX: __CortexA53843419_3A004: -// CHECK-FIX-NEXT: 5006c: e9 00 40 f9 ldr x9, [x7] -// CHECK-FIX-NEXT: 50070: e6 a7 ff 17 b #-90216 +// CHECK-FIX-NEXT: 5406c: e9 00 40 f9 ldr x9, [x7] +// CHECK-FIX-NEXT: 54070: e6 97 ff 17 b #-106600 // CHECK-FIX: __CortexA53843419_3C004: -// CHECK-FIX-NEXT: 50074: f6 06 40 f9 ldr x22, [x23, #8] -// CHECK-FIX-NEXT: 50078: e4 af ff 17 b #-82032 +// CHECK-FIX-NEXT: 54074: f6 06 40 f9 ldr x22, [x23, #8] +// CHECK-FIX-NEXT: 54078: e4 9f ff 17 b #-98416 // CHECK-FIX: __CortexA53843419_3E000: -// CHECK-FIX-NEXT: 5007c: f8 0a 40 f9 ldr x24, [x23, #16] -// CHECK-FIX-NEXT: 50080: e1 b7 ff 17 b #-73852 +// CHECK-FIX-NEXT: 5407c: f8 0a 40 f9 ldr x24, [x23, #16] +// CHECK-FIX-NEXT: 54080: e1 a7 ff 17 b #-90236 // CHECK-FIX: __CortexA53843419_40004: -// CHECK-FIX-NEXT: 50084: 02 00 40 f9 ldr x2, [x0] -// CHECK-FIX-NEXT: 50088: e0 bf ff 17 b #-65664 +// CHECK-FIX-NEXT: 54084: 02 00 40 f9 ldr x2, [x0] +// CHECK-FIX-NEXT: 54088: e0 af ff 17 b #-82048 // CHECK-FIX: __CortexA53843419_42008: -// CHECK-FIX-NEXT: 5008c: 9b 07 00 f9 str x27, [x28, #8] -// CHECK-FIX-NEXT: 50090: df c7 ff 17 b #-57476 +// CHECK-FIX-NEXT: 5408c: 9b 07 00 f9 str x27, [x28, #8] +// CHECK-FIX-NEXT: 54090: df b7 ff 17 b #-73860 // CHECK-FIX: __CortexA53843419_44004: -// CHECK-FIX-NEXT: 50094: 0e 0a 40 f9 ldr x14, [x16, #16] -// CHECK-FIX-NEXT: 50098: dc cf ff 17 b #-49296 +// CHECK-FIX-NEXT: 54094: 0e 0a 40 f9 ldr x14, [x16, #16] +// CHECK-FIX-NEXT: 54098: dc bf ff 17 b #-65680 // CHECK-FIX: __CortexA53843419_46004: -// CHECK-FIX-NEXT: 5009c: 0e 06 40 f9 ldr x14, [x16, #8] -// CHECK-FIX-NEXT: 500a0: da d7 ff 17 b #-41112 +// CHECK-FIX-NEXT: 5409c: 0e 06 40 f9 ldr x14, [x16, #8] +// CHECK-FIX-NEXT: 540a0: da c7 ff 17 b #-57496 // CHECK-FIX: __CortexA53843419_48004: -// CHECK-FIX-NEXT: 500a4: 0e 06 40 f9 ldr x14, [x16, #8] -// CHECK-FIX-NEXT: 500a8: d8 df ff 17 b #-32928 +// CHECK-FIX-NEXT: 540a4: 0e 06 40 f9 ldr x14, [x16, #8] +// CHECK-FIX-NEXT: 540a8: d8 cf ff 17 b #-49312 // CHECK-FIX: __CortexA53843419_4A008: -// CHECK-FIX-NEXT: 500ac: 0e 06 40 f9 ldr x14, [x16, #8] -// CHECK-FIX-NEXT: 500b0: d7 e7 ff 17 b #-24740 +// CHECK-FIX-NEXT: 540ac: 0e 06 40 f9 ldr x14, [x16, #8] +// CHECK-FIX-NEXT: 540b0: d7 d7 ff 17 b #-41124 // CHECK-FIX: __CortexA53843419_4C008: -// CHECK-FIX-NEXT: 500b4: ea 00 40 f9 ldr x10, [x7] -// CHECK-FIX-NEXT: 500b8: d5 ef ff 17 b #-16556 +// CHECK-FIX-NEXT: 540b4: ea 00 40 f9 ldr x10, [x7] +// CHECK-FIX-NEXT: 540b8: d5 df ff 17 b #-32940 // CHECK-FIX: __CortexA53843419_4E008: -// CHECK-FIX-NEXT: 500bc: 18 ff 3f f9 str x24, [x24, #32760] -// CHECK-FIX-NEXT: 500c0: d3 f7 ff 17 b #-8372 +// CHECK-FIX-NEXT: 540bc: 18 ff 3f f9 str x24, [x24, #32760] +// CHECK-FIX-NEXT: 540c0: d3 e7 ff 17 b #-24756 // CHECK-FIX: __CortexA53843419_50000: -// CHECK-FIX-NEXT: 500c4: 01 08 40 f9 ldr x1, [x0, #16] -// CHECK-FIX-NEXT: 500c8: cf ff ff 17 b #-196 - +// CHECK-FIX-NEXT: 540c4: 01 08 40 f9 ldr x1, [x0, #16] +// CHECK-FIX-NEXT: 540c8: cf ef ff 17 b #-16580 +// CHECK-FIX: __CortexA53843419_52000: +// CHECK-FIX-NEXT: 540cc: 01 08 40 f9 ldr x1, [x0, #16] +// CHECK-FIX-NEXT: 540d0: cd f7 ff 17 b #-8396 +// CHECK-FIX: __CortexA53843419_54000: +// CHECK-FIX-NEXT: 540d4: 01 08 40 f9 ldr x1, [x0, #16] +// CHECK-FIX-NEXT: 540d8: cb ff ff 17 b #-212 .data .globl dat .globl dat2 diff --git a/test/ELF/aarch64-cortex-a53-843419-thunk.s b/test/ELF/aarch64-cortex-a53-843419-thunk.s index 4568095a2fa7..c802f3f605f1 100644 --- a/test/ELF/aarch64-cortex-a53-843419-thunk.s +++ b/test/ELF/aarch64-cortex-a53-843419-thunk.s @@ -3,7 +3,8 @@ // RUN: echo "SECTIONS { \ // RUN: .text1 0x10000 : { *(.text.01) *(.text.02) *(.text.03) } \ // RUN: .text2 0x8010000 : { *(.text.04) } } " > %t.script -// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 | FileCheck -check-prefix=CHECK-PRINT %s +// RUN: ld.lld --script %t.script -fix-cortex-a53-843419 -verbose %t.o -o %t2 2>&1 \ +// RUN: | FileCheck -check-prefix=CHECK-PRINT %s // RUN: llvm-objdump -triple=aarch64-linux-gnu -d %t2 | FileCheck %s // %t2 is 128 Megabytes, so delete it early. diff --git a/test/ELF/aarch64-data-relocs.s b/test/ELF/aarch64-data-relocs.s index 19e11bc3925c..d32871543bf6 100644 --- a/test/ELF/aarch64-data-relocs.s +++ b/test/ELF/aarch64-data-relocs.s @@ -1,8 +1,8 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %S/Inputs/abs256.s -o %t256.o // RUN: ld.lld %t %t256.o -o %t2 // RUN: llvm-objdump -s %t2 | FileCheck %s -// REQUIRES: aarch64 .globl _start _start: diff --git a/test/ELF/aarch64-fpic-abs16.s b/test/ELF/aarch64-fpic-abs16.s index 2b14b11c75db..c180939b7cac 100644 --- a/test/ELF/aarch64-fpic-abs16.s +++ b/test/ELF/aarch64-fpic-abs16.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: relocation R_AARCH64_ABS16 cannot be used against shared object; recompile with -fPIC +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: relocation R_AARCH64_ABS16 cannot be used against symbol foo; recompile with -fPIC // CHECK-NEXT: >>> defined in {{.*}}.o // CHECK-NEXT: >>> referenced by {{.*}}.o:(.data+0x0) diff --git a/test/ELF/aarch64-fpic-add_abs_lo12_nc.s b/test/ELF/aarch64-fpic-add_abs_lo12_nc.s index 9e13fd18af46..fc58e06b3db3 100644 --- a/test/ELF/aarch64-fpic-add_abs_lo12_nc.s +++ b/test/ELF/aarch64-fpic-add_abs_lo12_nc.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_AARCH64_ADD_ABS_LO12_NC against symbol: dat +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: can't create dynamic relocation R_AARCH64_ADD_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/aarch64-fpic-adr_prel_lo21.s b/test/ELF/aarch64-fpic-adr_prel_lo21.s index c1e6bc6359bd..4b6f43f1f226 100644 --- a/test/ELF/aarch64-fpic-adr_prel_lo21.s +++ b/test/ELF/aarch64-fpic-adr_prel_lo21.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_AARCH64_ADR_PREL_LO21 against symbol: dat +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: relocation R_AARCH64_ADR_PREL_LO21 cannot be used against symbol dat; recompile with -fPIC // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s b/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s index e27867b85242..651a32e56868 100644 --- a/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s +++ b/test/ELF/aarch64-fpic-adr_prel_pg_hi21.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_AARCH64_ADR_PREL_PG_HI21 against symbol: dat +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: relocation R_AARCH64_ADR_PREL_PG_HI21 cannot be used against symbol dat; recompile with -fPIC // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s index 02b75a5bfcde..b68b9f23e4ca 100644 --- a/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s +++ b/test/ELF/aarch64-fpic-ldst32_abs_lo12_nc.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_AARCH64_LDST32_ABS_LO12_NC against symbol: dat +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: can't create dynamic relocation R_AARCH64_LDST32_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s index 45e4f2032c19..1d5b9439f0f4 100644 --- a/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s +++ b/test/ELF/aarch64-fpic-ldst64_abs_lo12_nc.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_AARCH64_LDST64_ABS_LO12_NC against symbol: dat +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: can't create dynamic relocation R_AARCH64_LDST64_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s b/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s index 16e7df1bc4a1..a3f8243a080c 100644 --- a/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s +++ b/test/ELF/aarch64-fpic-ldst8_abs_lo12_nc.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_AARCH64_LDST8_ABS_LO12_NC against symbol: dat +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: can't create dynamic relocation R_AARCH64_LDST8_ABS_LO12_NC against symbol: dat in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/aarch64-fpic-prel16.s b/test/ELF/aarch64-fpic-prel16.s index 1faef9f866e0..1de7f6f63370 100644 --- a/test/ELF/aarch64-fpic-prel16.s +++ b/test/ELF/aarch64-fpic-prel16.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: R_AARCH64_PREL16 cannot be used against shared object; recompile with -fPIC +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: R_AARCH64_PREL16 cannot be used against symbol foo; recompile with -fPIC // CHECK: >>> defined in {{.*}} // CHECK: >>> referenced by {{.*}}:(.data+0x0) diff --git a/test/ELF/aarch64-fpic-prel32.s b/test/ELF/aarch64-fpic-prel32.s index b797dca2f2c4..0988b26a2b91 100644 --- a/test/ELF/aarch64-fpic-prel32.s +++ b/test/ELF/aarch64-fpic-prel32.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: relocation R_AARCH64_PREL32 cannot be used against shared object; recompile with -fPIC +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: relocation R_AARCH64_PREL32 cannot be used against symbol foo; recompile with -fPIC // CHECK: >>> defined in {{.*}} // CHECK: >>> referenced by {{.*}}:(.data+0x0) diff --git a/test/ELF/aarch64-fpic-prel64.s b/test/ELF/aarch64-fpic-prel64.s index 4c67837eac78..653f54220334 100644 --- a/test/ELF/aarch64-fpic-prel64.s +++ b/test/ELF/aarch64-fpic-prel64.s @@ -1,7 +1,7 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-freebsd %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s -// CHECK: relocation R_AARCH64_PREL64 cannot be used against shared object; recompile with -fPIC +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s +// CHECK: relocation R_AARCH64_PREL64 cannot be used against symbol foo; recompile with -fPIC // CHECK: >>> defined in {{.*}} // CHECK: >>> referenced by {{.*}}:(.data+0x0) diff --git a/test/ELF/aarch64-gnu-ifunc-nosym.s b/test/ELF/aarch64-gnu-ifunc-nosym.s index bb3a0b8b5116..aa0124aa3fa2 100644 --- a/test/ELF/aarch64-gnu-ifunc-nosym.s +++ b/test/ELF/aarch64-gnu-ifunc-nosym.s @@ -1,7 +1,7 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-readobj -symbols %tout | FileCheck %s -// REQUIRES: aarch64 // Check that no __rela_iplt_end/__rela_iplt_start // appear in symtab if there is no references to them. diff --git a/test/ELF/aarch64-gnu-ifunc-plt.s b/test/ELF/aarch64-gnu-ifunc-plt.s index 5138675676d3..ca30316c7afe 100644 --- a/test/ELF/aarch64-gnu-ifunc-plt.s +++ b/test/ELF/aarch64-gnu-ifunc-plt.s @@ -1,3 +1,4 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %S/Inputs/shared2.s -o %t1.o // RUN: ld.lld %t1.o --shared -o %t.so // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o @@ -5,7 +6,6 @@ // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s -// REQUIRES: aarch64 // Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt // CHECK: Relocations [ diff --git a/test/ELF/aarch64-gnu-ifunc.s b/test/ELF/aarch64-gnu-ifunc.s index 4e0dc328025d..b3c1571b7604 100644 --- a/test/ELF/aarch64-gnu-ifunc.s +++ b/test/ELF/aarch64-gnu-ifunc.s @@ -1,8 +1,8 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux-gnu %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s -// REQUIRES: aarch64 // CHECK: Sections [ // CHECK: Section { diff --git a/test/ELF/aarch64-hi21-error.s b/test/ELF/aarch64-hi21-error.s index 9e2b283ea118..07f9e04953b0 100644 --- a/test/ELF/aarch64-hi21-error.s +++ b/test/ELF/aarch64-hi21-error.s @@ -1,7 +1,7 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t -// RUN: not ld.lld %tabs %t -o %t2 2>&1 | FileCheck %s -// REQUIRES: aarch64 +// RUN: not ld.lld %tabs %t -o /dev/null 2>&1 | FileCheck %s .globl _start _start: diff --git a/test/ELF/aarch64-jump26-thunk.s b/test/ELF/aarch64-jump26-thunk.s index 088ab3a9e1a5..13c084a0c78e 100644 --- a/test/ELF/aarch64-jump26-thunk.s +++ b/test/ELF/aarch64-jump26-thunk.s @@ -1,8 +1,8 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t // RUN: ld.lld %t %tabs -o %t2 2>&1 // RUN: llvm-objdump -d -triple=aarch64-pc-freebsd %t2 | FileCheck %s -// REQUIRES: aarch64 .text .globl _start diff --git a/test/ELF/aarch64-ldprel-lo19-invalid.s b/test/ELF/aarch64-ldprel-lo19-invalid.s index 04df32e05904..cf38b2c84fd0 100644 --- a/test/ELF/aarch64-ldprel-lo19-invalid.s +++ b/test/ELF/aarch64-ldprel-lo19-invalid.s @@ -1,7 +1,7 @@ # REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o -# RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s # CHECK: relocation R_AARCH64_LD_PREL_LO19 out of range: 2065536 is not in [-1048576, 1048575] diff --git a/test/ELF/aarch64-lo12-alignment.s b/test/ELF/aarch64-lo12-alignment.s index 2b30022658e6..7edecd4494f5 100644 --- a/test/ELF/aarch64-lo12-alignment.s +++ b/test/ELF/aarch64-lo12-alignment.s @@ -1,6 +1,6 @@ // REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s // Test derived from a typical ODR violation where a global is declared // extern int but defined as a half or byte sized type. diff --git a/test/ELF/aarch64-lo21-error.s b/test/ELF/aarch64-lo21-error.s index 055f8948f6a3..c1fb8a6fa2c2 100644 --- a/test/ELF/aarch64-lo21-error.s +++ b/test/ELF/aarch64-lo21-error.s @@ -1,7 +1,7 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %S/Inputs/abs.s -o %tabs // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t -// RUN: not ld.lld %tabs %t -o %t2 2>&1 | FileCheck %s -// REQUIRES: aarch64 +// RUN: not ld.lld %tabs %t -o /dev/null 2>&1 | FileCheck %s .globl _start _start: diff --git a/test/ELF/aarch64-load-alignment.s b/test/ELF/aarch64-load-alignment.s index 7b1129b7afa5..175f1e6dad74 100644 --- a/test/ELF/aarch64-load-alignment.s +++ b/test/ELF/aarch64-load-alignment.s @@ -1,7 +1,7 @@ # REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o -# RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s # CHECK: improper alignment for relocation R_AARCH64_LD_PREL_LO19: 0x10005 is not aligned to 4 bytes diff --git a/test/ELF/aarch64-relocs.s b/test/ELF/aarch64-relocs.s index 9d02bd599b25..79caabcb6bb5 100644 --- a/test/ELF/aarch64-relocs.s +++ b/test/ELF/aarch64-relocs.s @@ -1,8 +1,8 @@ +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/uabs_label.s -o %t2.o # RUN: ld.lld %t %t2.o -o %t2 # RUN: llvm-objdump -d %t2 | FileCheck %s -# REQUIRES: aarch64 .section .R_AARCH64_ADR_PREL_LO21,"ax",@progbits .globl _start diff --git a/test/ELF/aarch64-thunk-pi.s b/test/ELF/aarch64-thunk-pi.s index 91e2b7f0f3cd..d5d956c669b5 100644 --- a/test/ELF/aarch64-thunk-pi.s +++ b/test/ELF/aarch64-thunk-pi.s @@ -1,3 +1,4 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t // RUN: echo "SECTIONS { \ // RUN: .text_low : { *(.text_low) } \ @@ -5,7 +6,6 @@ // RUN: } " > %t.script // RUN: ld.lld --script %t.script --shared %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=aarch64-linux-gnu %t2 | FileCheck %s -// REQUIRES: aarch64 // Check that Position Independent thunks are generated for shared libraries. .section .text_low, "ax", %progbits @@ -16,8 +16,8 @@ low_target: bl high_target ret // CHECK: low_target: -// CHECK-NEXT: 0: 04 00 00 94 bl #16 -// CHECK-NEXT: 4: c0 03 5f d6 ret +// CHECK-NEXT: 8: 04 00 00 94 bl #16 +// CHECK-NEXT: c: c0 03 5f d6 ret .hidden low_target2 .globl low_target2 @@ -27,19 +27,19 @@ low_target2: bl high_target2 ret // CHECK: low_target2: -// CHECK-NEXT: 8: 05 00 00 94 bl #20 -// CHECK-NEXT: c: c0 03 5f d6 ret +// CHECK-NEXT: 0: 05 00 00 94 bl #20 +// CHECK-NEXT: 4: c0 03 5f d6 ret // Expect range extension thunks for .text_low // adrp calculation is (PC + signed immediate) & (!0xfff) // CHECK: __AArch64ADRPThunk_high_target: -// CHECK-NEXT: 10: 10 00 08 90 adrp x16, #268435456 -// CHECK-NEXT: 14: 10 82 04 91 add x16, x16, #288 -// CHECK-NEXT: 18: 00 02 1f d6 br x16 +// CHECK-NEXT: e8: 10 00 08 90 adrp x16, #268435456 +// CHECK-NEXT: ec: 10 02 01 91 add x16, x16, #64 +// CHECK-NEXT: f0: 00 02 1f d6 br x16 // CHECK: __AArch64ADRPThunk_high_target2: -// CHECK-NEXT: 1c: 10 00 08 90 adrp x16, #268435456 -// CHECK-NEXT: 20: 10 22 00 91 add x16, x16, #8 -// CHECK-NEXT: 24: 00 02 1f d6 br x16 +// CHECK-NEXT: f4: 10 00 08 90 adrp x16, #268435456 +// CHECK-NEXT: f8: 10 22 00 91 add x16, x16, #8 +// CHECK-NEXT: fc: 00 02 1f d6 br x16 .section .text_high, "ax", %progbits @@ -50,7 +50,7 @@ high_target: bl low_target ret // CHECK: high_target: -// CHECK-NEXT: 10000000: 4c 00 00 94 bl #304 +// CHECK-NEXT: 10000000: 14 00 00 94 bl #80 // CHECK-NEXT: 10000004: c0 03 5f d6 ret .hidden high_target2 @@ -68,24 +68,24 @@ high_target2: // CHECK: __AArch64ADRPThunk_low_target2: // CHECK-NEXT: 10000010: 10 00 f8 90 adrp x16, #-268435456 -// CHECK-NEXT: 10000014: 10 22 00 91 add x16, x16, #8 +// CHECK-NEXT: 10000014: 10 82 03 91 add x16, x16, #224 // CHECK-NEXT: 10000018: 00 02 1f d6 br x16 // CHECK: Disassembly of section .plt: // CHECK-NEXT: .plt: -// CHECK-NEXT: 10000100: f0 7b bf a9 stp x16, x30, [sp, #-16]! -// CHECK-NEXT: 10000104: 10 00 00 90 adrp x16, #0 -// CHECK-NEXT: 10000108: 11 aa 40 f9 ldr x17, [x16, #336] -// CHECK-NEXT: 1000010c: 10 42 05 91 add x16, x16, #336 -// CHECK-NEXT: 10000110: 20 02 1f d6 br x17 -// CHECK-NEXT: 10000114: 1f 20 03 d5 nop -// CHECK-NEXT: 10000118: 1f 20 03 d5 nop -// CHECK-NEXT: 1000011c: 1f 20 03 d5 nop -// CHECK-NEXT: 10000120: 10 00 00 90 adrp x16, #0 -// CHECK-NEXT: 10000124: 11 ae 40 f9 ldr x17, [x16, #344] -// CHECK-NEXT: 10000128: 10 62 05 91 add x16, x16, #344 -// CHECK-NEXT: 1000012c: 20 02 1f d6 br x17 -// CHECK-NEXT: 10000130: 10 00 00 90 adrp x16, #0 -// CHECK-NEXT: 10000134: 11 b2 40 f9 ldr x17, [x16, #352] -// CHECK-NEXT: 10000138: 10 82 05 91 add x16, x16, #352 -// CHECK-NEXT: 1000013c: 20 02 1f d6 br x17 +// CHECK-NEXT: 10000020: f0 7b bf a9 stp x16, x30, [sp, #-16]! +// CHECK-NEXT: 10000024: 10 00 00 90 adrp x16, #0 +// CHECK-NEXT: 10000028: 11 3a 40 f9 ldr x17, [x16, #112] +// CHECK-NEXT: 1000002c: 10 c2 01 91 add x16, x16, #112 +// CHECK-NEXT: 10000030: 20 02 1f d6 br x17 +// CHECK-NEXT: 10000034: 1f 20 03 d5 nop +// CHECK-NEXT: 10000038: 1f 20 03 d5 nop +// CHECK-NEXT: 1000003c: 1f 20 03 d5 nop +// CHECK-NEXT: 10000040: 10 00 00 90 adrp x16, #0 +// CHECK-NEXT: 10000044: 11 3e 40 f9 ldr x17, [x16, #120] +// CHECK-NEXT: 10000048: 10 e2 01 91 add x16, x16, #120 +// CHECK-NEXT: 1000004c: 20 02 1f d6 br x17 +// CHECK-NEXT: 10000050: 10 00 00 90 adrp x16, #0 +// CHECK-NEXT: 10000054: 11 42 40 f9 ldr x17, [x16, #128] +// CHECK-NEXT: 10000058: 10 02 02 91 add x16, x16, #128 +// CHECK-NEXT: 1000005c: 20 02 1f d6 br x17 diff --git a/test/ELF/aarch64-thunk-script.s b/test/ELF/aarch64-thunk-script.s index ebfaf72de5f4..1dfdcbc7a562 100644 --- a/test/ELF/aarch64-thunk-script.s +++ b/test/ELF/aarch64-thunk-script.s @@ -1,3 +1,4 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t // RUN: echo "SECTIONS { \ // RUN: .text_low 0x2000: { *(.text_low) } \ @@ -5,7 +6,6 @@ // RUN: } " > %t.script // RUN: ld.lld --script %t.script %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=aarch64-linux-gnu %t2 | FileCheck %s -// REQUIRES: aarch64 // Check that we have the out of branch range calculation right. The immediate // field is signed so we have a slightly higher negative displacement. diff --git a/test/ELF/aarch64-thunk-section-location.s b/test/ELF/aarch64-thunk-section-location.s index bf70b7c365ba..606c6941579e 100644 --- a/test/ELF/aarch64-thunk-section-location.s +++ b/test/ELF/aarch64-thunk-section-location.s @@ -1,7 +1,7 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -d -start-address=134086664 -stop-address=134086676 -triple=aarch64-linux-gnu %t2 | FileCheck %s -// REQUIRES: aarch64 // Check that the range extension thunks are dumped close to the aarch64 branch // range of 128 MiB .section .text.1, "ax", %progbits diff --git a/test/ELF/aarch64-tls-gdle.s b/test/ELF/aarch64-tls-gdle.s index a111cacefd29..6763c50838da 100644 --- a/test/ELF/aarch64-tls-gdle.s +++ b/test/ELF/aarch64-tls-gdle.s @@ -1,9 +1,9 @@ +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o # RUN: ld.lld %tmain.o %ttlsie.o -o %tout # RUN: llvm-objdump -d %tout | FileCheck %s # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s -# REQUIRES: aarch64 #Local-Dynamic to Initial-Exec relax creates no #RELOC: Relocations [ diff --git a/test/ELF/aarch64-tls-ie.s b/test/ELF/aarch64-tls-ie.s index 8b7431093a26..fba7cd8af51f 100644 --- a/test/ELF/aarch64-tls-ie.s +++ b/test/ELF/aarch64-tls-ie.s @@ -1,11 +1,11 @@ // REQUIRES: aarch64 +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-tls-ie.s -o %tdso.o # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o # RUN: ld.lld -shared %tdso.o -o %tdso.so # RUN: ld.lld --hash-style=sysv %tmain.o %tdso.so -o %tout # RUN: llvm-objdump -d %tout | FileCheck %s # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s -# REQUIRES: aarch64 #RELOC: Section { #RELOC: Index: diff --git a/test/ELF/aarch64-tls-iele.s b/test/ELF/aarch64-tls-iele.s index 208b5cdd5446..c97a578f8dc2 100644 --- a/test/ELF/aarch64-tls-iele.s +++ b/test/ELF/aarch64-tls-iele.s @@ -1,9 +1,9 @@ +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/aarch64-tls-ie.s -o %ttlsie.o # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %tmain.o # RUN: ld.lld %tmain.o %ttlsie.o -o %tout # RUN: llvm-objdump -d %tout | FileCheck %s # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s -# REQUIRES: aarch64 # Initial-Exec to Local-Exec relax creates no dynamic relocations. # RELOC: Relocations [ diff --git a/test/ELF/aarch64-tls-le.s b/test/ELF/aarch64-tls-le.s index df943f7f091a..e5b1c208a185 100644 --- a/test/ELF/aarch64-tls-le.s +++ b/test/ELF/aarch64-tls-le.s @@ -1,8 +1,8 @@ +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %tmain.o # RUN: ld.lld %tmain.o -o %tout # RUN: llvm-objdump -d %tout | FileCheck %s # RUN: llvm-readobj -s -r %tout | FileCheck -check-prefix=RELOC %s -# REQUIRES: aarch64 #Local-Dynamic to Initial-Exec relax creates no #RELOC: Relocations [ diff --git a/test/ELF/aarch64-tlsld-ldst.s b/test/ELF/aarch64-tlsld-ldst.s new file mode 100644 index 000000000000..9de3a38044d9 --- /dev/null +++ b/test/ELF/aarch64-tlsld-ldst.s @@ -0,0 +1,85 @@ +// REQUIRES: aarch64 +// RUN: llvm-mc -triple=aarch64-linux-gnu -filetype=obj %s -o %t.o +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump -d %t | FileCheck %s +// RUN: llvm-readelf --symbols %t | FileCheck -check-prefix CHECK-SYMS %s + + .text + .globl _start + .type _start, %function +_start: mrs x8, TPIDR_EL0 + + add x8, x8, :tprel_hi12:var0 + ldr q20, [x8, :tprel_lo12_nc:var0] + + add x8, x8, :tprel_hi12:var1 + ldr x0, [x8, :tprel_lo12_nc:var1] + + add x8, x8, :tprel_hi12:var2 + ldr w0, [x8, :tprel_lo12_nc:var2] + + add x8, x8, :tprel_hi12:var3 + ldrh w0, [x8, :tprel_lo12_nc:var3] + + add x8, x8, :tprel_hi12:var4 + ldrb w0, [x8, :tprel_lo12_nc:var4] + +// CHECK: _start: +// CHECK-NEXT: 20000: 48 d0 3b d5 mrs x8, TPIDR_EL0 +// 0x0 + c10 = 0xc10 = tcb (16-bytes) + var0 +// CHECK-NEXT: 20004: 08 01 40 91 add x8, x8, #0, lsl #12 +// CHECK-NEXT: 20008: 14 05 c3 3d ldr q20, [x8, #3088] +// 0x1000 + 0x820 = 0x1820 = tcb + var1 +// CHECK-NEXT: 2000c: 08 05 40 91 add x8, x8, #1, lsl #12 +// CHECK-NEXT: 20010: 00 11 44 f9 ldr x0, [x8, #2080] +// 0x2000 + 0x428 = 0x2428 = tcb + var2 +// CHECK-NEXT: 20014: 08 09 40 91 add x8, x8, #2, lsl #12 +// CHECK-NEXT: 20018: 00 29 44 b9 ldr w0, [x8, #1064] +// 0x3000 + 0x2c = 0x302c = tcb + var3 +// CHECK-NEXT: 2001c: 08 0d 40 91 add x8, x8, #3, lsl #12 +// CHECK-NEXT: 20020: 00 59 40 79 ldrh w0, [x8, #44] +// 0x3000 + 0xc2e = 0x32ce = tcb + var4 +// CHECK-NEXT: 20024: 08 0d 40 91 add x8, x8, #3, lsl #12 +// CHECK-NEXT: 20028: 00 b9 70 39 ldrb w0, [x8, #3118] + +// CHECK-SYMS: 0000000000000c00 0 TLS GLOBAL DEFAULT 2 var0 +// CHECK-SYMS-NEXT: 0000000000001810 4 TLS GLOBAL DEFAULT 2 var1 +// CHECK-SYMS-NEXT: 0000000000002418 2 TLS GLOBAL DEFAULT 2 var2 +// CHECK-SYMS-NEXT: 000000000000301c 1 TLS GLOBAL DEFAULT 2 var3 +// CHECK-SYMS-NEXT: 0000000000003c1e 0 TLS GLOBAL DEFAULT 2 var4 + + .globl var0 + .globl var1 + .globl var2 + .globl var3 + .globl var4 + .type var0,@object + .type var1,@object + .type var2,@object + .type var3,@object + +.section .tbss,"awT",@nobits + .balign 16 + .space 1024 * 3 +var0: + .quad 0 + .quad 0 + .size var1, 16 + .space 1024 * 3 +var1: + .quad 0 + .size var1, 8 + .space 1024 * 3 +var2: + .word 0 + .size var1, 4 + + .space 1024 * 3 +var3: + .hword 0 + .size var2, 2 + .space 1024 * 3 +var4: + .byte 0 + .size var3, 1 + .space 1024 * 3 diff --git a/test/ELF/aarch64-tstbr14-reloc.s b/test/ELF/aarch64-tstbr14-reloc.s index c0a0a543a6c5..779ca6b808a8 100644 --- a/test/ELF/aarch64-tstbr14-reloc.s +++ b/test/ELF/aarch64-tstbr14-reloc.s @@ -1,3 +1,4 @@ +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %p/Inputs/aarch64-tstbr14-reloc.s -o %t1 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t2 # RUN: ld.lld %t1 %t2 -o %t @@ -5,7 +6,6 @@ # RUN: ld.lld -shared %t1 %t2 -o %t3 # RUN: llvm-objdump -d %t3 | FileCheck -check-prefix=DSO %s # RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s -# REQUIRES: aarch64 # 0x1101c - 28 = 0x20000 # 0x11020 - 16 = 0x20010 diff --git a/test/ELF/aarch64-undefined-weak.s b/test/ELF/aarch64-undefined-weak.s index 35f50417497e..e2316acf36a0 100644 --- a/test/ELF/aarch64-undefined-weak.s +++ b/test/ELF/aarch64-undefined-weak.s @@ -1,7 +1,7 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-none-linux %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -triple=aarch64-none-linux -d %t2 | FileCheck %s -// REQUIRES: aarch64 // Check that the ARM 64-bit ABI rules for undefined weak symbols are applied. // Branch instructions are resolved to the next instruction. Undefined diff --git a/test/ELF/abs-conflict.s b/test/ELF/abs-conflict.s index 4662c48a4e40..ea435cc956c0 100644 --- a/test/ELF/abs-conflict.s +++ b/test/ELF/abs-conflict.s @@ -15,4 +15,4 @@ foo = 0x123 // DUP: duplicate symbol: foo // DUP-NEXT: >>> defined in {{.*}}.o -// DUP-NEXT: >>> defined in <internal> +// DUP-NEXT: >>> defined in {{.*}}2.o diff --git a/test/ELF/allow-multiple-definition.s b/test/ELF/allow-multiple-definition.s index c54438d9f1e0..06684f47e616 100644 --- a/test/ELF/allow-multiple-definition.s +++ b/test/ELF/allow-multiple-definition.s @@ -3,13 +3,14 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/allow-multiple-definition.s -o %t2 # RUN: not ld.lld %t1 %t2 -o %t3 -# RUN: ld.lld --allow-multiple-definition %t1 %t2 -o %t3 -# RUN: ld.lld --allow-multiple-definition %t2 %t1 -o %t4 +# RUN: not ld.lld --allow-multiple-definition --no-allow-multiple-definition %t1 %t2 -o %t3 +# RUN: ld.lld --allow-multiple-definition --fatal-warnings %t1 %t2 -o %t3 +# RUN: ld.lld --allow-multiple-definition --fatal-warnings %t2 %t1 -o %t4 # RUN: llvm-objdump -d %t3 | FileCheck %s # RUN: llvm-objdump -d %t4 | FileCheck -check-prefix=REVERT %s -# RUN: ld.lld -z muldefs %t1 %t2 -o %t3 -# RUN: ld.lld -z muldefs %t2 %t1 -o %t4 +# RUN: ld.lld -z muldefs --fatal-warnings %t1 %t2 -o %t3 +# RUN: ld.lld -z muldefs --fatal-warnings %t2 %t1 -o %t4 # RUN: llvm-objdump -d %t3 | FileCheck %s # RUN: llvm-objdump -d %t4 | FileCheck -check-prefix=REVERT %s diff --git a/test/ELF/amdgpu-elf-flags-err.s b/test/ELF/amdgpu-elf-flags-err.s index 4c295b5b92e4..b5619352fb04 100644 --- a/test/ELF/amdgpu-elf-flags-err.s +++ b/test/ELF/amdgpu-elf-flags-err.s @@ -1,7 +1,6 @@ -# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o -# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-1.s -o %t-1.o -# RUN: not ld.lld -shared %t-0.o %t-1.o %S/Inputs/amdgpu-kernel-2.o -o %t.so 2>&1 | FileCheck %s - # REQUIRES: amdgpu +# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx802 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o +# RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-1.s -o %t-1.o +# RUN: not ld.lld -shared %t-0.o %t-1.o -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: incompatible e_flags: {{.*}}amdgpu-kernel-2.o +# CHECK: error: incompatible e_flags: {{.*}}-1.o diff --git a/test/ELF/amdgpu-elf-flags.s b/test/ELF/amdgpu-elf-flags.s index 85f891a98364..d062dac748ea 100644 --- a/test/ELF/amdgpu-elf-flags.s +++ b/test/ELF/amdgpu-elf-flags.s @@ -1,10 +1,9 @@ +# REQUIRES: amdgpu # RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-0.s -o %t-0.o # RUN: llvm-mc -triple amdgcn-amd-amdhsa -mcpu=gfx803 -filetype=obj %S/Inputs/amdgpu-kernel-1.s -o %t-1.o # RUN: ld.lld -shared %t-0.o %t-1.o -o %t.so # RUN: llvm-readobj -file-headers %t.so | FileCheck %s -# REQUIRES: amdgpu - -# CHECK: Flags [ (0x2) -# CHECK: EF_AMDGPU_ARCH_GCN (0x2) +# CHECK: Flags [ +# CHECK: EF_AMDGPU_MACH_AMDGCN_GFX803 (0x2A) # CHECK: ] diff --git a/test/ELF/amdgpu-globals.s b/test/ELF/amdgpu-globals.s index e32159b332e7..eadc4ef1e0d6 100644 --- a/test/ELF/amdgpu-globals.s +++ b/test/ELF/amdgpu-globals.s @@ -1,9 +1,8 @@ +# REQUIRES: amdgpu # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o # RUN: ld.lld -shared %t.o -o %t # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s -# REQUIRES: amdgpu - .type glob0, @object .data .globl glob0 diff --git a/test/ELF/amdgpu-kernels.s b/test/ELF/amdgpu-kernels.s index c76613f1a336..01b1ef2757fb 100644 --- a/test/ELF/amdgpu-kernels.s +++ b/test/ELF/amdgpu-kernels.s @@ -1,9 +1,8 @@ +# REQUIRES: amdgpu # RUN: llvm-mc -filetype=obj -triple amdgcn--amdhsa -mcpu=kaveri %s -o %t.o # RUN: ld.lld -shared %t.o -o %t # RUN: llvm-readobj -sections -symbols -program-headers %t | FileCheck %s -# REQUIRES: amdgpu - .hsa_code_object_version 1,0 .hsa_code_object_isa 7,0,0,"AMD","AMDGPU" diff --git a/test/ELF/amdgpu-relocs.s b/test/ELF/amdgpu-relocs.s index 8b5a61ed21f4..eeb7571e21df 100644 --- a/test/ELF/amdgpu-relocs.s +++ b/test/ELF/amdgpu-relocs.s @@ -1,10 +1,9 @@ +# REQUIRES: amdgpu # RUN: llvm-mc -filetype=obj -triple=amdgcn--amdhsa -mcpu=fiji %s -o %t.o # RUN: ld.lld --hash-style=sysv -shared %t.o -o %t.so # RUN: llvm-readobj -r %t.so | FileCheck %s # RUN: llvm-objdump -s %t.so | FileCheck %s --check-prefix=OBJDUMP -# REQUIRES: amdgpu - .text kernel0: @@ -77,6 +76,15 @@ ptr: ptr2: .quad temp2 +# R_AMDGPU_REL64: +.type foo, @object +.rodata + .globl foo + .p2align 3 +foo: + .quad temp2@rel64 + .size foo, 8 + # The relocation for local_var{0, 1, 2} and var should be resolved by the # linker. # CHECK: Relocations [ @@ -101,6 +109,9 @@ ptr2: # CHECK-NEXT: } # CHECK-NEXT: ] +# OBJDUMP: Contents of section .rodata: +# OBJDUMP: d0f8ffff ffffffff + # OBJDUMP: Contents of section nonalloc: # OBJDUMP-NEXT: 0000 00000000 04480000 00000000 08440000 # OBJDUMP-NEXT: 00000000 0c400000 diff --git a/test/ELF/archive.s b/test/ELF/archive.s index 59c96a5fba9b..aa7455764fbf 100644 --- a/test/ELF/archive.s +++ b/test/ELF/archive.s @@ -1,16 +1,21 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive.s -o %t2 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t3 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive3.s -o %t4 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive4.s -o %t5 -# RUN: llvm-ar rcs %tar %t2 %t3 %t4 -# RUN: ld.lld %t %tar %t5 -o %tout -# RUN: llvm-nm %tout | FileCheck %s -# RUN: rm -f %tarthin -# RUN: llvm-ar --format=gnu rcsT %tarthin %t2 %t3 %t4 -# RUN: ld.lld %t %tarthin %t5 -o %tout -# RUN: llvm-nm %tout | FileCheck %s -# REQUIRES: x86 + +# RUN: rm -f %t.a +# RUN: llvm-ar rcs %t.a %t2 %t3 %t4 + +# RUN: ld.lld %t %t.a %t5 -o %t.out +# RUN: llvm-nm %t.out | FileCheck %s + +# RUN: rm -f %t.thin +# RUN: llvm-ar --format=gnu rcsT %t.thin %t2 %t3 %t4 + +# RUN: ld.lld %t %t.thin %t5 -o %t.out +# RUN: llvm-nm %t.out | FileCheck %s # Nothing here. Just needed for the linker to create a undefined _start symbol. @@ -31,8 +36,8 @@ # Test that the hitting the first object file after having a lazy symbol for # _start is handled correctly. -# RUN: ld.lld %tar %t -o %tout -# RUN: llvm-nm %tout | FileCheck --check-prefix=AR-FIRST %s +# RUN: ld.lld %t.a %t -o %t.out +# RUN: llvm-nm %t.out | FileCheck --check-prefix=AR-FIRST %s # AR-FIRST: T _start # AR-FIRST-NEXT: w bar diff --git a/test/ELF/arm-attributes.s b/test/ELF/arm-attributes.s index 14517e8fc789..e4411e79b010 100644 --- a/test/ELF/arm-attributes.s +++ b/test/ELF/arm-attributes.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-attributes1.s -o %t1.o // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2.o @@ -7,7 +8,6 @@ // RUN: llvm-readobj -arm-attributes %t2 | FileCheck %s // RUN: ld.lld %t1.o %t2.o -r -o %t3 // RUN: llvm-readobj -arm-attributes %t3 | FileCheck %s -// REQUIRES: arm // Check that we retain only 1 SHT_ARM_ATTRIBUTES section. At present we do not // try and merge or use the contents of SHT_ARM_ATTRIBUTES sections. We just diff --git a/test/ELF/arm-bl-v6.s b/test/ELF/arm-bl-v6.s index 6317aa433d6c..c27a99e6b9e7 100644 --- a/test/ELF/arm-bl-v6.s +++ b/test/ELF/arm-bl-v6.s @@ -1,6 +1,6 @@ -// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t -// RUN: ld.lld %t -o %t2 2>&1 | FileCheck %s // REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s // On Arm v6 the range of a Thumb BL instruction is only 4 megabytes as the // extended range encoding is not supported. The following example has a Thumb diff --git a/test/ELF/arm-blx-v4t.s b/test/ELF/arm-blx-v4t.s index 858b93fd5891..f526b3b01f4a 100644 --- a/test/ELF/arm-blx-v4t.s +++ b/test/ELF/arm-blx-v4t.s @@ -1,6 +1,6 @@ -// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t -// RUN: ld.lld %t -o %t2 2>&1 | FileCheck %s // REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=arm-none-linux-gnueabi %s -o %t +// RUN: ld.lld %t -o /dev/null 2>&1 | FileCheck %s // On Arm v4t there is no blx instruction so all interworking must go via // a thunk. At present we don't support v4t so we give a warning for unsupported diff --git a/test/ELF/arm-blx.s b/test/ELF/arm-blx.s index 159eee51c74c..5b44c8416c20 100644 --- a/test/ELF/arm-blx.s +++ b/test/ELF/arm-blx.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar // RUN: echo "SECTIONS { \ @@ -10,7 +11,6 @@ // RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s -// REQUIRES: arm // Test BLX instruction is chosen for ARM BL/BLX instruction and Thumb callee // Using two callees to ensure at least one has 2-byte alignment. diff --git a/test/ELF/arm-branch-rangethunk.s b/test/ELF/arm-branch-rangethunk.s index c61ec899adae..739a7707dbec 100644 --- a/test/ELF/arm-branch-rangethunk.s +++ b/test/ELF/arm-branch-rangethunk.s @@ -1,8 +1,11 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar // RUN: ld.lld %t %tfar -o %t2 2>&1 -// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s -// REQUIRES: arm +// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck --check-prefix=SHORT %s +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-long-arm-abs.s -o %tfarlong +// RUN: ld.lld %t %tfarlong -o %t3 2>&1 +// RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck --check-prefix=LONG %s .syntax unified .section .text, "ax",%progbits .globl _start @@ -15,20 +18,32 @@ _start: b too_far2 beq too_far3 -// CHECK: Disassembly of section .text: -// CHECK-NEXT: _start: -// CHECK-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1> -// CHECK-NEXT: 20004: 03 00 00 ea b #12 <__ARMv7ABSLongThunk_too_far2> -// CHECK-NEXT: 20008: 05 00 00 0a beq #20 <__ARMv7ABSLongThunk_too_far3> -// CHECK: __ARMv7ABSLongThunk_too_far1: -// CHECK-NEXT: 2000c: 08 c0 00 e3 movw r12, #8 -// CHECK-NEXT: 20010: 02 c2 40 e3 movt r12, #514 -// CHECK-NEXT: 20014: 1c ff 2f e1 bx r12 -// CHECK: __ARMv7ABSLongThunk_too_far2: -// CHECK-NEXT: 20018: 0c c0 00 e3 movw r12, #12 -// CHECK-NEXT: 2001c: 02 c2 40 e3 movt r12, #514 -// CHECK-NEXT: 20020: 1c ff 2f e1 bx r12 -// CHECK: __ARMv7ABSLongThunk_too_far3: -// CHECK-NEXT: 20024: 10 c0 00 e3 movw r12, #16 -// CHECK-NEXT: 20028: 02 c2 40 e3 movt r12, #514 -// CHECK-NEXT: 2002c: 1c ff 2f e1 bx r12 +// SHORT: Disassembly of section .text: +// SHORT-NEXT: _start: +// SHORT-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1> +// SHORT-NEXT: 20004: 01 00 00 ea b #4 <__ARMv7ABSLongThunk_too_far2> +// SHORT-NEXT: 20008: 01 00 00 0a beq #4 <__ARMv7ABSLongThunk_too_far3> +// SHORT: __ARMv7ABSLongThunk_too_far1: +// SHORT-NEXT: 2000c: fd ff 7f ea b #33554420 <__ARMv7ABSLongThunk_too_far3+0x1fffff4> +// SHORT: __ARMv7ABSLongThunk_too_far2: +// SHORT-NEXT: 20010: fd ff 7f ea b #33554420 <__ARMv7ABSLongThunk_too_far3+0x1fffff8> +// SHORT: __ARMv7ABSLongThunk_too_far3: +// SHORT-NEXT: 20014: fd ff 7f ea b #33554420 <__ARMv7ABSLongThunk_too_far3+0x1fffffc> + +// LONG: Disassembly of section .text: +// LONG-NEXT: _start: +// LONG-NEXT: 20000: 01 00 00 eb bl #4 <__ARMv7ABSLongThunk_too_far1> +// LONG-NEXT: 20004: 03 00 00 ea b #12 <__ARMv7ABSLongThunk_too_far2> +// LONG-NEXT: 20008: 05 00 00 0a beq #20 <__ARMv7ABSLongThunk_too_far3> +// LONG: __ARMv7ABSLongThunk_too_far1: +// LONG-NEXT: 2000c: 14 c0 00 e3 movw r12, #20 +// LONG-NEXT: 20010: 02 c2 40 e3 movt r12, #514 +// LONG-NEXT: 20014: 1c ff 2f e1 bx r12 +// LONG: __ARMv7ABSLongThunk_too_far2: +// LONG-NEXT: 20018: 20 c0 00 e3 movw r12, #32 +// LONG-NEXT: 2001c: 02 c2 40 e3 movt r12, #514 +// LONG-NEXT: 20020: 1c ff 2f e1 bx r12 +// LONG: __ARMv7ABSLongThunk_too_far3: +// LONG-NEXT: 20024: 2c c0 00 e3 movw r12, #44 +// LONG-NEXT: 20028: 02 c2 40 e3 movt r12, #514 +// LONG-NEXT: 2002c: 1c ff 2f e1 bx r12 diff --git a/test/ELF/arm-branch-undef-weak-plt-thunk.s b/test/ELF/arm-branch-undef-weak-plt-thunk.s index f95da0dcec21..f47ed61ca5a6 100644 --- a/test/ELF/arm-branch-undef-weak-plt-thunk.s +++ b/test/ELF/arm-branch-undef-weak-plt-thunk.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-shared.s -o %t // RUN: ld.lld %t --shared -o %t.so // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2 // RUN: ld.lld %t2 %t.so -o %t3 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi -start-address=69632 -stop-address=69664 %t3 | FileCheck %s -// REQUIRES: arm // When we are dynamic linking, undefined weak references have a PLT entry so // we must create a thunk for the branch to the PLT entry. diff --git a/test/ELF/arm-branch.s b/test/ELF/arm-branch.s index 986863d3d80c..48c497724b0d 100644 --- a/test/ELF/arm-branch.s +++ b/test/ELF/arm-branch.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/far-arm-abs.s -o %tfar // RUN: echo "SECTIONS { \ @@ -7,7 +8,6 @@ // RUN: .callee2 : { *(.callee_high) } } " > %t.script // RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s -// REQUIRES: arm .syntax unified .section .callee_low, "ax",%progbits .align 2 diff --git a/test/ELF/arm-copy.s b/test/ELF/arm-copy.s index dc9e3628de4f..e42f93ea5bb6 100644 --- a/test/ELF/arm-copy.s +++ b/test/ELF/arm-copy.s @@ -1,7 +1,7 @@ // REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/relocation-copy-arm.s -o %t2.o -// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld -shared %t2.o -soname fixed-length-string.so -o %t2.so // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t3 // RUN: llvm-readobj -s -r --expand-relocs -symbols %t3 | FileCheck %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CODE %s @@ -33,7 +33,7 @@ _start: // CHECK-NEXT: AddressAlignment: 16 // CHECK: Relocations [ -// CHECK-NEXT: Section (5) .rel.dyn { +// CHECK-NEXT: Section {{.*}} .rel.dyn { // CHECK-NEXT: Relocation { // CHECK-NEXT: Offset: 0x13000 // CHECK-NEXT: Type: R_ARM_COPY @@ -78,4 +78,4 @@ _start: // RODATA: Contents of section .rodata: // S(z) = 0x13004 -// RODATA-NEXT: 10114 04300100 +// RODATA-NEXT: 10190 04300100 diff --git a/test/ELF/arm-data-prel.s b/test/ELF/arm-data-prel.s index a8c0c280b220..78b42818609b 100644 --- a/test/ELF/arm-data-prel.s +++ b/test/ELF/arm-data-prel.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o // RUN: echo "SECTIONS { \ // RUN: .text : { *(.text) } \ @@ -6,7 +7,6 @@ // RUN: .TEST1 : { *(.TEST1) } } " > %t.script // RUN: ld.lld --script %t.script %t.o -o %t // RUN: llvm-readobj -s -sd %t | FileCheck --check-prefix=CHECK %s -// REQUIRES: arm // The R_ARM_PREL31 relocation is used in by the .ARM.exidx exception tables // bit31 of the place denotes whether the field is an inline table entry diff --git a/test/ELF/arm-data-relocs.s b/test/ELF/arm-data-relocs.s index ed237850c4c1..586e1a6c8933 100644 --- a/test/ELF/arm-data-relocs.s +++ b/test/ELF/arm-data-relocs.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/abs256.s -o %t256.o // RUN: ld.lld %t %t256.o -o %t2 // RUN: llvm-objdump -d %t2 | FileCheck %s -// REQUIRES: arm .syntax unified .globl _start _start: diff --git a/test/ELF/arm-eabi-version.s b/test/ELF/arm-eabi-version.s index 727b805fddd7..a08374c132f0 100644 --- a/test/ELF/arm-eabi-version.s +++ b/test/ELF/arm-eabi-version.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-readobj -file-headers %tout | FileCheck %s -// REQUIRES: arm .syntax unified .text .globl _start diff --git a/test/ELF/arm-execute-only.s b/test/ELF/arm-execute-only.s new file mode 100644 index 000000000000..999d88c9e768 --- /dev/null +++ b/test/ELF/arm-execute-only.s @@ -0,0 +1,40 @@ +// REQUIRES: arm + +// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t.so -shared +// RUN: llvm-readelf -l %t.so | FileCheck %s + +// RUN: ld.lld %t.o %t.o -o %t.so -shared +// RUN: llvm-readelf -l %t.so | FileCheck %s + +// RUN: echo ".section .foo,\"ax\"; \ +// RUN: bx lr" > %t.s +// RUN: llvm-mc -filetype=obj -triple=armv7-pc-linux %t.s -o %t2.o +// RUN: ld.lld %t.o %t2.o -o %t.so -shared +// RUN: llvm-readelf -l %t.so | FileCheck --check-prefix=DIFF %s + +// CHECK-NOT: LOAD +// CHECK: LOAD 0x000000 0x00000000 0x00000000 0x0016d 0x0016d R 0x1000 +// CHECK: LOAD 0x001000 0x00001000 0x00001000 0x{{.*}} 0x{{.*}} R E 0x1000 +// CHECK: LOAD 0x002000 0x00002000 0x00002000 0x{{.*}} 0x{{.*}} E 0x1000 +// CHECK: LOAD 0x003000 0x00003000 0x00003000 0x00038 0x00038 RW 0x1000 +// CHECK-NOT: LOAD + +// CHECK: 01 .dynsym .gnu.hash .hash .dynstr +// CHECK: 02 .text +// CHECK: 03 .foo +// CHECK: 04 .dynamic + +// DIFF-NOT: LOAD +// DIFF: LOAD 0x000000 0x00000000 0x00000000 0x0014d 0x0014d R 0x1000 +// DIFF: LOAD 0x001000 0x00001000 0x00001000 0x0000c 0x0000c R E 0x1000 +// DIFF: LOAD 0x002000 0x00002000 0x00002000 0x00038 0x00038 RW 0x1000 +// DIFF-NOT: LOAD + +// DIFF: 01 .dynsym .gnu.hash .hash .dynstr +// DIFF: 02 .text .foo +// DIFF: 03 .dynamic + + bx lr + .section .foo,"axy" + bx lr diff --git a/test/ELF/arm-exidx-canunwind.s b/test/ELF/arm-exidx-canunwind.s index 96a7808e8e84..df89d0082fcf 100644 --- a/test/ELF/arm-exidx-canunwind.s +++ b/test/ELF/arm-exidx-canunwind.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s // RUN: llvm-readobj --program-headers --sections %t2 | FileCheck -check-prefix=CHECK-PT %s -// REQUIRES: arm // Test that inline unwinding table entries and references to .ARM.extab // entries survive the re-ordering of the .ARM.exidx section diff --git a/test/ELF/arm-exidx-dedup.s b/test/ELF/arm-exidx-dedup.s index 1648f77152e9..49d4c2cd1ec3 100644 --- a/test/ELF/arm-exidx-dedup.s +++ b/test/ELF/arm-exidx-dedup.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t --no-merge-exidx-entries -o %t2 // RUN: llvm-objdump -s %t2 | FileCheck --check-prefix CHECK-DUPS %s // RUN: ld.lld %t -o %t3 // RUN: llvm-objdump -s %t3 | FileCheck %s -// REQUIRES: arm // Test that lld can at least remove duplicate .ARM.exidx sections. A more // fine grained implementation will be able to remove duplicate entries within // a .ARM.exidx section. diff --git a/test/ELF/arm-exidx-discard.s b/test/ELF/arm-exidx-discard.s new file mode 100644 index 000000000000..2a204a04cd1b --- /dev/null +++ b/test/ELF/arm-exidx-discard.s @@ -0,0 +1,14 @@ +// REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple arm-gnu-linux-eabi -mcpu cortex-a7 -arm-add-build-attributes %s -o %t.o +// RUN: echo "ENTRY(__entrypoint) SECTIONS { . = 0x10000; .text : { *(.text .text.*) } /DISCARD/ : { *(.ARM.exidx*) *(.gnu.linkonce.armexidx.*) } }" > %t.script +// RUN: ld.lld -T %t.script %t.o -o %t.elf 2>&1 +// RUN: llvm-readobj -sections %t.elf | FileCheck %s + +.globl __entrypoint +__entrypoint: + bx lr + +// Check that .ARM.exidx/.gnu.linkonce.armexidx +// are correctly removed if they were added. +// CHECK-NOT: .ARM.exidx +// CHECK-NOT: .gnu.linkonce.armexidx. diff --git a/test/ELF/arm-exidx-gc.s b/test/ELF/arm-exidx-gc.s index 34bd9dbe37b2..50c8616ae773 100644 --- a/test/ELF/arm-exidx-gc.s +++ b/test/ELF/arm-exidx-gc.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t --no-merge-exidx-entries -o %t2 --gc-sections 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXIDX %s -// REQUIRES: arm // Test the behavior of .ARM.exidx sections under garbage collection // A .ARM.exidx section is live if it has a relocation to a live executable diff --git a/test/ELF/arm-exidx-order.s b/test/ELF/arm-exidx-order.s index c988ad8a2cfe..7e2d4ce91d92 100644 --- a/test/ELF/arm-exidx-order.s +++ b/test/ELF/arm-exidx-order.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-exidx-cantunwind.s -o %tcantunwind // RUN: ld.lld --no-merge-exidx-entries %t %tcantunwind -o %t2 2>&1 @@ -11,7 +12,6 @@ // RUN: ld.lld --no-merge-exidx-entries --script %t.script %tcantunwind %t -o %t3 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT %s // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-SCRIPT-EXIDX %s -// REQUIRES: arm // Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set // with the sh_link containing the section index of the executable section @@ -142,28 +142,28 @@ f3: // CHECK-SCRIPT-NEXT: 11014: 1e ff 2f e1 bx lr // CHECK-SCRIPT-NEXT: Disassembly of section .func1: // CHECK-SCRIPT-NEXT: func1: -// CHECK-SCRIPT-NEXT: 11068: 1e ff 2f e1 bx lr +// CHECK-SCRIPT-NEXT: 11018: 1e ff 2f e1 bx lr // CHECK-SCRIPT-NEXT: Disassembly of section .func2: // CHECK-SCRIPT-NEXT: func2: -// CHECK-SCRIPT-NEXT: 1106c: 1e ff 2f e1 bx lr +// CHECK-SCRIPT-NEXT: 1101c: 1e ff 2f e1 bx lr // CHECK-SCRIPT-NEXT: Disassembly of section .func3: // CHECK-SCRIPT-NEXT: func3: -// CHECK-SCRIPT-NEXT: 11070: 1e ff 2f e1 bx lr +// CHECK-SCRIPT-NEXT: 11020: 1e ff 2f e1 bx lr // Check that the .ARM.exidx section is sorted in order as the functions // The offset in field 1, is 32-bit so in the binary the most significant bit -// 11018 - 18 = 11000 func4 -// 11020 - 1c = 11004 func5 -// CHECK-SCRIPT-EXIDX: 11018 e8ffff7f 01000000 e4ffff7f 01000000 -// 11028 - 20 = 11008 _start -// 11030 - 24 = 1100c f1 -// CHECK-SCRIPT-EXIDX-NEXT: 11028 e0ffff7f 01000000 dcffff7f 01000000 -// 11038 - 28 = 11010 f2 -// 11040 - 2c = 11014 f3 -// CHECK-SCRIPT-EXIDX-NEXT: 11038 d8ffff7f 01000000 d4ffff7f 01000000 -// 11048 + 20 = 11068 func1 -// 11050 + 1c = 1106c func2 -// CHECK-SCRIPT-EXIDX-NEXT: 11048 20000000 01000000 1c000000 01000000 -// 11058 + 18 = 11070 func3 -// 11060 + 14 = 11074 func3 + sizeof(func3) -// CHECK-SCRIPT-EXIDX-NEXT: 11058 18000000 01000000 14000000 01000000 +// 11024 - 24 = 11000 func4 +// 1102c - 28 = 11004 func5 +// CHECK-SCRIPT-EXIDX: 11024 dcffff7f 01000000 d8ffff7f 01000000 +// 11034 - 2c = 11008 _start +// 1103c - 30 = 1100c f1 +// CHECK-SCRIPT-EXIDX-NEXT: 11034 d4ffff7f 01000000 d0ffff7f 01000000 +// 11044 - 34 = 11010 f2 +// 1104c - 38 = 11014 f3 +// CHECK-SCRIPT-EXIDX-NEXT: 11044 ccffff7f 01000000 c8ffff7f 01000000 +// 11054 - 3c = 11018 func1 +// 1105c - 40 = 1101c func2 +// CHECK-SCRIPT-EXIDX-NEXT: 11054 c4ffff7f 01000000 c0ffff7f 01000000 +// 11064 - 44 = 11020 func3 +// 11068 - 48 = 11024 func3 + sizeof(func3) +// CHECK-SCRIPT-EXIDX-NEXT: 11064 bcffff7f 01000000 b8ffff7f 01000000 diff --git a/test/ELF/arm-exidx-output.s b/test/ELF/arm-exidx-output.s index dca43a359934..4c65c274b713 100644 --- a/test/ELF/arm-exidx-output.s +++ b/test/ELF/arm-exidx-output.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-readobj -sections %t2 | FileCheck %s -// REQUIRES: arm // Check that only a single .ARM.exidx output section is created when // there are input sections of the form .ARM.exidx.<section-name>. The diff --git a/test/ELF/arm-exidx-relocatable.s b/test/ELF/arm-exidx-relocatable.s index 1b6ee3f23a4f..422dfc289ed7 100644 --- a/test/ELF/arm-exidx-relocatable.s +++ b/test/ELF/arm-exidx-relocatable.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %S/Inputs/arm-exidx-cantunwind.s -o %tcantunwind // Check that relocatable link maintains SHF_LINK_ORDER // RUN: ld.lld -r %t %tcantunwind -o %t4 2>&1 // RUN: llvm-readobj -s %t4 | FileCheck %s -// REQUIRES: arm // Each assembler created .ARM.exidx section has the SHF_LINK_ORDER flag set // with the sh_link containing the section index of the executable section diff --git a/test/ELF/arm-exidx-sentinel-norelocatable.s b/test/ELF/arm-exidx-sentinel-norelocatable.s index 4a5b64d8cd18..22e3a09c573f 100644 --- a/test/ELF/arm-exidx-sentinel-norelocatable.s +++ b/test/ELF/arm-exidx-sentinel-norelocatable.s @@ -1,6 +1,6 @@ +// REQUIRES: arm // RUN: llvm-mc %s -triple=armv7-unknown-linux-gnueabi -filetype=obj -o %t.o // RUN: ld.lld -r %t.o -o %t -// REQUIRES: arm // RUN: llvm-readobj -s %t | FileCheck %s // Check that when doing a relocatable link we don't add a terminating entry // to the .ARM.exidx section diff --git a/test/ELF/arm-exidx-sentinel-orphan.s b/test/ELF/arm-exidx-sentinel-orphan.s index 0e68c245dd10..9aebc4299184 100644 --- a/test/ELF/arm-exidx-sentinel-orphan.s +++ b/test/ELF/arm-exidx-sentinel-orphan.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // Use Linker script without .ARM.exidx Output Section so it is treated as // an orphan. We must still add the sentinel table entry @@ -6,7 +7,6 @@ // RUN: } " > %t.script // RUN: ld.lld --no-merge-exidx-entries --script %t.script %t -o %t2 // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s -// REQUIRES: arm .syntax unified .text @@ -20,4 +20,4 @@ _start: // CHECK: Contents of section .ARM.exidx: // 11004 - 4 = 0x11000 = _start // 1100c - 8 = 0x11004 = _start + sizeof(_start) -// CHECK-NEXT: 11004 fcffff7f 01000000 f8ffff7f 01000000 +// CHECK-NEXT: 0000 00100100 01000000 fc0f0100 01000000 diff --git a/test/ELF/arm-exidx-shared.s b/test/ELF/arm-exidx-shared.s index bf7c2dc383e7..631eb0711b8d 100644 --- a/test/ELF/arm-exidx-shared.s +++ b/test/ELF/arm-exidx-shared.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld --hash-style=sysv %t --shared -o %t2 2>&1 // RUN: llvm-readobj --relocations %t2 | FileCheck %s // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-EXTAB %s -// REQUIRES: arm // Check that the relative R_ARM_PREL31 relocation can access a PLT entry // for when the personality routine is referenced from a shared library. @@ -37,9 +37,9 @@ __aeabi_unwind_cpp_pr0: bx lr // CHECK: Relocations [ -// CHECK-NEXT: Section (6) .rel.plt { +// CHECK-NEXT: Section {{.*}} .rel.plt { // CHECK-NEXT: 0x200C R_ARM_JUMP_SLOT __gxx_personality_v0 // CHECK-EXTAB: Contents of section .ARM.extab: -// 014c + 0ee4 = 0x1030 = __gxx_personality_v0(PLT) -// CHECK-EXTAB-NEXT: 014c e40e0000 b0b0b000 00000000 +// 0x0210 + 0x0e20 = 0x1030 = __gxx_personality_v0(PLT) +// CHECK-EXTAB-NEXT: 0210 200e0000 b0b0b000 00000000 diff --git a/test/ELF/arm-gnu-ifunc-nosym.s b/test/ELF/arm-gnu-ifunc-nosym.s index fa79aef7ced8..b76ede75b4a1 100644 --- a/test/ELF/arm-gnu-ifunc-nosym.s +++ b/test/ELF/arm-gnu-ifunc-nosym.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-readobj -symbols %tout | FileCheck %s -// REQUIRES: arm // Check that no __rel_iplt_end/__rel_iplt_start // appear in symtab if there are no references to them. diff --git a/test/ELF/arm-gnu-ifunc-plt.s b/test/ELF/arm-gnu-ifunc-plt.s index 2ff2ec0a143d..441c31c2bb25 100644 --- a/test/ELF/arm-gnu-ifunc-plt.s +++ b/test/ELF/arm-gnu-ifunc-plt.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %S/Inputs/arm-shared.s -o %t1.o // RUN: ld.lld %t1.o --shared -o %t.so // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t.o @@ -5,7 +6,6 @@ // RUN: llvm-objdump -triple=armv7a-linux-gnueabihf -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s -// REQUIRES: arm // Check that the IRELATIVE relocations are last in the .got // CHECK: Relocations [ diff --git a/test/ELF/arm-gnu-ifunc.s b/test/ELF/arm-gnu-ifunc.s index 799b8b17f62b..8a7cb0ae237a 100644 --- a/test/ELF/arm-gnu-ifunc.s +++ b/test/ELF/arm-gnu-ifunc.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-objdump -triple armv7a-none-linux-gnueabi -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s -// REQUIRES: arm .syntax unified .text .type foo STT_GNU_IFUNC diff --git a/test/ELF/arm-gotoff.s b/test/ELF/arm-gotoff.s index 5169f84e6a01..b9432b20df20 100644 --- a/test/ELF/arm-gotoff.s +++ b/test/ELF/arm-gotoff.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabi %s -o %t.o // RUN: ld.lld %t.o -o %t // RUN: llvm-readobj -s -r -t %t | FileCheck %s // RUN: llvm-objdump -triple=armv7a-linux-gnueabi -d %t | FileCheck --check-prefix=DISASM %s -// REQUIRES: arm // Test the R_ARM_GOTOFF32 relocation diff --git a/test/ELF/arm-long-thunk-converge.s b/test/ELF/arm-long-thunk-converge.s new file mode 100644 index 000000000000..dadc7e5fc9a9 --- /dev/null +++ b/test/ELF/arm-long-thunk-converge.s @@ -0,0 +1,29 @@ +// REQUIRES: arm +// RUN: llvm-mc -triple armv7-unknown-gnu -filetype=obj -o %t %s +// RUN: ld.lld %t %S/Inputs/arm-long-thunk-converge.lds -o %t2 +// RUN: llvm-objdump -d -start-address=0x00000000 -stop-address=0x00000010 -triple=armv7a-linux-gnueabihf %t2 | FileCheck --check-prefix=CHECK1 %s +// RUN: llvm-objdump -d -start-address=0x02000000 -stop-address=0x02000010 -triple=armv7a-linux-gnueabihf %t2 | FileCheck --check-prefix=CHECK2 %s +// RUN: rm -f %t2 + +// CHECK1: __ARMv7ABSLongThunk_bar: +// CHECK1-NEXT: 0: 0c c0 00 e3 movw r12, #12 +// CHECK1-NEXT: 4: 00 c2 40 e3 movt r12, #512 +// CHECK1-NEXT: 8: 1c ff 2f e1 bx r12 +// CHECK1: foo: +// CHECK1-NEXT: c: fb ff ff eb bl #-20 + +.section .foo,"ax",%progbits,unique,1 +foo: +bl bar + +// CHECK2: __ARMv7ABSLongThunk_foo: +// CHECK2-NEXT: 2000000: 0c c0 00 e3 movw r12, #12 +// CHECK2-NEXT: 2000004: 00 c0 40 e3 movt r12, #0 +// CHECK2-NEXT: 2000008: 1c ff 2f e1 bx r12 +// CHECK2: bar: +// CHECK2-NEXT: 200000c: fb ff ff eb bl #-20 <__ARMv7ABSLongThunk_foo> + +.section .bar,"ax",%progbits,unique,1 +bar: +bl foo +.zero 0x1000000 diff --git a/test/ELF/arm-mov-relocs.s b/test/ELF/arm-mov-relocs.s index 7e3ce67e0615..f49e2c102e40 100644 --- a/test/ELF/arm-mov-relocs.s +++ b/test/ELF/arm-mov-relocs.s @@ -1,10 +1,10 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-unknown-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-objdump -d %t2 -triple=armv7a-unknown-linux-gnueabi | FileCheck %s // RUN: llvm-mc -filetype=obj -triple=thumbv7a-unknown-linux-gnueabi %s -o %t3 // RUN: ld.lld %t3 -o %t4 // RUN: llvm-objdump -d %t4 -triple=thumbv7a-unknown-linux-gnueabi | FileCheck %s -// REQUIRES: arm // Test the R_ARM_MOVW_ABS_NC and R_ARM_MOVT_ABS relocations as well as // the R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_ABS relocations. diff --git a/test/ELF/arm-pie-relative.s b/test/ELF/arm-pie-relative.s index f225015eb5f3..582bb8aa03d2 100644 --- a/test/ELF/arm-pie-relative.s +++ b/test/ELF/arm-pie-relative.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld --hash-style=sysv %t --pie -o %t2 // RUN: llvm-readobj -r %t2 | FileCheck %s // RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=GOT -// REQUIRES: arm // Test that a R_ARM_GOT_BREL relocation with PIE results in a R_ARM_RELATIVE // dynamic relocation diff --git a/test/ELF/arm-plt-reloc.s b/test/ELF/arm-plt-reloc.s index f8166d60ffcf..347bc87f6655 100644 --- a/test/ELF/arm-plt-reloc.s +++ b/test/ELF/arm-plt-reloc.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1 // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t2 // RUN: ld.lld %t1 %t2 -o %t @@ -5,7 +6,6 @@ // RUN: ld.lld --hash-style=sysv -shared %t1 %t2 -o %t3 // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSO %s // RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s -// REQUIRES: arm // // Test PLT entry generation .syntax unified @@ -96,7 +96,7 @@ _start: // DSOREL-NEXT: AddressAlignment: 4 // DSOREL-NEXT: EntrySize: // DSOREL: Relocations [ -// DSOREL-NEXT: Section (4) .rel.plt { +// DSOREL-NEXT: Section {{.*}} .rel.plt { // DSOREL-NEXT: 0x200C R_ARM_JUMP_SLOT func1 0x0 // DSOREL-NEXT: 0x2010 R_ARM_JUMP_SLOT func2 0x0 // DSOREL-NEXT: 0x2014 R_ARM_JUMP_SLOT func3 0x0 @@ -162,7 +162,7 @@ _start: // DSORELHIGH-NEXT: ] // DSORELHIGH-NEXT: Address: 0x1100000 // DSORELHIGH: Relocations [ -// DSORELHIGH-NEXT: Section (6) .rel.plt { +// DSORELHIGH-NEXT: Section {{.*}} .rel.plt { // DSORELHIGH-NEXT: 0x110000C R_ARM_JUMP_SLOT func1 0x0 // DSORELHIGH-NEXT: 0x1100010 R_ARM_JUMP_SLOT func2 0x0 // DSORELHIGH-NEXT: 0x1100014 R_ARM_JUMP_SLOT func3 0x0 @@ -227,7 +227,7 @@ _start: // DSORELLONG-NEXT: ] // DSORELLONG-NEXT: Address: 0x11111100 // DSORELLONG: Relocations [ -// DSORELLONG-NEXT: Section (6) .rel.plt { +// DSORELLONG-NEXT: Section {{.*}} .rel.plt { // DSORELLONG-NEXT: 0x1111110C R_ARM_JUMP_SLOT func1 0x0 // DSORELLONG-NEXT: 0x11111110 R_ARM_JUMP_SLOT func2 0x0 // DSORELLONG-NEXT: 0x11111114 R_ARM_JUMP_SLOT func3 0x0 @@ -292,7 +292,7 @@ _start: // DSORELMIX-NEXT: SHF_WRITE // DSORELMIX-NEXT: ] // DSORELMIX-NEXT: Address: 0x8002020 -// DSORELMIX: Section (6) .rel.plt { +// DSORELMIX: Section {{.*}} .rel.plt { // DSORELMIX-NEXT: 0x800202C R_ARM_JUMP_SLOT func1 0x0 // DSORELMIX-NEXT: 0x8002030 R_ARM_JUMP_SLOT func2 0x0 // DSORELMIX-NEXT: 0x8002034 R_ARM_JUMP_SLOT func3 0x0 diff --git a/test/ELF/arm-sbrel32.s b/test/ELF/arm-sbrel32.s index 7f12717195a9..064f59bbd3fe 100644 --- a/test/ELF/arm-sbrel32.s +++ b/test/ELF/arm-sbrel32.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck %s -// REQUIRES: arm // Test the R_ARM_SBREL32 relocation which calculates the offset of the Symbol // from the static base. We define the static base to be the address of the diff --git a/test/ELF/arm-static-defines.s b/test/ELF/arm-static-defines.s index 815c20ca9451..4487ecdc2925 100644 --- a/test/ELF/arm-static-defines.s +++ b/test/ELF/arm-static-defines.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld --no-merge-exidx-entries %t --static -o %t2 2>&1 // RUN: llvm-readobj --symbols %t2 | FileCheck %s -// REQUIRES: arm // Check that on ARM we don't get a multiply defined symbol for __tls_get_addr // and undefined symbols for references to __exidx_start and __exidx_end diff --git a/test/ELF/arm-symbol-ordering-file.s b/test/ELF/arm-symbol-ordering-file.s new file mode 100644 index 000000000000..fe3de0d9d013 --- /dev/null +++ b/test/ELF/arm-symbol-ordering-file.s @@ -0,0 +1,32 @@ +# REQUIRES: arm +# RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux %s -o %t.o + +# RUN: echo ordered > %t_order.txt +# RUN: ld.lld --symbol-ordering-file %t_order.txt %t.o -o %t2.out +# RUN: llvm-nm -n %t2.out | FileCheck %s + +# CHECK: unordered1 +# CHECK-NEXT: unordered2 +# CHECK-NEXT: unordered3 +# CHECK-NEXT: ordered +# CHECK-NEXT: unordered4 + +.section .foo,"ax",%progbits,unique,1 +unordered1: +.zero 1 + +.section .foo,"ax",%progbits,unique,2 +unordered2: +.zero 1 + +.section .foo,"ax",%progbits,unique,3 +unordered3: +.zero 2 + +.section .foo,"ax",%progbits,unique,4 +unordered4: +.zero 4 + +.section .foo,"ax",%progbits,unique,5 +ordered: +.zero 1 diff --git a/test/ELF/arm-target1.s b/test/ELF/arm-target1.s index e77fa57bbf16..2fc0b8bc4281 100644 --- a/test/ELF/arm-target1.s +++ b/test/ELF/arm-target1.s @@ -31,6 +31,6 @@ // RELATIVE: SYMBOL TABLE: // RELATIVE: 00001004 .text 00000000 patatino -// ABS: can't create dynamic relocation R_ARM_TARGET1 against symbol: patatino +// ABS: can't create dynamic relocation R_ARM_TARGET1 against symbol: patatino in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // ABS: >>> defined in {{.*}}.o // ABS: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/arm-target2.s b/test/ELF/arm-target2.s index a678f7e08fdf..4dbcde88ec31 100644 --- a/test/ELF/arm-target2.s +++ b/test/ELF/arm-target2.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: ld.lld %t.o -o %t 2>&1 // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t | FileCheck %s @@ -7,7 +8,6 @@ // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t3 | FileCheck -check-prefix=CHECK-ABS %s // RUN: ld.lld %t.o --target2=rel -o %t4 2>&1 // RUN: llvm-objdump -s -triple=armv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-REL %s -// REQUIRES: arm // The R_ARM_TARGET2 is present in .ARM.extab sections. It can be handled as // either R_ARM_ABS32, R_ARM_REL32 or R_ARM_GOT_PREL. For ARM linux the default @@ -35,16 +35,16 @@ __gxx_personality_v0: _ZTIi: .word 0 // CHECK: Contents of section .ARM.extab: -// 1011c + 1ee4 = 12000 = .got -// CHECK-NEXT: 10114 f00e0000 b0b0b000 e41e0000 +// 0x1012c + 0x1ed4 = 0x12000 = .got +// CHECK-NEXT: 10124 e00e0000 b0b0b000 d41e0000 // CHECK-ABS: Contents of section .ARM.extab: -// 100f0 = .rodata -// CHECK-ABS-NEXT: 100d4 300f0000 b0b0b000 f0000100 +// 0x100f0 = .rodata +// CHECK-ABS-NEXT: 100e4 200f0000 b0b0b000 f0000100 // CHECK-REL: Contents of section .ARM.extab: -// 100dc + c = 100e8 = .rodata -// CHECK-REL-NEXT: 100d4 300f0000 b0b0b000 14000000 +// 0x100ec + 4 = 0x100f0 = .rodata +// CHECK-REL-NEXT: 100e4 200f0000 b0b0b000 04000000 // CHECK: Contents of section .rodata: // CHECK-NEXT: 10130 00000000 diff --git a/test/ELF/arm-thumb-blx.s b/test/ELF/arm-thumb-blx.s index d79bef1835e3..5316d13dbc28 100644 --- a/test/ELF/arm-thumb-blx.s +++ b/test/ELF/arm-thumb-blx.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/arm-thumb-blx-targets.s -o %ttarget // RUN: echo "SECTIONS { \ @@ -9,7 +10,6 @@ // RUN: ld.lld --script %t.script %t %ttarget -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM %s -// REQUIRES: arm // Test BLX instruction is chosen for Thumb BL/BLX instruction and ARM callee // 2 byte nops are used to test the pc-rounding behaviour. As a BLX from a // 2 byte aligned destination is defined as Align(PC,4) + immediate:00 diff --git a/test/ELF/arm-thumb-branch-rangethunk.s b/test/ELF/arm-thumb-branch-rangethunk.s index f83e64144d70..4bbd69214e93 100644 --- a/test/ELF/arm-thumb-branch-rangethunk.s +++ b/test/ELF/arm-thumb-branch-rangethunk.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar // RUN: ld.lld %t %tfar -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 -// REQUIRES: arm .syntax unified .thumb .section .text, "ax",%progbits diff --git a/test/ELF/arm-thumb-branch.s b/test/ELF/arm-thumb-branch.s index 81bf7a3c68a9..89c081a69b88 100644 --- a/test/ELF/arm-thumb-branch.s +++ b/test/ELF/arm-thumb-branch.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %S/Inputs/far-arm-thumb-abs.s -o %tfar // RUN: echo "SECTIONS { \ @@ -7,7 +8,6 @@ // RUN: .callee2 : { *(.callee_high) } } " > %t.script // RUN: ld.lld --script %t.script %t %tfar -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s -// REQUIRES: arm .syntax unified .thumb diff --git a/test/ELF/arm-thumb-condbranch-thunk.s b/test/ELF/arm-thumb-condbranch-thunk.s index c527e5df297c..c9365efb73a7 100644 --- a/test/ELF/arm-thumb-condbranch-thunk.s +++ b/test/ELF/arm-thumb-condbranch-thunk.s @@ -38,13 +38,9 @@ _start: // CHECK1-NEXT: 80000: 70 47 bx lr // CHECK1-NEXT: 80002: 7f f3 ff d7 bl #16252926 // CHECK1: __Thumbv7ABSLongThunk_tfunc05: -// CHECK1-NEXT: 80008: 40 f2 01 0c movw r12, #1 -// CHECK1-NEXT: 8000c: c0 f2 30 0c movt r12, #48 -// CHECK1-NEXT: 80010: 60 47 bx r12 +// CHECK1-NEXT: 80008: 7f f2 fa bf b.w #2621428 <tfunc05> // CHECK1: __Thumbv7ABSLongThunk_tfunc00: -// CHECK1-NEXT: 80012: 40 f2 01 0c movw r12, #1 -// CHECK1-NEXT: 80016: c0 f2 08 0c movt r12, #8 -// CHECK1-NEXT: 8001a: 60 47 bx r12 +// CHECK1-NEXT: 8000c: ff f7 f8 bf b.w #-16 <tfunc00> FUNCTION 01 // tfunc02 is within range of tfunc02 beq.w tfunc02 @@ -61,7 +57,7 @@ _start: beq.w tfunc00 // CHECK3: 180000: 70 47 bx lr // CHECK3-NEXT: 180002: 40 f4 01 80 bne.w #-1048574 <__Thumbv7ABSLongThunk_tfunc05> -// CHECK3-NEXT: 180006: 00 f4 04 80 beq.w #-1048568 <__Thumbv7ABSLongThunk_tfunc00> +// CHECK3-NEXT: 180006: 00 f4 01 80 beq.w #-1048574 <__Thumbv7ABSLongThunk_tfunc00> FUNCTION 03 FUNCTION 04 FUNCTION 05 @@ -70,9 +66,7 @@ _start: FUNCTION 08 FUNCTION 09 // CHECK4: __Thumbv7ABSLongThunk_tfunc03: -// CHECK4-NEXT: 500004: 40 f2 01 0c movw r12, #1 -// CHECK4-NEXT: 500008: c0 f2 20 0c movt r12, #32 -// CHECK4-NEXT: 50000c: 60 47 bx r12 +// CHECK4-NEXT: 500004: ff f4 fc bf b.w #-3145736 <tfunc03> FUNCTION 10 // We can't reach any Thunk Section, create a new one beq.w tfunc03 @@ -101,17 +95,13 @@ _start: FUNCTION 30 FUNCTION 31 // CHECK6: __Thumbv7ABSLongThunk_tfunc33: -// CHECK6-NEXT: 1000004: 40 f2 01 0c movw r12, #1 -// CHECK6-NEXT: 1000008: c0 f2 10 1c movt r12, #272 -// CHECK6-NEXT: 100000c: 60 47 bx r12 +// CHECK6-NEXT: 1000004: ff f0 fc bf b.w #1048568 <tfunc33> // CHECK6: __Thumbv7ABSLongThunk_tfunc00: -// CHECK6-NEXT: 100000e: 40 f2 01 0c movw r12, #1 -// CHECK6-NEXT: 1000012: c0 f2 08 0c movt r12, #8 -// CHECK6-NEXT: 1000016: 60 47 bx r12 +// CHECK6-NEXT: 1000008: 7f f4 fa 97 b.w #-16252940 <tfunc00> FUNCTION 32 FUNCTION 33 // We should be able to reach an existing ThunkSection. b.w tfunc00 // CHECK7: tfunc33: // CHECK7-NEXT: 1100000: 70 47 bx lr -// CHECK7-NEXT: 1100002: 00 f7 04 b8 b.w #-1048568 <__Thumbv7ABSLongThunk_tfunc00> +// CHECK7-NEXT: 1100002: 00 f7 01 b8 b.w #-1048574 <__Thumbv7ABSLongThunk_tfunc00> diff --git a/test/ELF/arm-thumb-interwork-shared.s b/test/ELF/arm-thumb-interwork-shared.s index cadcd451ad67..030ac29854b2 100644 --- a/test/ELF/arm-thumb-interwork-shared.s +++ b/test/ELF/arm-thumb-interwork-shared.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t --shared -o %t.so // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t.so | FileCheck %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t.so | FileCheck %s -check-prefix=PLT -// REQUIRES: arm .syntax unified .global sym1 .global elsewhere diff --git a/test/ELF/arm-thumb-interwork-thunk-range.s b/test/ELF/arm-thumb-interwork-thunk-range.s index db674f4d5f7c..d59ee1159920 100644 --- a/test/ELF/arm-thumb-interwork-thunk-range.s +++ b/test/ELF/arm-thumb-interwork-thunk-range.s @@ -1,6 +1,6 @@ // REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o -// RUN: ld.lld %t.o -o %t -image-base=0x80000000 +// RUN: ld.lld %t.o -o /dev/null -image-base=0x80000000 // Test that when the thunk is at a high address we don't get confused with it // being out of range. diff --git a/test/ELF/arm-thumb-interwork-thunk.s b/test/ELF/arm-thumb-interwork-thunk.s index 04755c4603cc..df5d6c6b7401 100644 --- a/test/ELF/arm-thumb-interwork-thunk.s +++ b/test/ELF/arm-thumb-interwork-thunk.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: echo "SECTIONS { \ // RUN: . = SIZEOF_HEADERS; \ @@ -8,7 +9,7 @@ // RUN: .thumb_caller : { *(.thumb_caller) } \ // RUN: .R_ARM_JUMP24_callee_2 : { *(.R_ARM_JUMP24_callee_high) } \ // RUN: .R_ARM_THM_JUMP_callee_2 : { *(.R_ARM_THM_JUMP_callee_high) } \ -// RUN: .got.plt 0x1894 : { } } " > %t.script +// RUN: .got.plt 0x18b4 : { } } " > %t.script // RUN: ld.lld --script %t.script %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-ABS-THUMB %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t2 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-ABS-ARM %s @@ -19,7 +20,6 @@ // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-THUMB -check-prefix=CHECK-PI-PLT-THUMB %s // RUN: llvm-objdump -d -triple=armv7a-none-linux-gnueabi %t4 | FileCheck -check-prefix=CHECK-ARM -check-prefix=CHECK-PI-PLT-ARM %s // RUN: llvm-readobj -s -r %t4 | FileCheck -check-prefix=CHECK-DSO-REL %s -// REQUIRES: arm // Test ARM Thumb Interworking // The file is linked and checked 3 times to check the following contexts @@ -368,11 +368,11 @@ _start: // CHECK-PI-ARM-PLT-NEXT: 183c: 00 f0 9c e5 ldr pc, [r12] // CHECK-PI-ARM-PLT-NEXT: 1840: 7c 00 00 00 -// CHECK-DSO-REL: 0x18A0 R_ARM_JUMP_SLOT arm_caller -// CHECK-DSO-REL-NEXT: 0x18A4 R_ARM_JUMP_SLOT thumb_caller -// CHECK-DSO-REL-NEXT: 0x18A8 R_ARM_JUMP_SLOT thumb_callee1 -// CHECK-DSO-REL-NEXT: 0x18AC R_ARM_JUMP_SLOT thumb_callee2 -// CHECK-DSO-REL-NEXT: 0x18B0 R_ARM_JUMP_SLOT thumb_callee3 -// CHECK-DSO-REL-NEXT: 0x18B4 R_ARM_JUMP_SLOT arm_callee1 -// CHECK-DSO-REL-NEXT: 0x18B8 R_ARM_JUMP_SLOT arm_callee2 -// CHECK-DSO-REL-NEXT: 0x18BC R_ARM_JUMP_SLOT arm_callee3 +// CHECK-DSO-REL: 0x18C0 R_ARM_JUMP_SLOT arm_caller +// CHECK-DSO-REL-NEXT: 0x18C4 R_ARM_JUMP_SLOT thumb_caller +// CHECK-DSO-REL-NEXT: 0x18C8 R_ARM_JUMP_SLOT thumb_callee1 +// CHECK-DSO-REL-NEXT: 0x18CC R_ARM_JUMP_SLOT thumb_callee2 +// CHECK-DSO-REL-NEXT: 0x18D0 R_ARM_JUMP_SLOT thumb_callee3 +// CHECK-DSO-REL-NEXT: 0x18D4 R_ARM_JUMP_SLOT arm_callee1 +// CHECK-DSO-REL-NEXT: 0x18D8 R_ARM_JUMP_SLOT arm_callee2 +// CHECK-DSO-REL-NEXT: 0x18DC R_ARM_JUMP_SLOT arm_callee3 diff --git a/test/ELF/arm-thumb-mix-range-thunk-os.s b/test/ELF/arm-thumb-mix-range-thunk-os.s index beff4148b6ff..b5db2565f2c9 100644 --- a/test/ELF/arm-thumb-mix-range-thunk-os.s +++ b/test/ELF/arm-thumb-mix-range-thunk-os.s @@ -11,7 +11,7 @@ // RUN: llvm-objdump -d %t2 -start-address=35651584 -stop-address=35651590 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK6 %s // RUN: llvm-objdump -d %t2 -start-address=36700160 -stop-address=36700168 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s // RUN: llvm-objdump -d %t2 -start-address=48234500 -stop-address=48234512 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s -// RUN: llvm-objdump -d %t2 -start-address=63963140 -stop-address=63963160 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s +// RUN: llvm-objdump -d %t2 -start-address=53477380 -stop-address=53477392 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s // RUN: llvm-objdump -d %t2 -start-address=68157440 -stop-address=68157452 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK10 %s // RUN: llvm-objdump -d %t2 -start-address=69206016 -stop-address=69206024 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK11 %s @@ -155,6 +155,13 @@ _start: ARMFUNCTION 48 THUMBFUNCTION 49 ARMFUNCTION 50 +// Expect precreated Thunk Section here +// CHECK9: __Thumbv7ABSLongThunk_afunc34: +// CHECK9-NEXT: 3300004: 40 f2 00 0c movw r12, #0 +// CHECK9-NEXT: 3300008: c0 f2 30 2c movt r12, #560 +// CHECK9-NEXT: 330000c: 60 47 bx r12 +// CHECK9: __Thumbv7ABSLongThunk_tfunc35: +// CHECK9-NEXT: 330000e: ff f4 f7 97 b.w #-15728658 <tfunc35> THUMBFUNCTION 51 ARMFUNCTION 52 THUMBFUNCTION 53 @@ -165,15 +172,6 @@ _start: ARMFUNCTION 58 THUMBFUNCTION 59 ARMFUNCTION 60 -// Expect precreated Thunk Section here -// CHECK9: __Thumbv7ABSLongThunk_afunc34: -// CHECK9-NEXT: 3d00004: 40 f2 00 0c movw r12, #0 -// CHECK9-NEXT: 3d00008: c0 f2 30 2c movt r12, #560 -// CHECK9-NEXT: 3d0000c: 60 47 bx r12 -// CHECK9: __Thumbv7ABSLongThunk_tfunc35: -// CHECK9-NEXT: 3d0000e: 40 f2 01 0c movw r12, #1 -// CHECK9-NEXT: 3d00012: c0 f2 40 2c movt r12, #576 -// CHECK9-NEXT: 3d00016: 60 47 bx r12 THUMBFUNCTION 61 ARMFUNCTION 62 THUMBFUNCTION 63 @@ -191,5 +189,5 @@ _start: bl tfunc35 // CHECK11: tfunc65: // CHECK11: 4200000: 70 47 bx lr -// CHECK11-NEXT: 4200002: ff f6 ff f7 bl #-5242882 -// CHECK11-NEXT: 4200006: 00 f7 02 f0 bl #-5242876 +// CHECK11-NEXT: 4200002: ff f4 ff d7 bl #-15728642 +// CHECK11-NEXT: 4200006: 00 f5 02 d0 bl #-15728636 diff --git a/test/ELF/arm-thumb-narrow-branch-check.s b/test/ELF/arm-thumb-narrow-branch-check.s index 82a7164f6df6..27bac59787e1 100644 --- a/test/ELF/arm-thumb-narrow-branch-check.s +++ b/test/ELF/arm-thumb-narrow-branch-check.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: echo "SECTIONS { \ // RUN: . = SIZEOF_HEADERS; \ @@ -7,7 +8,6 @@ // RUN: .text : { *(.text) } } " > %t.script // RUN: ld.lld --script %t.script %t %S/Inputs/arm-thumb-narrow-branch.o -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s -// REQUIRES: arm // Test the R_ARM_PC11 relocation which is used with the narrow encoding of B.N // the source of these relocations is a binary file arm-thumb-narrow-branch.o diff --git a/test/ELF/arm-thumb-no-undefined-thunk.s b/test/ELF/arm-thumb-no-undefined-thunk.s index e8d8d8db684c..5456e7639498 100644 --- a/test/ELF/arm-thumb-no-undefined-thunk.s +++ b/test/ELF/arm-thumb-no-undefined-thunk.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s -// REQUIRES: arm // Check that no thunks are created for an undefined weak symbol .syntax unified diff --git a/test/ELF/arm-thumb-plt-range-thunk-os.s b/test/ELF/arm-thumb-plt-range-thunk-os.s index f412faa98eca..080160bb2474 100644 --- a/test/ELF/arm-thumb-plt-range-thunk-os.s +++ b/test/ELF/arm-thumb-plt-range-thunk-os.s @@ -1,12 +1,12 @@ // REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t -// RUN: ld.lld %t --shared -o %t.so +// RUN: ld.lld %t --shared --icf=all -o %t.so // The output file is large, most of it zeroes. We dissassemble only the // parts we need to speed up the test and avoid a large output file -// RUN: llvm-objdump -d %t.so -start-address=8388608 -stop-address=8388624 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s -// RUN: llvm-objdump -d %t.so -start-address=16777216 -stop-address=16777256 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s -// RUN: llvm-objdump -d %t.so -start-address=25165824 -stop-address=25165828 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s -// RUN: llvm-objdump -d %t.so -start-address=25165828 -stop-address=25165924 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s +// RUN: llvm-objdump -d %t.so -start-address=0x2000000 -stop-address=0x2000018 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s +// RUN: llvm-objdump -d %t.so -start-address=0x2800004 -stop-address=0x2800034 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s +// RUN: llvm-objdump -d %t.so -start-address=0x4000000 -stop-address=0x4000010 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s +// RUN: llvm-objdump -d %t.so -start-address=0x4000010 -stop-address=0x4000100 -triple=armv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s .syntax unified .thumb @@ -19,74 +19,96 @@ .type preemptible, %function .global far_preemptible .type far_preemptible, %function + .global far_nonpreemptible + .hidden far_nonpreemptible + .type far_nonpreemptible, %function + .global far_nonpreemptible_alias + .hidden far_nonpreemptible_alias + .type far_nonpreemptible_alias, %function sym1: bl elsewhere bl preemptible bx lr preemptible: bl far_preemptible + bl far_nonpreemptible + bl far_nonpreemptible_alias bx lr // CHECK1: Disassembly of section .text: // CHECK1-NEXT: sym1: -// CHECK1-NEXT: 800000: 00 f0 00 d8 bl #8388608 -// CHECK1-NEXT: 800004: 00 f0 04 d8 bl #8388616 -// CHECK1-NEXT: 800008: 70 47 bx lr +// CHECK1-NEXT: 2000000: 00 f0 00 d8 bl #8388608 +// CHECK1-NEXT: 2000004: 00 f0 04 d8 bl #8388616 +// CHECK1-NEXT: 2000008: 70 47 bx lr // CHECK1: preemptible: -// CHECK1-NEXT: 80000a: 00 f0 07 d8 bl #8388622 -// CHECK1-NEXT: 80000e: 70 47 bx lr +// CHECK1-NEXT: 200000a: 00 f0 07 d8 bl #8388622 +// CHECK1-NEXT: 200000e: 00 f0 0b d8 bl #8388630 +// CHECK1-NEXT: 2000012: 00 f0 09 d8 bl #8388626 +// CHECK1-NEXT: 2000016: 70 47 bx lr .section .text.2, "ax", %progbits .balign 0x0800000 bx lr // CHECK2: __ThumbV7PILongThunk_elsewhere: -// CHECK2-NEXT: 1000004: 40 f2 20 0c movw r12, #32 -// CHECK2-NEXT: 1000008: c0 f2 80 0c movt r12, #128 -// CHECK2-NEXT: 100000c: fc 44 add r12, pc -// CHECK2-NEXT: 100000e: 60 47 bx r12 +// CHECK2-NEXT: 2800004: 40 f2 20 0c movw r12, #32 +// CHECK2-NEXT: 2800008: c0 f2 80 1c movt r12, #384 +// CHECK2-NEXT: 280000c: fc 44 add r12, pc +// CHECK2-NEXT: 280000e: 60 47 bx r12 // CHECK2: __ThumbV7PILongThunk_preemptible: -// CHECK2-NEXT: 1000010: 40 f2 24 0c movw r12, #36 -// CHECK2-NEXT: 1000014: c0 f2 80 0c movt r12, #128 -// CHECK2-NEXT: 1000018: fc 44 add r12, pc -// CHECK2-NEXT: 100001a: 60 47 bx r12 +// CHECK2-NEXT: 2800010: 40 f2 24 0c movw r12, #36 +// CHECK2-NEXT: 2800014: c0 f2 80 1c movt r12, #384 +// CHECK2-NEXT: 2800018: fc 44 add r12, pc +// CHECK2-NEXT: 280001a: 60 47 bx r12 // CHECK2: __ThumbV7PILongThunk_far_preemptible: -// CHECK2-NEXT: 100001c: 40 f2 28 0c movw r12, #40 -// CHECK2-NEXT: 1000020: c0 f2 80 0c movt r12, #128 -// CHECK2-NEXT: 1000024: fc 44 add r12, pc -// CHECK2-NEXT: 1000026: 60 47 bx r12 +// CHECK2-NEXT: 280001c: 40 f2 28 0c movw r12, #40 +// CHECK2-NEXT: 2800020: c0 f2 80 1c movt r12, #384 +// CHECK2-NEXT: 2800024: fc 44 add r12, pc +// CHECK2-NEXT: 2800026: 60 47 bx r12 +// CHECK2: __ThumbV7PILongThunk_far_nonpreemptible: +// CHECK2-NEXT: 2800028: 4f f6 cd 7c movw r12, #65485 +// CHECK2-NEXT: 280002c: c0 f2 7f 1c movt r12, #383 +// CHECK2-NEXT: 2800030: fc 44 add r12, pc +// CHECK2-NEXT: 2800032: 60 47 bx r12 .section .text.3, "ax", %progbits -.balign 0x0800000 +.balign 0x2000000 far_preemptible: +far_nonpreemptible: bl elsewhere + + .section .text.4, "ax", %progbits +.balign 0x2000000 +far_nonpreemptible_alias: + bl elsewhere + // CHECK3: far_preemptible: -// CHECK3: 1800000: 00 f0 16 e8 blx #44 +// CHECK3: 4000000: 00 f0 16 e8 blx #44 // CHECK4: Disassembly of section .plt: // CHECK4-NEXT: $a: -// CHECK4-NEXT: 1800010: 04 e0 2d e5 str lr, [sp, #-4]! -// CHECK4-NEXT: 1800014: 00 e6 8f e2 add lr, pc, #0, #12 -// CHECK4-NEXT: 1800018: 00 ea 8e e2 add lr, lr, #0, #20 -// CHECK4-NEXT: 180001c: ec ff be e5 ldr pc, [lr, #4076]! +// CHECK4-NEXT: 4000010: 04 e0 2d e5 str lr, [sp, #-4]! +// CHECK4-NEXT: 4000014: 00 e6 8f e2 add lr, pc, #0, #12 +// CHECK4-NEXT: 4000018: 00 ea 8e e2 add lr, lr, #0, #20 +// CHECK4-NEXT: 400001c: ec ff be e5 ldr pc, [lr, #4076]! // CHECK4: $d: -// CHECK4-NEXT: 1800020: d4 d4 d4 d4 .word 0xd4d4d4d4 -// CHECK4-NEXT: 1800024: d4 d4 d4 d4 .word 0xd4d4d4d4 -// CHECK4-NEXT: 1800028: d4 d4 d4 d4 .word 0xd4d4d4d4 -// CHECK4-NEXT: 180002c: d4 d4 d4 d4 .word 0xd4d4d4d4 +// CHECK4-NEXT: 4000020: d4 d4 d4 d4 .word 0xd4d4d4d4 +// CHECK4-NEXT: 4000024: d4 d4 d4 d4 .word 0xd4d4d4d4 +// CHECK4-NEXT: 4000028: d4 d4 d4 d4 .word 0xd4d4d4d4 +// CHECK4-NEXT: 400002c: d4 d4 d4 d4 .word 0xd4d4d4d4 // CHECK4: $a: -// CHECK4-NEXT: 1800030: 00 c6 8f e2 add r12, pc, #0, #12 -// CHECK4-NEXT: 1800034: 00 ca 8c e2 add r12, r12, #0, #20 -// CHECK4-NEXT: 1800038: d4 ff bc e5 ldr pc, [r12, #4052]! +// CHECK4-NEXT: 4000030: 00 c6 8f e2 add r12, pc, #0, #12 +// CHECK4-NEXT: 4000034: 00 ca 8c e2 add r12, r12, #0, #20 +// CHECK4-NEXT: 4000038: d4 ff bc e5 ldr pc, [r12, #4052]! // CHECK4: $d: -// CHECK4-NEXT: 180003c: d4 d4 d4 d4 .word 0xd4d4d4d4 +// CHECK4-NEXT: 400003c: d4 d4 d4 d4 .word 0xd4d4d4d4 // CHECK4: $a: -// CHECK4-NEXT: 1800040: 00 c6 8f e2 add r12, pc, #0, #12 -// CHECK4-NEXT: 1800044: 00 ca 8c e2 add r12, r12, #0, #20 -// CHECK4-NEXT: 1800048: c8 ff bc e5 ldr pc, [r12, #4040]! +// CHECK4-NEXT: 4000040: 00 c6 8f e2 add r12, pc, #0, #12 +// CHECK4-NEXT: 4000044: 00 ca 8c e2 add r12, r12, #0, #20 +// CHECK4-NEXT: 4000048: c8 ff bc e5 ldr pc, [r12, #4040]! // CHECK4: $d: -// CHECK4-NEXT: 180004c: d4 d4 d4 d4 .word 0xd4d4d4d4 +// CHECK4-NEXT: 400004c: d4 d4 d4 d4 .word 0xd4d4d4d4 // CHECK4: $a: -// CHECK4-NEXT: 1800050: 00 c6 8f e2 add r12, pc, #0, #12 -// CHECK4-NEXT: 1800054: 00 ca 8c e2 add r12, r12, #0, #20 -// CHECK4-NEXT: 1800058: bc ff bc e5 ldr pc, [r12, #4028]! +// CHECK4-NEXT: 4000050: 00 c6 8f e2 add r12, pc, #0, #12 +// CHECK4-NEXT: 4000054: 00 ca 8c e2 add r12, r12, #0, #20 +// CHECK4-NEXT: 4000058: bc ff bc e5 ldr pc, [r12, #4028]! // CHECK4: $d: -// CHECK4-NEXT: 180005c: d4 d4 d4 d4 .word 0xd4d4d4d4 +// CHECK4-NEXT: 400005c: d4 d4 d4 d4 .word 0xd4d4d4d4 diff --git a/test/ELF/arm-thumb-plt-reloc.s b/test/ELF/arm-thumb-plt-reloc.s index dd8770edc3c1..742e95994fff 100644 --- a/test/ELF/arm-thumb-plt-reloc.s +++ b/test/ELF/arm-thumb-plt-reloc.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %p/Inputs/arm-plt-reloc.s -o %t1 // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t2 // RUN: ld.lld %t1 %t2 -o %t @@ -6,7 +7,6 @@ // RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOTHUMB %s // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t3 | FileCheck -check-prefix=DSOARM %s // RUN: llvm-readobj -s -r %t3 | FileCheck -check-prefix=DSOREL %s -// REQUIRES: arm // // Test PLT entry generation .syntax unified diff --git a/test/ELF/arm-thumb-range-thunk-os.s b/test/ELF/arm-thumb-range-thunk-os.s index 588539ddab8c..182b18d79cae 100644 --- a/test/ELF/arm-thumb-range-thunk-os.s +++ b/test/ELF/arm-thumb-range-thunk-os.s @@ -9,8 +9,8 @@ // RUN: llvm-objdump -d %t2 -start-address=4194304 -stop-address=4194310 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK4 %s // RUN: llvm-objdump -d %t2 -start-address=16777216 -stop-address=16777270 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK5 %s // RUN: llvm-objdump -d %t2 -start-address=17825792 -stop-address=17825808 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK6 %s -// RUN: llvm-objdump -d %t2 -start-address=31457280 -stop-address=31457286 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s -// RUN: llvm-objdump -d %t2 -start-address=32505860 -stop-address=32505880 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s +// RUN: llvm-objdump -d %t2 -start-address=20971524 -stop-address=20971532 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK7 %s +// RUN: llvm-objdump -d %t2 -start-address=31457280 -stop-address=31457286 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK8 %s // RUN: llvm-objdump -d %t2 -start-address=35651584 -stop-address=35651594 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK9 %s // RUN: llvm-objdump -d %t2 -start-address=36700160 -stop-address=36700170 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK10 %s @@ -60,7 +60,7 @@ _start: b.w tfunc28 // CHECK4: tfunc02: // CHECK4-NEXT: 400000: 70 47 bx lr -// CHECK4-NEXT: 400002: 00 f0 04 90 b.w #12582920 <__Thumbv7ABSLongThunk_tfunc28> +// CHECK4-NEXT: 400002: 00 f0 01 90 b.w #12582914 <__Thumbv7ABSLongThunk_tfunc28> FUNCTION 03 FUNCTION 04 FUNCTION 05 @@ -75,25 +75,19 @@ _start: FUNCTION 14 // Expect precreated ThunkSection here // CHECK5: __Thumbv7ABSLongThunk_tfunc16: -// CHECK5-NEXT: 1000004: 40 f2 01 0c movw r12, #1 -// CHECK5-NEXT: 1000008: c0 f2 20 1c movt r12, #288 -// CHECK5-NEXT: 100000c: 60 47 bx r12 +// CHECK5-NEXT: 1000004: ff f1 fc bf b.w #2097144 <tfunc16> // CHECK5: __Thumbv7ABSLongThunk_tfunc28: -// CHECK5-NEXT: 100000e: 40 f2 01 0c movw r12, #1 -// CHECK5-NEXT: 1000012: c0 f2 e0 1c movt r12, #480 -// CHECK5-NEXT: 1000016: 60 47 bx r12 +// CHECK5-NEXT: 1000008: ff f1 fa 97 b.w #14680052 <tfunc28> // CHECK5: __Thumbv7ABSLongThunk_tfunc32: -// CHECK5-NEXT: 1000018: 40 f2 01 0c movw r12, #1 -// CHECK5-NEXT: 100001c: c0 f2 20 2c movt r12, #544 -// CHECK5-NEXT: 1000020: 60 47 bx r12 +// CHECK5-NEXT: 100000c: 40 f2 01 0c movw r12, #1 +// CHECK5-NEXT: 1000010: c0 f2 20 2c movt r12, #544 +// CHECK5-NEXT: 1000014: 60 47 bx r12 // CHECK5: __Thumbv7ABSLongThunk_tfunc33: -// CHECK5-NEXT: 1000022: 40 f2 01 0c movw r12, #1 -// CHECK5-NEXT: 1000026: c0 f2 30 2c movt r12, #560 -// CHECK5-NEXT: 100002a: 60 47 bx r12 +// CHECK5-NEXT: 1000016: 40 f2 01 0c movw r12, #1 +// CHECK5-NEXT: 100001a: c0 f2 30 2c movt r12, #560 +// CHECK5-NEXT: 100001e: 60 47 bx r12 // CHECK5: __Thumbv7ABSLongThunk_tfunc02: -// CHECK5-NEXT: 100002c: 40 f2 01 0c movw r12, #1 -// CHECK5-NEXT: 1000030: c0 f2 40 0c movt r12, #64 -// CHECK5-NEXT: 1000034: 60 47 bx r12 +// CHECK5-NEXT: 1000020: ff f7 ee 97 b.w #-12582948 <tfunc02> FUNCTION 15 // tfunc00 and tfunc01 are < 16Mb away, expect no range extension thunks bl tfunc00 @@ -106,11 +100,16 @@ _start: // CHECK6-NEXT: 1100000: 70 47 bx lr // CHECK6-NEXT: 1100002: ff f4 fd d7 bl #-15728646 // CHECK6-NEXT: 1100006: ff f5 fb d7 bl #-14680074 -// CHECK6-NEXT: 110000a: 00 f7 05 f8 bl #-1048566 -// CHECK6-NEXT: 110000e: 00 f7 08 f8 bl #-1048560 +// CHECK6-NEXT: 110000a: ff f6 ff ff bl #-1048578 +// CHECK6-NEXT: 110000e: 00 f7 02 f8 bl #-1048572 FUNCTION 16 FUNCTION 17 FUNCTION 18 +// Expect another precreated thunk section here +// CHECK7: __Thumbv7ABSLongThunk_tfunc15: +// CHECK7-NEXT: 1400004: ff f4 fc bf b.w #-3145736 <tfunc15> +// CHECK7: __Thumbv7ABSLongThunk_tfunc16: +// CHECK7-NEXT: 1400008: ff f5 fa bf b.w #-2097164 <tfunc16> FUNCTION 19 FUNCTION 20 FUNCTION 21 @@ -123,21 +122,12 @@ _start: FUNCTION 28 // tfunc02 is > 16Mb away, expect range extension thunks in precreated thunk // section -// CHECK7: tfunc28: -// CHECK7-NEXT: 1e00000: 70 47 bx lr -// CHECK7-NEXT: 1e00002: 00 f6 13 90 b.w #-14680026 <__Thumbv7ABSLongThunk_tfunc02> +// CHECK8: tfunc28: +// CHECK8-NEXT: 1e00000: 70 47 bx lr +// CHECK8-NEXT: 1e00002: 00 f6 0d 90 b.w #-14680038 <__Thumbv7ABSLongThunk_tfunc02> b.w tfunc02 FUNCTION 29 -// Expect another precreated thunk section here -// CHECK8: __Thumbv7ABSLongThunk_tfunc15: -// CHECK8-NEXT: 1f00004: 40 f2 01 0c movw r12, #1 -// CHECK8-NEXT: 1f00008: c0 f2 10 1c movt r12, #272 -// CHECK8-NEXT: 1f0000c: 60 47 bx r12 -// CHECK8: __Thumbv7ABSLongThunk_tfunc16: -// CHECK8-NEXT: 1f0000e: 40 f2 01 0c movw r12, #1 -// CHECK8-NEXT: 1f00012: c0 f2 20 1c movt r12, #288 -// CHECK8-NEXT: 1f00016: 60 47 bx r12 FUNCTION 30 FUNCTION 31 FUNCTION 32 @@ -147,13 +137,13 @@ _start: bl tfunc16 // CHECK9: tfunc32: // CHECK9: 2200000: 70 47 bx lr -// CHECK9-NEXT: 2200002: ff f4 ff ff bl #-3145730 -// CHECK9-NEXT: 2200006: 00 f5 02 f8 bl #-3145724 +// CHECK9-NEXT: 2200002: ff f5 ff d7 bl #-14680066 +// CHECK9-NEXT: 2200006: ff f5 ff d7 bl #-14680066 FUNCTION 33 bl tfunc15 bl tfunc16 // CHECK10: tfunc33: // CHECK10: 2300000: 70 47 bx lr -// CHECK10-NEXT: 2300002: ff f7 ff f7 bl #-4194306 -// CHECK10-NEXT: 2300006: 00 f4 02 f8 bl #-4194300 +// CHECK10-NEXT: 2300002: ff f4 ff d7 bl #-15728642 +// CHECK10-NEXT: 2300006: ff f4 ff d7 bl #-15728642 diff --git a/test/ELF/arm-thumb-thunk-empty-pass.s b/test/ELF/arm-thumb-thunk-empty-pass.s index 9ff6ed6a7807..ab9da1b8a2c2 100644 --- a/test/ELF/arm-thumb-thunk-empty-pass.s +++ b/test/ELF/arm-thumb-thunk-empty-pass.s @@ -2,7 +2,7 @@ // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -d %t2 -start-address=69632 -stop-address=69646 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s -// RUN: llvm-objdump -d %t2 -start-address=16846860 -stop-address=16846874 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s +// RUN: llvm-objdump -d %t2 -start-address=16846856 -stop-address=16846874 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s .syntax unified .global _start, foo .type _start, %function @@ -20,13 +20,11 @@ foo: // CHECK1-NEXT: _start: // CHECK1-NEXT: 11000: ff f7 fe ff bl #-4 // CHECK1: __Thumbv7ABSLongThunk__start: -// CHECK1-NEXT: 11004: 41 f2 01 0c movw r12, #4097 -// CHECK1-NEXT: 11008: c0 f2 01 0c movt r12, #1 -// CHECK1-NEXT: 1100c: 60 47 bx r12 +// CHECK1-NEXT: 11004: ff f7 fc bf b.w #-8 <_start> // CHECK2: __Thumbv7ABSLongThunk__start: -// CHECK2: 101100c: 41 f2 01 0c movw r12, #4097 -// CHECK2-NEXT: 1011010: c0 f2 01 0c movt r12, #1 -// CHECK2-NEXT: 1011014: 60 47 bx r12 +// CHECK2: 1011008: 41 f2 01 0c movw r12, #4097 +// CHECK2-NEXT: 101100c: c0 f2 01 0c movt r12, #1 +// CHECK2-NEXT: 1011010: 60 47 bx r12 // CHECK2: foo: -// CHECK2-NEXT: 1011016: ff f7 f9 ff bl #-14 +// CHECK2-NEXT: 1011012: ff f7 f9 ff bl #-14 diff --git a/test/ELF/arm-thumb-thunk-symbols.s b/test/ELF/arm-thumb-thunk-symbols.s index faa39fec0218..457d460997aa 100644 --- a/test/ELF/arm-thumb-thunk-symbols.s +++ b/test/ELF/arm-thumb-thunk-symbols.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-readobj --symbols %t2 | FileCheck %s // RUN: ld.lld --shared %t -o %t3 2>&1 // RUN: llvm-readobj --symbols %t3 | FileCheck -check-prefix=CHECK-PI %s -// REQUIRES: arm // Check that the symbols generated for Thunks have the correct symbol type // of STT_FUNC and the correct value of bit 0 (0 for ARM 1 for Thumb) diff --git a/test/ELF/arm-thumb-undefined-weak.s b/test/ELF/arm-thumb-undefined-weak.s index 7f481b0ddb89..d973c58f16d8 100644 --- a/test/ELF/arm-thumb-undefined-weak.s +++ b/test/ELF/arm-thumb-undefined-weak.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -triple=thumbv7a-none-linux-gnueabi -d %t2 | FileCheck %s -// REQUIRES: arm // Check that the ARM ABI rules for undefined weak symbols are applied. // Branch instructions are resolved to the next instruction. Relative diff --git a/test/ELF/arm-thunk-largesection.s b/test/ELF/arm-thunk-largesection.s index 950f789764a6..d68cd0c76141 100644 --- a/test/ELF/arm-thunk-largesection.s +++ b/test/ELF/arm-thunk-largesection.s @@ -1,11 +1,11 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=69632 -stop-address=69636 %t2 | FileCheck -check-prefix=CHECK1 %s // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=73732 -stop-address=73742 %t2 | FileCheck -check-prefix=CHECK2 %s -// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=16850944 -stop-address=16850948 %t2 | FileCheck -check-prefix=CHECK3 %s -// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=33628160 -stop-address=33628164 %t2 | FileCheck -check-prefix=CHECK4 %s -// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=50405364 -stop-address=50405376 %t2 | FileCheck -check-prefix=CHECK5 %s -// REQUIRES: arm +// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=16850936 -stop-address=16850940 %t2 | FileCheck -check-prefix=CHECK3 %s +// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=33628152 -stop-address=33628156 %t2 | FileCheck -check-prefix=CHECK4 %s +// RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi -start-address=50405356 -stop-address=50405376 %t2 | FileCheck -check-prefix=CHECK5 %s .syntax unified .balign 0x1000 .thumb @@ -21,9 +21,7 @@ _start: // CHECK1-NEXT: 11002: 00 00 movs r0, r0 // CHECK2: __Thumbv7ABSLongThunk__start: -// CHECK2-NEXT: 12004: 41 f2 01 0c movw r12, #4097 -// CHECK2-NEXT: 12008: c0 f2 01 0c movt r12, #1 -// CHECK2-NEXT: 1200c: 60 47 bx r12 +// CHECK2-NEXT: 12004: fe f7 fc bf b.w #-4104 <_start> // Gigantic section where we need a ThunkSection either side of it .section .text.large1, "ax", %progbits @@ -33,10 +31,10 @@ _start: .space (16 * 1024 * 1024) - 4 bl _start .space (16 * 1024 * 1024) - 16 -// CHECK3: 1012000: 00 f4 00 d0 bl #-16777216 -// CHECK4: 2012000: ff f3 f8 d7 bl #16777200 +// CHECK3: 1011ff8: 00 f4 04 d0 bl #-16777208 +// CHECK4: 2011ff8: ff f3 f8 d7 bl #16777200 // CHECK5: __Thumbv7ABSLongThunk__start: -// CHECK5-NEXT: 3011ff4: 41 f2 01 0c movw r12, #4097 -// CHECK5-NEXT: 3011ff8: c0 f2 01 0c movt r12, #1 -// CHECK5-NEXT: 3011ffc: 60 47 bx r12 +// CHECK5-NEXT: 3011fec: 41 f2 01 0c movw r12, #4097 +// CHECK5-NEXT: 3011ff0: c0 f2 01 0c movt r12, #1 +// CHECK5-NEXT: 3011ff4: 60 47 bx r12 diff --git a/test/ELF/arm-thunk-linkerscript-dotexpr.s b/test/ELF/arm-thunk-linkerscript-dotexpr.s index bd0e9a293102..ea741708bc90 100644 --- a/test/ELF/arm-thunk-linkerscript-dotexpr.s +++ b/test/ELF/arm-thunk-linkerscript-dotexpr.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: echo "SECTIONS { \ // RUN: . = SIZEOF_HEADERS; \ @@ -6,7 +7,6 @@ // RUN: ld.lld --script %t.script %t -o %t2 2>&1 // RUN: llvm-objdump -d %t2 -start-address=148 -stop-address=188 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s // RUN: llvm-objdump -d %t2 -start-address=33554620 -stop-address=33554654 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s -// REQUIRES: arm // Test that range extension thunks can handle location expressions within // a Section Description .syntax unified diff --git a/test/ELF/arm-thunk-linkerscript-large.s b/test/ELF/arm-thunk-linkerscript-large.s index 07cd1dd87976..839d7716c278 100644 --- a/test/ELF/arm-thunk-linkerscript-large.s +++ b/test/ELF/arm-thunk-linkerscript-large.s @@ -79,9 +79,7 @@ _start: FUNCTIONL 08 FUNCTIONL 09 // CHECK3: __Thumbv7ABSLongThunk_tfuncl24: -// CHECK3-NEXT: b00004: 40 f2 01 0c movw r12, #1 -// CHECK3-NEXT: b00008: c0 f2 a0 1c movt r12, #416 -// CHECK3-NEXT: b0000c: 60 47 bx r12 +// CHECK3-NEXT: b00004: ff f2 fc 97 b.w #15728632 <tfuncl24> FUNCTIONL 10 FUNCTIONL 11 FUNCTIONL 12 diff --git a/test/ELF/arm-thunk-linkerscript-sort.s b/test/ELF/arm-thunk-linkerscript-sort.s index 69d176765780..62ea41363f41 100644 --- a/test/ELF/arm-thunk-linkerscript-sort.s +++ b/test/ELF/arm-thunk-linkerscript-sort.s @@ -41,9 +41,7 @@ tfunc\suff\(): FUNCTION 16 FUNCTION 15 // CHECK2: __Thumbv7ABSLongThunk_tfunc31: -// CHECK2-NEXT: 1000004: 40 f2 01 0c movw r12, #1 -// CHECK2-NEXT: 1000008: c0 f2 00 2c movt r12, #512 -// CHECK2-NEXT: 100000c: 60 47 bx r12 +// CHECK2-NEXT: 1000004: ff f3 fc 97 b.w #16777208 <tfunc31> FUNCTION 14 FUNCTION 13 FUNCTION 12 diff --git a/test/ELF/arm-thunk-linkerscript.s b/test/ELF/arm-thunk-linkerscript.s index 9aaa29237cbe..7728ddf76a97 100644 --- a/test/ELF/arm-thunk-linkerscript.s +++ b/test/ELF/arm-thunk-linkerscript.s @@ -1,3 +1,4 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: echo "SECTIONS { \ // RUN: . = SIZEOF_HEADERS; \ @@ -6,7 +7,6 @@ // RUN: } " > %t.script // RUN: ld.lld --script %t.script %t -o %t2 2>&1 // RUN: llvm-objdump -d -triple=thumbv7a-none-linux-gnueabi %t2 | FileCheck %s -// REQUIRES: arm // Simple test that we can support range extension thunks with linker scripts .syntax unified .section .text_low, "ax", %progbits diff --git a/test/ELF/arm-thunk-multipass.s b/test/ELF/arm-thunk-multipass.s index 25bf5235f755..b353bb148ff6 100644 --- a/test/ELF/arm-thunk-multipass.s +++ b/test/ELF/arm-thunk-multipass.s @@ -5,7 +5,7 @@ // parts we need to speed up the test and avoid a large output file // RUN: llvm-objdump -d %t2 -start-address=1048578 -stop-address=1048586 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK1 %s // RUN: llvm-objdump -d %t2 -start-address=16777224 -stop-address=16777254 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK2 %s -// RUN: llvm-objdump -d %t2 -start-address=17825818 -stop-address=17825828 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s +// RUN: llvm-objdump -d %t2 -start-address=17825812 -stop-address=17825826 -triple=thumbv7a-linux-gnueabihf | FileCheck -check-prefix=CHECK3 %s // In this test case a branch that is in range and does not need its range // extended can be pushed out of range by another Thunk, necessitating another // pass @@ -64,19 +64,15 @@ arm_target: // CHECK2-NEXT: 100000c: c0 f2 00 1c movt r12, #256 // CHECK2-NEXT: 1000010: 60 47 bx r12 // CHECK2: __Thumbv7ABSLongThunk_target: -// CHECK2-NEXT: 1000012: 40 f2 1b 0c movw r12, #27 -// CHECK2-NEXT: 1000016: c0 f2 10 1c movt r12, #272 -// CHECK2-NEXT: 100001a: 60 47 bx r12 +// CHECK2-NEXT: 1000012: ff f0 ff bf b.w #1048574 <target> // CHECK2: __Thumbv7ABSLongThunk_target2: -// CHECK2-NEXT: 100001c: 40 f2 13 0c movw r12, #19 -// CHECK2-NEXT: 1000020: c0 f2 10 0c movt r12, #16 -// CHECK2-NEXT: 1000024: 60 47 bx r12 +// CHECK2-NEXT: 1000016: ff f4 fc 97 b.w #-15728648 <target2> .section .text.17, "ax", %progbits // Just enough space so that bl target is in range if no extension thunks are // generated. - .space 0x100000 - 12 + .space 0x100000 - 6 .section .text.18, "ax", %progbits .thumb @@ -90,7 +86,7 @@ target: nop bx lr // CHECK3: target: -// CHECK3-NEXT: 110001a: ff f6 ff ff bl #-1048578 -// CHECK3-NEXT: 110001e: 00 bf nop -// CHECK3-NEXT: 1100020: 00 bf nop -// CHECK3-NEXT: 1100022: 70 47 bx lr +// CHECK3-NEXT: 1100014: ff f6 ff ff bl #-1048578 +// CHECK3-NEXT: 1100018: 00 bf nop +// CHECK3-NEXT: 110001a: 00 bf nop +// CHECK3-NEXT: 110001c: 70 47 bx lr diff --git a/test/ELF/arm-thunk-nosuitable.s b/test/ELF/arm-thunk-nosuitable.s new file mode 100644 index 000000000000..cde790665c42 --- /dev/null +++ b/test/ELF/arm-thunk-nosuitable.s @@ -0,0 +1,33 @@ +// REQUIRES: ARM +// RUN: llvm-mc %s --arm-add-build-attributes --triple=armv7a-linux-gnueabihf --filetype=obj -o %t.o +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump -triple=thumbv7a-linux-gnueabihf -d -start-address=2166784 -stop-address=2166794 %t | FileCheck %s + + // Create a conditional branch too far away from a precreated thunk + // section. This will need a thunk section created within range. + .syntax unified + .thumb + + .section .text.0, "ax", %progbits + .space 2 * 1024 * 1024 + .globl _start + .type _start, %function +_start: + // Range of +/- 1 Megabyte, new ThunkSection will need creating after + // .text.1 + beq.w target + .section .text.1, "ax", %progbits + bx lr + +// CHECK: _start: +// CHECK-NEXT: 211000: 00 f0 00 80 beq.w #0 +// CHECK: __Thumbv7ABSLongThunk_target: +// CHECK-NEXT: 211004: 00 f0 01 90 b.w #12582914 +// CHECK: $t.1: +// CHECK-NEXT: 211008: 70 47 bx lr + + .section .text.2, "ax", %progbits + .space 12 * 1024 * 1024 + .globl target + .type target, %function +target: bx lr diff --git a/test/ELF/arm-thunk-section-too-large.s b/test/ELF/arm-thunk-section-too-large.s new file mode 100644 index 000000000000..9174093380f7 --- /dev/null +++ b/test/ELF/arm-thunk-section-too-large.s @@ -0,0 +1,21 @@ +// REQUIRES: ARM +// RUN: llvm-mc %s -triple=armv7a-linux-gnueabihf -arm-add-build-attributes -filetype=obj -o %t.o +// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +// CHECK: InputSection too large for range extension thunk + .syntax unified + .thumb + .text + .globl _start + .type _start, %function +_start: + .space 2 * 1024 * 1024 + // conditional branch has range of 1 Mb expect error as we can't place + // a thunk in range of the branch. + beq target + .space 2 * 1024 * 1024 + + .section .text.2, "ax", %progbits + .globl target + .type target, %function +target: bx lr diff --git a/test/ELF/arm-thunk-toolargesection.s b/test/ELF/arm-thunk-toolargesection.s index 28fb94a8ccfd..13d0ea78368b 100644 --- a/test/ELF/arm-thunk-toolargesection.s +++ b/test/ELF/arm-thunk-toolargesection.s @@ -1,6 +1,6 @@ -// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s // REQUIRES: arm +// RUN: llvm-mc -filetype=obj -triple=thumbv7a-none-linux-gnueabi %s -o %t +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s .syntax unified .balign 0x1000 .thumb diff --git a/test/ELF/arm-tls-gd-nonpreemptible.s b/test/ELF/arm-tls-gd-nonpreemptible.s index ebaad4788c76..e72d422bad8b 100644 --- a/test/ELF/arm-tls-gd-nonpreemptible.s +++ b/test/ELF/arm-tls-gd-nonpreemptible.s @@ -1,10 +1,10 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: llvm-objdump -s %t2 | FileCheck %s // RUN: ld.lld --hash-style=sysv %t --shared -o %t3.so // RUN: llvm-objdump -s %t3.so | FileCheck -check-prefix=CHECK-SHARED %s -// REQUIRES: arm // For an executable, we write the module index 1 and the offset into the TLS // directly into the GOT. For a shared library we can only write the offset diff --git a/test/ELF/arm-tls-gd32.s b/test/ELF/arm-tls-gd32.s index a32e26f2aeb9..28ef4967aba8 100644 --- a/test/ELF/arm-tls-gd32.s +++ b/test/ELF/arm-tls-gd32.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared // RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s -// REQUIRES: arm // Test the handling of the global-dynamic TLS model. Dynamic Loader finds // module index R_ARM_TLS_DTPMOD32 and the offset within the module diff --git a/test/ELF/arm-tls-ie32.s b/test/ELF/arm-tls-ie32.s index 26e1265568c8..b12bc1be3161 100644 --- a/test/ELF/arm-tls-ie32.s +++ b/test/ELF/arm-tls-ie32.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared // RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s -// REQUIRES: arm // Test the handling of the initial-exec TLS model. Relative location within // static TLS is a run-time constant computed by dynamic loader as a result diff --git a/test/ELF/arm-tls-ldm32.s b/test/ELF/arm-tls-ldm32.s index 629dcd038899..94931d945761 100644 --- a/test/ELF/arm-tls-ldm32.s +++ b/test/ELF/arm-tls-ldm32.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared // RUN: llvm-readobj -s -dyn-relocations %t.so | FileCheck --check-prefix=SEC %s // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t.so | FileCheck %s -// REQUIRES: arm // Test the handling of the local-dynamic TLS model. Dynamic loader finds // module index R_ARM_TLS_DTPMOD32. The offset in the next GOT slot is 0 diff --git a/test/ELF/arm-tls-le32.s b/test/ELF/arm-tls-le32.s index 4d42a06b0fff..7834dedf1be0 100644 --- a/test/ELF/arm-tls-le32.s +++ b/test/ELF/arm-tls-le32.s @@ -1,8 +1,8 @@ +// REQUIRES: arm // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld %t.o -o %t // RUN: llvm-readobj -s -dyn-relocations %t | FileCheck --check-prefix=SEC %s // RUN: llvm-objdump -d -triple=armv7a-linux-gnueabi %t | FileCheck %s -// REQUIRES: arm // Test the handling of the local exec TLS model. TLS can be resolved // statically for an application. The code sequences assume a thread pointer diff --git a/test/ELF/arm-tls-norelax-gd-ie.s b/test/ELF/arm-tls-norelax-gd-ie.s index bcee56165958..ba60521520fe 100644 --- a/test/ELF/arm-tls-norelax-gd-ie.s +++ b/test/ELF/arm-tls-norelax-gd-ie.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1 // RUN: ld.lld %t1 --shared -o %t1.so // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t // RUN: llvm-readobj -s -dyn-relocations %t | FileCheck %s -// REQUIRES: arm // This tls global-dynamic sequence is with respect to a preemptible symbol but // is in an application so a relaxation to Initial Exec would normally be diff --git a/test/ELF/arm-tls-norelax-gd-le.s b/test/ELF/arm-tls-norelax-gd-le.s index 788c845b3f8b..f1e78c4c76b1 100644 --- a/test/ELF/arm-tls-norelax-gd-le.s +++ b/test/ELF/arm-tls-norelax-gd-le.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1 // RUN: ld.lld %t1 --shared -o %t1.so // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t // RUN: llvm-objdump -s %t | FileCheck %s -// REQUIRES: arm // This tls global-dynamic sequence is with respect to a non-preemptible // symbol in an application so a relaxation to Local Exec would normally be diff --git a/test/ELF/arm-tls-norelax-ie-le.s b/test/ELF/arm-tls-norelax-ie-le.s index eb96aa0fad57..be8af9760481 100644 --- a/test/ELF/arm-tls-norelax-ie-le.s +++ b/test/ELF/arm-tls-norelax-ie-le.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1 // RUN: ld.lld %t1 --shared -o %t1.so // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t // RUN: llvm-objdump -s -triple=armv7a-linux-gnueabi %t | FileCheck %s -// REQUIRES: arm // This tls Initial Exec sequence is with respect to a non-preemptible symbol // so a relaxation would normally be possible. This would result in an assertion diff --git a/test/ELF/arm-tls-norelax-ld-le.s b/test/ELF/arm-tls-norelax-ld-le.s index fc5b72b80f9c..ce0697ad9047 100644 --- a/test/ELF/arm-tls-norelax-ld-le.s +++ b/test/ELF/arm-tls-norelax-ld-le.s @@ -1,9 +1,9 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-tls-get-addr.s -o %t1 // RUN: ld.lld %t1 --shared -o %t1.so // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=armv7a-linux-gnueabi // RUN: ld.lld --hash-style=sysv %t1.so %t.o -o %t // RUN: llvm-objdump -s %t | FileCheck %s -// REQUIRES: arm .global __tls_get_addr .text diff --git a/test/ELF/arm-undefined-weak.s b/test/ELF/arm-undefined-weak.s index 8af9f4916a95..0d4714a54835 100644 --- a/test/ELF/arm-undefined-weak.s +++ b/test/ELF/arm-undefined-weak.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t // RUN: ld.lld %t -o %t2 2>&1 // RUN: llvm-objdump -triple=armv7a-none-linux-gnueabi -d %t2 | FileCheck %s -// REQUIRES: arm // Check that the ARM ABI rules for undefined weak symbols are applied. // Branch instructions are resolved to the next instruction. Undefined diff --git a/test/ELF/arm-use-r-output.s b/test/ELF/arm-use-r-output.s index 918362466d3a..2d2350863165 100644 --- a/test/ELF/arm-use-r-output.s +++ b/test/ELF/arm-use-r-output.s @@ -1,7 +1,7 @@ // REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o // RUN: ld.lld -r %t.o -o %t2.o -// RUN: ld.lld -shared %t2.o -o %t.so +// RUN: ld.lld -shared %t2.o -o /dev/null // We used to crash using the output of -r because of the relative order of // SHF_LINK_ORDER sections. diff --git a/test/ELF/as-needed-lazy.s b/test/ELF/as-needed-lazy.s new file mode 100644 index 000000000000..e892b9980aad --- /dev/null +++ b/test/ELF/as-needed-lazy.s @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/as-needed-lazy.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: rm -f %t2.a +# RUN: llvm-ar rc %t2.a %t2.o +# RUN: ld.lld %t1.o %t2.a --as-needed %t2.so -o %t +# RUN: llvm-readobj -d %t | FileCheck %s + +# CHECK-NOT: NEEDED + +.global _start +_start: + nop diff --git a/test/ELF/as-needed-weak.s b/test/ELF/as-needed-weak.s new file mode 100644 index 000000000000..f009c72d6f48 --- /dev/null +++ b/test/ELF/as-needed-weak.s @@ -0,0 +1,22 @@ +# REQUIRES: x86 + +# RUN: echo '.globl foo; .type foo, @function; foo:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t1.o +# RUN: ld.lld -shared -o %t1.so -soname libfoo %t1.o + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o +# RUN: ld.lld -o %t.exe %t2.o --as-needed %t1.so +# RUN: llvm-readelf -dynamic-table -dyn-symbols %t.exe | FileCheck %s + +# CHECK-NOT: libfoo + +# CHECK: Symbol table of .hash for image: +# CHECK-NEXT: Num Buc: Value Size Type Bind Vis Ndx Name +# CHECK-NEXT: 1 1: 0000000000000000 0 FUNC WEAK DEFAULT UND foo@ + +.globl _start +.weak foo + +_start: + mov $foo, %eax + callq foo diff --git a/test/ELF/as-needed.s b/test/ELF/as-needed.s index bcfa32d01f66..a7bba79d57b0 100644 --- a/test/ELF/as-needed.s +++ b/test/ELF/as-needed.s @@ -22,7 +22,7 @@ // RUN: ld.lld --as-needed %t.o %t2.so --no-as-needed %t3.so %t4.so -o %t2 // RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s -/// GROUP directive is the same as --as-needed. +/// GROUP command is the same as listing the files on the command line. // RUN: echo "GROUP(\"%t2.so\" \"%t3.so\" \"%t4.so\")" > %t.script // RUN: ld.lld %t.o %t.script -o %t2 diff --git a/test/ELF/auxiliary.s b/test/ELF/auxiliary.s index 18fbdf05f9ec..86551e3e84bf 100644 --- a/test/ELF/auxiliary.s +++ b/test/ELF/auxiliary.s @@ -2,6 +2,8 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld %t.o -shared -f aaa --auxiliary bbb -o %t # RUN: llvm-readobj --dynamic-table %t | FileCheck %s +# RUN: ld.lld %t.o -shared -f aaa --auxiliary=bbb -o %t +# RUN: llvm-readobj --dynamic-table %t | FileCheck %s # CHECK: DynamicSection [ # CHECK-NEXT: Tag Type Name/Value diff --git a/test/ELF/basic-aarch64.s b/test/ELF/basic-aarch64.s index 6527d3dc0def..efbe0080844f 100644 --- a/test/ELF/basic-aarch64.s +++ b/test/ELF/basic-aarch64.s @@ -1,8 +1,8 @@ +# REQUIRES: aarch64 # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-freebsd %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \ # RUN: | FileCheck %s -# REQUIRES: aarch64 # exits with return code 42 on FreeBSD/AArch64 .globl _start diff --git a/test/ELF/basic-freebsd.s b/test/ELF/basic-freebsd.s index 375fdb5f8078..f614bb64b069 100644 --- a/test/ELF/basic-freebsd.s +++ b/test/ELF/basic-freebsd.s @@ -1,9 +1,9 @@ +# REQUIRES: x86 # Verify that OSABI is set to the correct value. # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-readobj -file-headers %t2 | FileCheck %s -# REQUIRES: x86 .globl _start _start: diff --git a/test/ELF/basic-mips.s b/test/ELF/basic-mips.s index a193529b3487..9ecabff47f6a 100644 --- a/test/ELF/basic-mips.s +++ b/test/ELF/basic-mips.s @@ -1,10 +1,9 @@ +# REQUIRES: mips # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t.exe # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t.exe \ # RUN: | FileCheck %s -# REQUIRES: mips - # Exits with return code 1 on Linux. .globl __start __start: @@ -19,7 +18,7 @@ __start: # CHECK-NEXT: DataEncoding: LittleEndian (0x1) # CHECK-NEXT: FileVersion: 1 # CHECK-NEXT: OS/ABI: SystemV (0x0) -# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: ABIVersion: 1 # CHECK-NEXT: Unused: (00 00 00 00 00 00 00) # CHECK-NEXT: } # CHECK-NEXT: Type: Executable (0x2) diff --git a/test/ELF/basic-ppc.s b/test/ELF/basic-ppc.s index cda32245fd2b..48b146a21d44 100644 --- a/test/ELF/basic-ppc.s +++ b/test/ELF/basic-ppc.s @@ -1,7 +1,7 @@ +# REQUIRES: ppc # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t # RUN: ld.lld --hash-style=sysv -discard-all -shared %t -o %t2 # RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s -# REQUIRES: ppc # exits with return code 42 on FreeBSD .text @@ -144,9 +144,9 @@ // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 8 // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00000006 00000114 0000000B 00000010 |................| -// CHECK-NEXT: 0010: 00000005 00000134 0000000A 00000001 |.......4........| -// CHECK-NEXT: 0020: 00000004 00000124 00000000 00000000 |.......$........| +// CHECK-NEXT: 0000: 00000006 00000114 0000000B 00000010 +// CHECK-NEXT: 0010: 00000005 00000134 0000000A 00000001 +// CHECK-NEXT: 0020: 00000004 00000124 00000000 00000000 // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { @@ -165,7 +165,7 @@ // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 1 // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| +// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| // CHECK-NEXT: ) // CHECK-NEXT: } // CHECK-NEXT: Section { @@ -215,7 +215,7 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x0 // CHECK-NEXT: Offset: 0x20A1 -// CHECK-NEXT: Size: 1 +// CHECK-NEXT: Size: 10 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 diff --git a/test/ELF/basic-ppc64.s b/test/ELF/basic-ppc64.s new file mode 100644 index 000000000000..f586d6320d16 --- /dev/null +++ b/test/ELF/basic-ppc64.s @@ -0,0 +1,323 @@ +# REQUIRES: ppc +# # RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t +# RUN: ld.lld --hash-style=sysv -discard-all -shared %t -o %t2 +# RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s +.abiversion 2 +# Exits with return code 55 on linux. +.text + li 0,1 + li 3,55 + sc + +// CHECK:Format: ELF64-ppc64 +// CHECK-NEXT:Arch: powerpc64le +// CHECK-NEXT:AddressSize: 64bit +// CHECK-NEXT:LoadName: +// CHECK-NEXT:ElfHeader { +// CHECK-NEXT: Ident { +// CHECK-NEXT: Magic: (7F 45 4C 46) +// CHECK-NEXT: Class: 64-bit (0x2) +// CHECK-NEXT: DataEncoding: LittleEndian (0x1) +// CHECK-NEXT: FileVersion: 1 +// CHECK-NEXT: OS/ABI: SystemV (0x0) +// CHECK-NEXT: ABIVersion: 0 +// CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +// CHECK-NEXT: } +// CHECK-NEXT: Type: SharedObject (0x3) +// CHECK-NEXT: Machine: EM_PPC64 (0x15) +// CHECK-NEXT: Version: 1 +// CHECK-NEXT: Entry: 0x10000 +// CHECK-NEXT: ProgramHeaderOffset: 0x40 +// CHECK-NEXT: SectionHeaderOffset: +// CHECK-NEXT: Flags [ (0x2) +// CHECK-NEXT: 0x2 +// CHECK-NEXT: ] +// CHECK-NEXT: HeaderSize: 64 +// CHECK-NEXT: ProgramHeaderEntrySize: 56 +// CHECK-NEXT: ProgramHeaderCount: 7 +// CHECK-NEXT: SectionHeaderEntrySize: 64 +// CHECK-NEXT: SectionHeaderCount: 10 +// CHECK-NEXT: StringTableSectionIndex: 8 +// CHECK-NEXT:} +// CHECK-NEXT:Sections [ +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 0 +// CHECK-NEXT: Name: (0) +// CHECK-NEXT: Type: SHT_NULL (0x0) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x0 +// CHECK-NEXT: Offset: 0x0 +// CHECK-NEXT: Size: 0 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 0 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 1 +// CHECK-NEXT: Name: .dynsym (1) +// CHECK-NEXT: Type: SHT_DYNSYM (0xB) +// CHECK-NEXT: Flags [ (0x2) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x1C8 +// CHECK-NEXT: Offset: 0x1C8 +// CHECK-NEXT: Size: 24 +// CHECK-NEXT: Link: 3 +// CHECK-NEXT: Info: 1 +// CHECK-NEXT: AddressAlignment: 8 +// CHECK-NEXT: EntrySize: 24 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| +// CHECK-NEXT: 0010: 00000000 00000000 |........| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 2 +// CHECK-NEXT: Name: .hash (9) +// CHECK-NEXT: Type: SHT_HASH (0x5) +// CHECK-NEXT: Flags [ (0x2) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x1E0 +// CHECK-NEXT: Offset: 0x1E0 +// CHECK-NEXT: Size: 16 +// CHECK-NEXT: Link: 1 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 4 +// CHECK-NEXT: EntrySize: 4 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 01000000 01000000 00000000 00000000 |................| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 3 +// CHECK-NEXT: Name: .dynstr (15) +// CHECK-NEXT: Type: SHT_STRTAB (0x3) +// CHECK-NEXT: Flags [ (0x2) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x1F0 +// CHECK-NEXT: Offset: 0x1F0 +// CHECK-NEXT: Size: 1 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 1 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 00 |.| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 4 +// CHECK-NEXT: Name: .text (23) +// CHECK-NEXT: Type: SHT_PROGBITS (0x1) +// CHECK-NEXT: Flags [ (0x6) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_EXECINSTR (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x10000 +// CHECK-NEXT: Offset: 0x10000 +// CHECK-NEXT: Size: 12 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 4 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 01000038 37006038 02000044 |...87.`8...D| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 5 +// CHECK-NEXT: Name: .dynamic (29) +// CHECK-NEXT: Type: SHT_DYNAMIC (0x6) +// CHECK-NEXT: Flags [ (0x3) +// CHECK-NEXT: SHF_ALLOC (0x2) +// CHECK-NEXT: SHF_WRITE (0x1) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x20000 +// CHECK-NEXT: Offset: 0x20000 +// CHECK-NEXT: Size: 96 +// CHECK-NEXT: Link: 3 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 8 +// CHECK-NEXT: EntrySize: 16 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 06000000 00000000 C8010000 00000000 |................| +// CHECK-NEXT: 0010: 0B000000 00000000 18000000 00000000 |................| +// CHECK-NEXT: 0020: 05000000 00000000 F0010000 00000000 |................| +// CHECK-NEXT: 0030: 0A000000 00000000 01000000 00000000 |................| +// CHECK-NEXT: 0040: 04000000 00000000 E0010000 00000000 |................| +// CHECK-NEXT: 0050: 00000000 00000000 00000000 00000000 |................| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 6 +// CHECK-NEXT: Name: .comment (38) +// CHECK-NEXT: Type: SHT_PROGBITS (0x1) +// CHECK-NEXT: Flags [ (0x30) +// CHECK-NEXT: SHF_MERGE (0x10) +// CHECK-NEXT: SHF_STRINGS (0x20) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x0 +// CHECK-NEXT: Offset: 0x20060 +// CHECK-NEXT: Size: 8 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 1 +// CHECK-NEXT: EntrySize: 1 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 7 +// CHECK-NEXT: Name: .symtab (47) +// CHECK-NEXT: Type: SHT_SYMTAB (0x2) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x0 +// CHECK-NEXT: Offset: 0x20068 +// CHECK-NEXT: Size: 48 +// CHECK-NEXT: Link: 9 +// CHECK-NEXT: Info: 2 +// CHECK-NEXT: AddressAlignment: 8 +// CHECK-NEXT: EntrySize: 24 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| +// CHECK-NEXT: 0010: 00000000 00000000 01000000 00020500 |................| +// CHECK-NEXT: 0020: 00000200 00000000 00000000 00000000 |................| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 8 +// CHECK-NEXT: Name: .shstrtab (55) +// CHECK-NEXT: Type: SHT_STRTAB (0x3) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x0 +// CHECK-NEXT: Offset: 0x20098 +// CHECK-NEXT: Size: 73 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 1 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 002E6479 6E73796D 002E6861 7368002E |..dynsym..hash..| +// CHECK-NEXT: 0010: 64796E73 7472002E 74657874 002E6479 |dynstr..text..dy| +// CHECK-NEXT: 0020: 6E616D69 63002E63 6F6D6D65 6E74002E |namic..comment..| +// CHECK-NEXT: 0030: 73796D74 6162002E 73687374 72746162 |symtab..shstrtab| +// CHECK-NEXT: 0040: 002E7374 72746162 00 |..strtab.| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT: Section { +// CHECK-NEXT: Index: 9 +// CHECK-NEXT: Name: .strtab (65) +// CHECK-NEXT: Type: SHT_STRTAB (0x3) +// CHECK-NEXT: Flags [ (0x0) +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x0 +// CHECK-NEXT: Offset: 0x200E1 +// CHECK-NEXT: Size: 10 +// CHECK-NEXT: Link: 0 +// CHECK-NEXT: Info: 0 +// CHECK-NEXT: AddressAlignment: 1 +// CHECK-NEXT: EntrySize: 0 +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 005F4459 4E414D49 4300 |._DYNAMIC.| +// CHECK-NEXT: ) +// CHECK-NEXT: } +// CHECK-NEXT:] +// CHECK-NEXT:ProgramHeaders [ +// CHECK-NEXT: ProgramHeader { +// CHECK-NEXT: Type: PT_PHDR (0x6) +// CHECK-NEXT: Offset: 0x40 +// CHECK-NEXT: VirtualAddress: 0x40 +// CHECK-NEXT: PhysicalAddress: 0x40 +// CHECK-NEXT: FileSize: 392 +// CHECK-NEXT: MemSize: 392 +// CHECK-NEXT: Flags [ (0x4) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 8 +// CHECK-NEXT: } +// CHECK-NEXT: ProgramHeader { +// CHECK-NEXT: Type: PT_LOAD (0x1) +// CHECK-NEXT: Offset: 0x0 +// CHECK-NEXT: VirtualAddress: 0x0 +// CHECK-NEXT: PhysicalAddress: 0x0 +// CHECK-NEXT: FileSize: 497 +// CHECK-NEXT: MemSize: 497 +// CHECK-NEXT: Flags [ (0x4) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 65536 +// CHECK-NEXT: } +// CHECK-NEXT: ProgramHeader { +// CHECK-NEXT: Type: PT_LOAD (0x1) +// CHECK-NEXT: Offset: 0x10000 +// CHECK-NEXT: VirtualAddress: 0x10000 +// CHECK-NEXT: PhysicalAddress: 0x10000 +// CHECK-NEXT: FileSize: 12 +// CHECK-NEXT: MemSize: 12 +// CHECK-NEXT: Flags [ (0x5) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: PF_X (0x1) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 65536 +// CHECK-NEXT: } +// CHECK-NEXT: ProgramHeader { +// CHECK-NEXT: Type: PT_LOAD (0x1) +// CHECK-NEXT: Offset: 0x20000 +// CHECK-NEXT: VirtualAddress: 0x20000 +// CHECK-NEXT: PhysicalAddress: 0x20000 +// CHECK-NEXT: FileSize: 96 +// CHECK-NEXT: MemSize: 96 +// CHECK-NEXT: Flags [ (0x6) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: PF_W (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 65536 +// CHECK-NEXT: } +// CHECK-NEXT: ProgramHeader { +// CHECK-NEXT: Type: PT_DYNAMIC (0x2) +// CHECK-NEXT: Offset: 0x20000 +// CHECK-NEXT: VirtualAddress: 0x20000 +// CHECK-NEXT: PhysicalAddress: 0x20000 +// CHECK-NEXT: FileSize: 96 +// CHECK-NEXT: MemSize: 96 +// CHECK-NEXT: Flags [ (0x6) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: PF_W (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 8 +// CHECK-NEXT: } +// CHECK-NEXT: ProgramHeader { +// CHECK-NEXT: Type: PT_GNU_RELRO (0x6474E552) +// CHECK-NEXT: Offset: 0x20000 +// CHECK-NEXT: VirtualAddress: 0x20000 +// CHECK-NEXT: PhysicalAddress: 0x20000 +// CHECK-NEXT: FileSize: 96 +// CHECK-NEXT: MemSize: 4096 +// CHECK-NEXT: Flags [ (0x4) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 1 +// CHECK-NEXT: } +// CHECK-NEXT: ProgramHeader { +// CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) +// CHECK-NEXT: Offset: 0x0 +// CHECK-NEXT: VirtualAddress: 0x0 +// CHECK-NEXT: PhysicalAddress: 0x0 +// CHECK-NEXT: FileSize: 0 +// CHECK-NEXT: MemSize: 0 +// CHECK-NEXT: Flags [ (0x6) +// CHECK-NEXT: PF_R (0x4) +// CHECK-NEXT: PF_W (0x2) +// CHECK-NEXT: ] +// CHECK-NEXT: Alignment: 0 +// CHECK-NEXT: } +// CHECK-NEXT:] diff --git a/test/ELF/basic-sparcv9.s b/test/ELF/basic-sparcv9.s index 75c20476a43b..272fe01cfc40 100644 --- a/test/ELF/basic-sparcv9.s +++ b/test/ELF/basic-sparcv9.s @@ -1,8 +1,8 @@ +# REQUIRES: sparc # RUN: llvm-mc -filetype=obj -triple=sparc64-unknown-openbsd %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-readobj -file-headers -sections -program-headers -symbols %t2 \ # RUN: | FileCheck %s -# REQUIRES: sparc # exits with return code 42 on OpenBSD/sparc64 .global _start diff --git a/test/ELF/basic32.s b/test/ELF/basic32.s index 071a06332f0a..72058dc6b168 100644 --- a/test/ELF/basic32.s +++ b/test/ELF/basic32.s @@ -1,7 +1,7 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-readobj -file-headers -sections -program-headers %t2 | FileCheck %s -# REQUIRES: x86 # exits with return code 42 on linux .globl _start diff --git a/test/ELF/basic64be.s b/test/ELF/basic64be.s index d16f4a074175..2bef1545153e 100644 --- a/test/ELF/basic64be.s +++ b/test/ELF/basic64be.s @@ -1,29 +1,14 @@ +# REQUIRES: ppc # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t # RUN: ld.lld -discard-all %t -o %t2 # RUN: llvm-readobj -file-headers -sections -section-data -program-headers %t2 | FileCheck %s -# REQUIRES: ppc # exits with return code 42 on linux -.section ".opd","aw" -.global _start -_start: -.quad .Lfoo,.TOC.@tocbase,0 - -# generate .toc and .toc1 sections to make sure that the ordering is as -# intended (.toc before .toc1, and both before .opd). -.section ".toc1","aw" -.quad 22, 37, 89, 47 - -.section ".toc","aw" -.quad 45, 86, 72, 24 - .text -.Lfoo: li 0,1 li 3,42 sc - -# CHECK: ElfHeader { +# CHECK: ElfHeader { # CHECK-NEXT: Ident { # CHECK-NEXT: Magic: (7F 45 4C 46) # CHECK-NEXT: Class: 64-bit (0x2) @@ -36,17 +21,18 @@ _start: # CHECK-NEXT: Type: Executable (0x2) # CHECK-NEXT: Machine: EM_PPC64 (0x15) # CHECK-NEXT: Version: 1 -# CHECK-NEXT: Entry: 0x10020040 +# CHECK-NEXT: Entry: 0x10010000 # CHECK-NEXT: ProgramHeaderOffset: 0x40 -# CHECK-NEXT: SectionHeaderOffset: 0x30080 -# CHECK-NEXT: Flags [ (0x0) +# CHECK-NEXT: SectionHeaderOffset: 0x11050 +# CHECK-NEXT: Flags [ (0x2) +# CHECK-NEXT: 0x2 # CHECK-NEXT: ] # CHECK-NEXT: HeaderSize: 64 # CHECK-NEXT: ProgramHeaderEntrySize: 56 -# CHECK-NEXT: ProgramHeaderCount: 6 +# CHECK-NEXT: ProgramHeaderCount: 4 # CHECK-NEXT: SectionHeaderEntrySize: 64 -# CHECK-NEXT: SectionHeaderCount: 10 -# CHECK-NEXT: StringTableSectionIndex: 8 +# CHECK-NEXT: SectionHeaderCount: 6 +# CHECK-NEXT: StringTableSectionIndex: 4 # CHECK-NEXT: } # CHECK-NEXT: Sections [ # CHECK-NEXT: Section { @@ -67,7 +53,7 @@ _start: # CHECK-NEXT: } # CHECK-NEXT: Section { # CHECK-NEXT: Index: 1 -# CHECK-NEXT: Name: .text +# CHECK-NEXT: Name: .text (1) # CHECK-NEXT: Type: SHT_PROGBITS (0x1) # CHECK-NEXT: Flags [ (0x6) # CHECK-NEXT: SHF_ALLOC (0x2) @@ -81,152 +67,80 @@ _start: # CHECK-NEXT: AddressAlignment: 4 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: SectionData ( -# CHECK: ) -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 2 -# CHECK-NEXT: Name: .toc -# CHECK-NEXT: Type: SHT_PROGBITS (0x1) -# CHECK-NEXT: Flags [ (0x3) -# CHECK-NEXT: SHF_ALLOC (0x2) -# CHECK-NEXT: SHF_WRITE (0x1) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x10020000 -# CHECK-NEXT: Offset: 0x20000 -# CHECK-NEXT: Size: 32 -# CHECK-NEXT: Link: 0 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 1 -# CHECK-NEXT: EntrySize: 0 -# CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 00000000 0000002D 00000000 00000056 |.......-.......V| -# CHECK-NEXT: 0010: 00000000 00000048 00000000 00000018 |.......H........| -# CHECK-NEXT: ) -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 3 -# CHECK-NEXT: Name: .toc1 -# CHECK-NEXT: Type: SHT_PROGBITS (0x1) -# CHECK-NEXT: Flags [ (0x3) -# CHECK-NEXT: SHF_ALLOC (0x2) -# CHECK-NEXT: SHF_WRITE (0x1) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x10020020 -# CHECK-NEXT: Offset: 0x20020 -# CHECK-NEXT: Size: 32 -# CHECK-NEXT: Link: 0 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 1 -# CHECK-NEXT: EntrySize: 0 -# CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 00000000 00000016 00000000 00000025 |...............%| -# CHECK-NEXT: 0010: 00000000 00000059 00000000 0000002F |.......Y......./| +# CHECK-NEXT: 0000: 38000001 3860002A 44000002 |8...8`.*D...| # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: Section { -# CHECK-NEXT: Index: 4 -# CHECK-NEXT: Name: .opd -# CHECK-NEXT: Type: SHT_PROGBITS (0x1) -# CHECK-NEXT: Flags [ (0x3) -# CHECK-NEXT: SHF_ALLOC (0x2) -# CHECK-NEXT: SHF_WRITE (0x1) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x10020040 -# CHECK-NEXT: Offset: 0x20040 -# CHECK-NEXT: Size: 24 -# CHECK-NEXT: Link: 0 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 1 -# CHECK-NEXT: EntrySize: 0 -# CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 00000000 10010000 00000000 10038000 |................| -# CHECK-NEXT: 0010: 00000000 00000000 |........| -# CHECK-NEXT: ) -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 5 -# CHECK-NEXT: Name: .got -# CHECK-NEXT: Type: SHT_PROGBITS -# CHECK-NEXT: Flags [ -# CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: SHF_WRITE -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x10030000 -# CHECK-NEXT: Offset: 0x30000 -# CHECK-NEXT: Size: 0 -# CHECK-NEXT: Link: 0 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 8 -# CHECK-NEXT: EntrySize: 0 -# CHECK-NEXT: SectionData ( -# CHECK-NEXT: ) -# CHECK-NEXT: } -# CHECK-NEXT: Section { -# CHECK-NEXT: Index: 6 -# CHECK-NEXT: Name: .comment +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .comment (7) # CHECK-NEXT: Type: SHT_PROGBITS (0x1) # CHECK-NEXT: Flags [ (0x30) # CHECK-NEXT: SHF_MERGE (0x10) # CHECK-NEXT: SHF_STRINGS (0x20) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x30000 +# CHECK-NEXT: Offset: 0x11000 # CHECK-NEXT: Size: 8 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 1 # CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| +# CHECK-NEXT: 0000: 4C4C4420 312E3000 |LLD 1.0.| # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: Section { -# CHECK-NEXT: Index: 7 -# CHECK-NEXT: Name: .symtab +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .symtab (16) # CHECK-NEXT: Type: SHT_SYMTAB (0x2) # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x30008 -# CHECK-NEXT: Size: 48 -# CHECK-NEXT: Link: 9 +# CHECK-NEXT: Offset: 0x11008 +# CHECK-NEXT: Size: 24 +# CHECK-NEXT: Link: 5 # CHECK-NEXT: Info: 1 # CHECK-NEXT: AddressAlignment: 8 # CHECK-NEXT: EntrySize: 24 # CHECK-NEXT: SectionData ( -# CHECK: ) +# CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 |................| +# CHECK-NEXT: 0010: 00000000 00000000 |........| +# CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: Section { -# CHECK-NEXT: Index: 8 -# CHECK-NEXT: Name: .shstrtab -# CHECK-NEXT: Type: SHT_STRTAB -# CHECK-NEXT: Flags [ +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .shstrtab (24) +# CHECK-NEXT: Type: SHT_STRTAB (0x3) +# CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x30038 -# CHECK-NEXT: Size: 63 +# CHECK-NEXT: Offset: 0x11020 +# CHECK-NEXT: Size: 42 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: SectionData ( -# CHECK: ) +# CHECK-NEXT: 0000: 002E7465 7874002E 636F6D6D 656E7400 |..text..comment.| +# CHECK-NEXT: 0010: 2E73796D 74616200 2E736873 74727461 |.symtab..shstrta| +# CHECK-NEXT: 0020: 62002E73 74727461 6200 |b..strtab.| +# CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: Section { -# CHECK-NEXT: Index: 9 -# CHECK-NEXT: Name: .strtab -# CHECK-NEXT: Type: SHT_STRTAB +# CHECK-NEXT: Index: 5 +# CHECK-NEXT: Name: .strtab (34) +# CHECK-NEXT: Type: SHT_STRTAB (0x3) # CHECK-NEXT: Flags [ (0x0) # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x30077 -# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Offset: 0x1104A +# CHECK-NEXT: Size: 1 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 005F7374 61727400 |._start.| +# CHECK-NEXT: 0000: 00 |.| # CHECK-NEXT: ) # CHECK-NEXT: } # CHECK-NEXT: ] @@ -236,74 +150,49 @@ _start: # CHECK-NEXT: Offset: 0x40 # CHECK-NEXT: VirtualAddress: 0x10000040 # CHECK-NEXT: PhysicalAddress: 0x10000040 -# CHECK-NEXT: FileSize: 336 -# CHECK-NEXT: MemSize: 336 -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R +# CHECK-NEXT: FileSize: 224 +# CHECK-NEXT: MemSize: 224 +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) # CHECK-NEXT: ] # CHECK-NEXT: Alignment: 8 # CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x10000000 -# CHECK-NEXT: PhysicalAddress: 0x10000000 -# CHECK-NEXT: FileSize: 400 -# CHECK-NEXT: MemSize: 400 -# CHECK-NEXT: Flags [ -# CHECK-NEXT: PF_R -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 65536 -# CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x10000 -# CHECK-NEXT: VirtualAddress: 0x10010000 -# CHECK-NEXT: PhysicalAddress: 0x10010000 -# CHECK-NEXT: FileSize: 12 -# CHECK-NEXT: MemSize: 12 -# CHECK-NEXT: Flags [ (0x5) -# CHECK-NEXT: PF_R (0x4) -# CHECK-NEXT: PF_X (0x1) -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 65536 -# CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_LOAD (0x1) -# CHECK-NEXT: Offset: 0x20000 -# CHECK-NEXT: VirtualAddress: 0x10020000 -# CHECK-NEXT: PhysicalAddress: 0x10020000 -# CHECK-NEXT: FileSize: 65536 -# CHECK-NEXT: MemSize: 65536 -# CHECK-NEXT: Flags [ (0x6) -# CHECK-NEXT: PF_R (0x4) -# CHECK-NEXT: PF_W (0x2) -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 65536 -# CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_GNU_RELRO -# CHECK-NEXT: Offset: 0x30000 -# CHECK-NEXT: VirtualAddress: 0x10030000 -# CHECK-NEXT: PhysicalAddress: 0x10030000 -# CHECK-NEXT: FileSize: 0 -# CHECK-NEXT: MemSize: 0 -# CHECK-NEXT: Flags [ (0x4) -# CHECK-NEXT: PF_R (0x4) -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 1 -# CHECK-NEXT: } -# CHECK-NEXT: ProgramHeader { -# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) -# CHECK-NEXT: Offset: 0x0 -# CHECK-NEXT: VirtualAddress: 0x0 -# CHECK-NEXT: PhysicalAddress: 0x0 -# CHECK-NEXT: FileSize: 0 -# CHECK-NEXT: MemSize: 0 -# CHECK-NEXT: Flags [ (0x6) -# CHECK-NEXT: PF_R (0x4) -# CHECK-NEXT: PF_W (0x2) -# CHECK-NEXT: ] -# CHECK-NEXT: Alignment: 0 -# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x10000000 +# CHECK-NEXT: PhysicalAddress: 0x10000000 +# CHECK-NEXT: FileSize: 288 +# CHECK-NEXT: MemSize: 288 +# CHECK-NEXT: Flags [ (0x4) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 65536 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x10000 +# CHECK-NEXT: VirtualAddress: 0x10010000 +# CHECK-NEXT: PhysicalAddress: 0x10010000 +# CHECK-NEXT: FileSize: 4096 +# CHECK-NEXT: MemSize: 4096 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 65536 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: 0 +# CHECK-NEXT: MemSize: 0 +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 0 +# CHECK-NEXT: } # CHECK-NEXT: ] diff --git a/test/ELF/bss.s b/test/ELF/bss.s index abd7f2e564d7..d35449828aed 100644 --- a/test/ELF/bss.s +++ b/test/ELF/bss.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-readobj -sections %t2 | FileCheck %s -// REQUIRES: x86 // Test that bss takes no space on disk. diff --git a/test/ELF/bsymbolic-undef.s b/test/ELF/bsymbolic-undef.s index 19bb3162fd95..1269cb456228 100644 --- a/test/ELF/bsymbolic-undef.s +++ b/test/ELF/bsymbolic-undef.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld -shared -Bsymbolic %t.o -o %t.so # RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s diff --git a/test/ELF/bsymbolic.s b/test/ELF/bsymbolic.s index 5a089d55492d..adb9b3ce3630 100644 --- a/test/ELF/bsymbolic.s +++ b/test/ELF/bsymbolic.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: ld.lld -shared %t.o -o %t0.so // RUN: ld.lld -shared -Bsymbolic %t.o -o %t1.so diff --git a/test/ELF/build-id.s b/test/ELF/build-id.s index 9447a14d4e8a..5ff2996dc8ea 100644 --- a/test/ELF/build-id.s +++ b/test/ELF/build-id.s @@ -7,6 +7,8 @@ # RUN: ld.lld --build-id %t -o %t2 -threads # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s +# RUN: ld.lld --build-id=fast %t -o %t2 -threads +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s # RUN: ld.lld --build-id %t -o %t2 -no-threads # RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=DEFAULT %s diff --git a/test/ELF/cgprofile-bad-clusters.s b/test/ELF/cgprofile-bad-clusters.s new file mode 100644 index 000000000000..a6a09bd04252 --- /dev/null +++ b/test/ELF/cgprofile-bad-clusters.s @@ -0,0 +1,70 @@ +# REQUIRES: x86 +# This test checks that CallGraphSort ignores edges that would form "bad" +# clusters. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "A C 1" > %t.call_graph +# RUN: echo "E B 4" >> %t.call_graph +# RUN: echo "C D 2" >> %t.call_graph +# RUN: echo "B D 1" >> %t.call_graph +# RUN: echo "F G 6" >> %t.call_graph +# RUN: echo "G H 5" >> %t.call_graph +# RUN: echo "H I 4" >> %t.call_graph +# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2 +# RUN: llvm-readobj -symbols %t2 | FileCheck %s + + .section .text.A,"ax",@progbits + .globl A +A: + retq + + .section .text.D,"ax",@progbits +D: + .fill 1000, 1, 0 + + .section .text.E,"ax",@progbits +E: + retq + + .section .text.C,"ax",@progbits +C: + retq + + .section .text.B,"ax",@progbits +B: + .fill 1000, 1, 0 + + .section .text.F,"ax",@progbits +F: + .fill (1024 * 1024) - 1, 1, 0 + + .section .text.G,"ax",@progbits +G: + retq + + .section .text.H,"ax",@progbits +H: + retq + + .section .text.I,"ax",@progbits +I: + .fill 13, 1, 0 + +# CHECK: Name: B +# CHECK-NEXT: Value: 0x201011 +# CHECK: Name: C +# CHECK-NEXT: Value: 0x20100F +# CHECK: Name: D +# CHECK-NEXT: Value: 0x2013F9 +# CHECK: Name: E +# CHECK-NEXT: Value: 0x201010 +# CHECK: Name: F +# CHECK-NEXT: Value: 0x2017E1 +# CHECK: Name: G +# CHECK-NEXT: Value: 0x3017E0 +# CHECK: Name: H +# CHECK-NEXT: Value: 0x201000 +# CHECK: Name: I +# CHECK-NEXT: Value: 0x201001 +# CHECK: Name: A +# CHECK-NEXT: Value: 0x20100E diff --git a/test/ELF/cgprofile-err.s b/test/ELF/cgprofile-err.s new file mode 100644 index 000000000000..6b5425dfafab --- /dev/null +++ b/test/ELF/cgprofile-err.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: echo "A B C 100" > %t.call_graph +# RUN: not ld.lld %t --call-graph-ordering-file \ +# RUN: %t.call_graph -o /dev/null 2>&1 | FileCheck %s + +# CHECK: {{.*}}.call_graph: parse error + +# RUN: echo "A B C" > %t.call_graph +# RUN: not ld.lld %t --call-graph-ordering-file \ +# RUN: %t.call_graph -o /dev/null 2>&1 | FileCheck %s diff --git a/test/ELF/cgprofile-icf.s b/test/ELF/cgprofile-icf.s new file mode 100644 index 000000000000..93b7274a5d33 --- /dev/null +++ b/test/ELF/cgprofile-icf.s @@ -0,0 +1,53 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: echo "A B 100" > %t.call_graph +# RUN: echo "A C 40" >> %t.call_graph +# RUN: echo "C D 61" >> %t.call_graph +# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t.out -icf=all +# RUN: llvm-readobj -symbols %t.out | FileCheck %s +# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2.out +# RUN: llvm-readobj -symbols %t2.out | FileCheck %s --check-prefix=NOICF + + .section .text.D,"ax",@progbits + .globl D +D: + mov $60, %rax + retq + + .section .text.C,"ax",@progbits + .globl C +C: + mov $60, %rax + retq + + .section .text.B,"ax",@progbits + .globl B +B: + mov $2, %rax + retq + + .section .text.A,"ax",@progbits + .globl A +A: + mov $42, %rax + retq + +# CHECK: Name: A +# CHECK-NEXT: Value: 0x201000 +# CHECK: Name: B +# CHECK-NEXT: Value: 0x201010 +# CHECK: Name: C +# CHECK-NEXT: Value: 0x201008 +# CHECK: Name: D +# CHECK-NEXT: Value: 0x201008 + +# NOICF: Name: A +# NOICF-NEXT: Value: 0x201000 +# NOICF: Name: B +# NOICF-NEXT: Value: 0x201008 +# NOICF: Name: C +# NOICF-NEXT: Value: 0x201010 +# NOICF: Name: D +# NOICF-NEXT: Value: 0x201018 diff --git a/test/ELF/cgprofile-txt.s b/test/ELF/cgprofile-txt.s new file mode 100644 index 000000000000..ee5149aac90d --- /dev/null +++ b/test/ELF/cgprofile-txt.s @@ -0,0 +1,185 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld -e A %t -o %t2 +# RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=NOSORT + +# RUN: echo "A B 10" > %t.call_graph +# RUN: echo "A B 10" >> %t.call_graph +# RUN: echo "Aa B 80" >> %t.call_graph +# RUN: echo "A C 40" >> %t.call_graph +# RUN: echo "B C 30" >> %t.call_graph +# RUN: echo "C D 90" >> %t.call_graph +# RUN: echo "PP TS 100" >> %t.call_graph +# RUN: echo "_init2 _init 24567837" >> %t.call_graph +# RUN: echo "TS QC 9001" >> %t.call_graph +# RUN: echo "TooManyPreds0 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds1 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds2 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds3 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds4 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds5 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds6 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds7 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds8 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds9 TooManyPreds 10" >> %t.call_graph +# RUN: echo "TooManyPreds10 TooManyPreds 11" >> %t.call_graph +# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o %t2 +# RUN: llvm-readobj -symbols %t2 | FileCheck %s + + .section .text.D,"ax",@progbits +D: + retq + + .section .text.C,"ax",@progbits + .globl C +C: + retq + + .section .text.B,"ax",@progbits + .globl B +B: + retq + + .section .text.A,"ax",@progbits + .globl A +A: +Aa: + retq + + .section .ponies,"ax",@progbits,unique,1 + .globl TS +TS: + retq + + .section .ponies,"ax",@progbits,unique,2 + .globl PP +PP: + retq + + .section .other,"ax",@progbits,unique,1 + .globl QC +QC: + retq + + .section .other,"ax",@progbits,unique,2 + .globl GB +GB: + retq + + .section .init,"ax",@progbits,unique,1 + .globl _init +_init: + retq + + .section .init,"ax",@progbits,unique,2 + .globl _init2 +_init2: + retq + + .section .text.TooManyPreds,"ax",@progbits +TooManyPreds: + retq + retq + retq + retq + retq + retq + retq + retq + retq + retq + + .section .text.TooManyPreds0,"ax",@progbits +TooManyPreds0: + retq + + .section .text.TooManyPreds1,"ax",@progbits +TooManyPreds1: + retq + + .section .text.TooManyPreds2,"ax",@progbits +TooManyPreds2: + retq + + .section .text.TooManyPreds3,"ax",@progbits +TooManyPreds3: + retq + + .section .text.TooManyPreds4,"ax",@progbits +TooManyPreds4: + retq + + .section .text.TooManyPreds5,"ax",@progbits +TooManyPreds5: + retq + + .section .text.TooManyPreds6,"ax",@progbits +TooManyPreds6: + retq + + .section .text.TooManyPreds7,"ax",@progbits +TooManyPreds7: + retq + + .section .text.TooManyPreds8,"ax",@progbits +TooManyPreds8: + retq + + .section .text.TooManyPreds9,"ax",@progbits +TooManyPreds9: + retq + + .section .text.TooManyPreds10,"ax",@progbits +TooManyPreds10: + retq + +# CHECK: Name: D +# CHECK-NEXT: Value: 0x201003 +# CHECK: Name: TooManyPreds +# CHECK-NEXT: Value: 0x201004 +# CHECK: Name: TooManyPreds10 +# CHECK-NEXT: Value: 0x201018 +# CHECK: Name: A +# CHECK-NEXT: Value: 0x201000 +# CHECK: Name: B +# CHECK-NEXT: Value: 0x201001 +# CHECK: Name: C +# CHECK-NEXT: Value: 0x201002 +# CHECK: Name: GB +# CHECK-NEXT: Value: 0x20101F +# CHECK: Name: PP +# CHECK-NEXT: Value: 0x20101C +# CHECK: Name: QC +# CHECK-NEXT: Value: 0x20101E +# CHECK: Name: TS +# CHECK-NEXT: Value: 0x20101D +# CHECK: Name: _init +# CHECK-NEXT: Value: 0x201020 +# CHECK: Name: _init2 +# CHECK-NEXT: Value: 0x201021 + +# NOSORT: Name: D +# NOSORT-NEXT: Value: 0x201000 +# NOSORT: Name: TooManyPreds +# NOSORT-NEXT: Value: 0x201004 +# NOSORT: Name: TooManyPreds10 +# NOSORT-NEXT: Value: 0x201018 +# NOSORT: Name: A +# NOSORT-NEXT: Value: 0x201003 +# NOSORT: Name: B +# NOSORT-NEXT: Value: 0x201002 +# NOSORT: Name: C +# NOSORT-NEXT: Value: 0x201001 +# NOSORT: Name: GB +# NOSORT-NEXT: Value: 0x20101C +# NOSORT: Name: PP +# NOSORT-NEXT: Value: 0x20101A +# NOSORT: Name: QC +# NOSORT-NEXT: Value: 0x20101B +# NOSORT: Name: TS +# NOSORT-NEXT: Value: 0x201019 +# NOSORT: Name: _init +# NOSORT-NEXT: Value: 0x20101D +# NOSORT: Name: _init2 +# NOSORT-NEXT: Value: 0x20101E diff --git a/test/ELF/cgprofile-warn.s b/test/ELF/cgprofile-warn.s new file mode 100644 index 000000000000..bfb89c4c3b57 --- /dev/null +++ b/test/ELF/cgprofile-warn.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: echo "A B 100" > %t.call_graph +# RUN: echo "A C 40" >> %t.call_graph +# RUN: echo "B C 30" >> %t.call_graph +# RUN: echo "adena1 A 30" >> %t.call_graph +# RUN: echo "A adena2 30" >> %t.call_graph +# RUN: echo "poppy A 30" >> %t.call_graph +# RUN: ld.lld -e A %t --call-graph-ordering-file %t.call_graph -o /dev/null \ +# RUN: -noinhibit-exec -icf=all 2>&1 | FileCheck %s + + .section .text.C,"ax",@progbits + .globl C +C: + mov poppy, %rax + retq + +B = 0x1234 + + .section .text.A,"ax",@progbits + .globl A +A: + mov poppy, %rax + retq + +# CHECK: unable to order absolute symbol: B +# CHECK: {{.*}}.call_graph: no such symbol: adena1 +# CHECK: {{.*}}.call_graph: no such symbol: adena2 +# CHECK: unable to order undefined symbol: poppy + +# RUN: ld.lld %t --call-graph-ordering-file %t.call_graph -o /dev/null \ +# RUN: -noinhibit-exec -icf=all --no-warn-symbol-ordering 2>&1 \ +# RUN: | FileCheck %s --check-prefix=NOWARN +# NOWARN-NOT: unable to order diff --git a/test/ELF/color-diagnostics.test b/test/ELF/color-diagnostics.test index 074bba29c54a..6dfa0ab1af92 100644 --- a/test/ELF/color-diagnostics.test +++ b/test/ELF/color-diagnostics.test @@ -9,6 +9,9 @@ # COLOR: {{ld.lld: .\[0;1;31merror: .\[0munknown argument: -xyz}} # COLOR: {{ld.lld: .\[0;1;31merror: .\[0mcannot open /nosuchfile}} +# RUN: not ld.lld -color-diagnostics=foobar 2>&1 | FileCheck -check-prefix=ERR %s +# ERR: unknown option: --color-diagnostics=foobar + # RUN: not ld.lld /nosuchfile 2>&1 | FileCheck -check-prefix=NOCOLOR %s # RUN: not ld.lld -color-diagnostics=never /nosuchfile 2>&1 \ # RUN: | FileCheck -check-prefix=NOCOLOR %s diff --git a/test/ELF/combrelocs.s b/test/ELF/combrelocs.s index 3c8be807053b..595f6049f5fa 100644 --- a/test/ELF/combrelocs.s +++ b/test/ELF/combrelocs.s @@ -4,6 +4,9 @@ # RUN: ld.lld -shared %t.o -o %t.out # RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s +# RUN: ld.lld -shared %t.o -o %t.out -z combreloc +# RUN: llvm-readobj -r --expand-relocs --dynamic-table %t.out | FileCheck %s + # CHECK: Relocations [ # CHECK-NEXT: Section ({{.*}}) .rela.dyn { # CHECK-NEXT: Relocation { diff --git a/test/ELF/comdat-discarded-reloc.s b/test/ELF/comdat-discarded-reloc.s new file mode 100644 index 000000000000..d23baf386e92 --- /dev/null +++ b/test/ELF/comdat-discarded-reloc.s @@ -0,0 +1,17 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat-discarded-reloc.s -o %t2.o +# RUN: ld.lld -gc-sections %t.o %t2.o -o %t + +## ELF spec doesn't allow a relocation to point to a deduplicated +## COMDAT section. Unfortunately this happens in practice (e.g. .eh_frame) +## Test case checks we do not crash. + +.global bar, _start + +.section .text.foo,"aG",@progbits,group,comdat + +.section .text +_start: + .quad .text.foo + .quad bar diff --git a/test/ELF/comdat-linkonce.s b/test/ELF/comdat-linkonce.s index 78611b4a9f26..8721f58bb20c 100644 --- a/test/ELF/comdat-linkonce.s +++ b/test/ELF/comdat-linkonce.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o // RUN: ld.lld -shared %t.o %t2.o -o %t diff --git a/test/ELF/comdat.s b/test/ELF/comdat.s index 5b190b177ee0..4728dd34af5f 100644 --- a/test/ELF/comdat.s +++ b/test/ELF/comdat.s @@ -1,18 +1,18 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o // RUN: ld.lld -shared %t.o %t.o %t2.o -o %t // RUN: llvm-objdump -d %t | FileCheck %s // RUN: llvm-readobj -s -t %t | FileCheck --check-prefix=READ %s -// REQUIRES: x86 // Check that we don't crash with --gc-section and that we print a list of // reclaimed sections on stderr. // RUN: ld.lld --gc-sections --print-gc-sections -shared %t.o %t.o %t2.o -o %t \ // RUN: 2>&1 | FileCheck --check-prefix=GC %s -// GC: removing unused section from '.text' in file -// GC: removing unused section from '.text3' in file -// GC: removing unused section from '.text' in file -// GC: removing unused section from '.text' in file +// GC: removing unused section {{.*}}.o:(.text) +// GC: removing unused section {{.*}}.o:(.text3) +// GC: removing unused section {{.*}}.o:(.text) +// GC: removing unused section {{.*}}.o:(.text) .section .text2,"axG",@progbits,foo,comdat,unique,0 foo: diff --git a/test/ELF/common.s b/test/ELF/common.s index 7f241ee4d65b..da6657173bfd 100644 --- a/test/ELF/common.s +++ b/test/ELF/common.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/common.s -o %t2 // RUN: ld.lld %t %t2 -o %t3 // RUN: llvm-readobj -t -s %t3 | FileCheck %s -// REQUIRES: x86 // CHECK: Name: .bss // CHECK-NEXT: Type: SHT_NOBITS diff --git a/test/ELF/compatible-section-types.s b/test/ELF/compatible-section-types.s index a5dadb867dc0..e47006c5514a 100644 --- a/test/ELF/compatible-section-types.s +++ b/test/ELF/compatible-section-types.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld -shared %t.o -o %t // RUN: llvm-objdump -section-headers %t | FileCheck %s diff --git a/test/ELF/compress-debug-sections-reloc.s b/test/ELF/compress-debug-sections-reloc.s new file mode 100644 index 000000000000..b4ee4ea6dd97 --- /dev/null +++ b/test/ELF/compress-debug-sections-reloc.s @@ -0,0 +1,26 @@ +# REQUIRES: x86, zlib + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/compress-debug.s -o %t2.o +# RUN: ld.lld %t2.o %t.o -o %t1 --compress-debug-sections=zlib -Ttext=0 +# RUN: llvm-dwarfdump %t1 -debug-str | FileCheck %s +# These two checks correspond to the patched values of a_sym and a_debug_sym. +# D = 0x44 - address of .text input section for this file (the start address of +# .text is 0 as requested on the command line, and the size of the +# preceding .text in the other input file is 0x44). +# C = 0x43 - offset of .debug_info section for this file (the size of +# the preceding .debug_info from the other input file is 0x43). +# CHECK: 0x00000000: "D" +# CHECK: 0x00000004: "C" + +.text +a_sym: +nop + +.section .debug_str,"",@progbits +.long a_sym +.long a_debug_sym + +.section .debug_info,"",@progbits +a_debug_sym: +.long 0x88776655 diff --git a/test/ELF/compressed-debug-conflict.s b/test/ELF/compressed-debug-conflict.s index c67bc9201803..e8c24262b7f4 100644 --- a/test/ELF/compressed-debug-conflict.s +++ b/test/ELF/compressed-debug-conflict.s @@ -1,15 +1,15 @@ # REQUIRES: x86, zlib # RUN: llvm-mc -filetype=obj -triple i686-linux-gnu -compress-debug-sections=zlib %s -o %t.o # RUN: llvm-readobj -sections %t.o | FileCheck -check-prefix=OBJ %s -# RUN: not ld.lld %t.o %t.o -o %tout 2>&1 | FileCheck -check-prefix=ERROR %s +# RUN: not ld.lld %t.o %t.o -o /dev/null 2>&1 | FileCheck -check-prefix=ERROR %s # OBJ: Sections [ # OBJ: Section { -# OBJ: Index: 3 -# OBJ-NEXT: Name: .debug_line (16) -# OBJ-NEXT: Type: SHT_PROGBITS (0x1) -# OBJ-NEXT: Flags [ (0x800) -# OBJ-NEXT: SHF_COMPRESSED (0x800) +# OBJ: Index: +# OBJ: Name: .debug_line +# OBJ-NEXT: Type: SHT_PROGBITS +# OBJ-NEXT: Flags [ +# OBJ-NEXT: SHF_COMPRESSED # OBJ-NEXT: ] # ERROR: error: duplicate symbol: main @@ -27,3 +27,24 @@ main: xorl %eax, %eax retl .file 2 "/tmp/repeat/repeat/repeat/repeat" "repeat.h" + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits + .long .Lend0 - .Lbegin0 # Length of Unit +.Lbegin0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 4 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit + .long .debug_line # DW_AT_stmt_list +.Lend0: + .section .debug_line,"",@progbits diff --git a/test/ELF/compressed-debug-input-err.s b/test/ELF/compressed-debug-input-err.s new file mode 100644 index 000000000000..e32ba315b342 --- /dev/null +++ b/test/ELF/compressed-debug-input-err.s @@ -0,0 +1,11 @@ +# REQUIRES: zlib, x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s + +## Check we are able to report zlib decompressor errors. +# CHECK: error: {{.*}}.o:(.zdebug_str): decompress failed: zlib error: Z_DATA_ERROR + +.section .zdebug_str,"MS",@progbits,1 + .ascii "ZLIB" + .byte 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1 diff --git a/test/ELF/conflict-debug-variable-file-index.s b/test/ELF/conflict-debug-variable-file-index.s new file mode 100644 index 000000000000..c7bd8bbcbafb --- /dev/null +++ b/test/ELF/conflict-debug-variable-file-index.s @@ -0,0 +1,103 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: not ld.lld %t.o %t.o -o %t 2>&1 | FileCheck %s + +## Check we are able to report errors even if DW_AT_decl_file +## contains invalid file name index. +## We did not try to support this intentionally but have +## an error handling and reporting logic that can take care +## of that and hence needs a test. + +# CHECK: duplicate symbol: foo +# CHECK-NEXT: >>> defined at {{.*}}.o:(foo) +# CHECK-NEXT: >>> {{.*}}.o:(.bss+0x0) + +# Used modified output from the following code and gcc 7.1.0: +# Source (1.c): +# int foo = 0; +# Invocation: g++ -g -S 1.c + +.bss +.globl foo +.type foo, @object +.size foo, 4 +foo: + +.text +.file 1 "1.c" + +.section .debug_info,"",@progbits + .long 0x35 # Compile Unit: length = 0x0000004b) + .value 0x4 # version = 0x0004 + .long 0 # abbr_offset = 0x0 + .byte 0x8 # addr_size = 0x08 + + .uleb128 0x1 # DW_TAG_compile_unit [1] * + .long 0 # DW_AT_producer [DW_FORM_strp] ( .debug_str[0x00000000] = ) + .byte 0x4 # DW_AT_language [DW_FORM_data1] (DW_LANG_C_plus_plus) + .string "1.c" # DW_AT_name [DW_FORM_string] ("1.c") + .long 0 # DW_AT_comp_dir [DW_FORM_strp] ( .debug_str[0x00000000] = ) + .long 0 # DW_AT_stmt_list [DW_FORM_sec_offset] (0x00000000) + + .uleb128 0x2 # DW_TAG_variable [2] + .string "foo" # DW_AT_name [DW_FORM_string] ("foo") + .byte 0xFE # DW_AT_decl_file [DW_FORM_data1] <broken file> + .byte 0x1 # DW_AT_decl_line [DW_FORM_data1] (1) + .long 0x32 # DW_AT_type [DW_FORM_ref4] (cu + 0x0032 => {0x00000032}) + .uleb128 0x9 # DW_AT_external [DW_FORM_flag_present] (true) + .byte 0x3 + .quad foo # DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0) + + .uleb128 0x3 # DW_TAG_base_type [3] + .byte 0x4 # DW_AT_byte_size [DW_FORM_data1] (0x04) + .byte 0x5 # DW_AT_encoding [DW_FORM_data1] (DW_ATE_signed) + .string "int" # DW_AT_name [DW_FORM_string] ("int") + +.section .debug_abbrev,"",@progbits + .uleb128 0x1 # Abbreviation code. + .uleb128 0x11 # DW_TAG_compile_unit + + .byte 0x1 # ID + .uleb128 0x25 # DW_AT_producer, DW_FORM_strp + .uleb128 0xe + .uleb128 0x13 # DW_AT_language, DW_FORM_data1 + .uleb128 0xb + .uleb128 0x3 # DW_AT_name, DW_FORM_string + .uleb128 0x8 + .uleb128 0x1b # DW_AT_comp_dir, DW_FORM_strp + .uleb128 0xe + .uleb128 0x10 # DW_AT_stmt_list, DW_FORM_sec_offset + .uleb128 0x17 + .byte 0 + .byte 0 + + .uleb128 0x2 # ID + .uleb128 0x34 # DW_TAG_variable, DW_CHILDREN_no + .byte 0 + .uleb128 0x3 # DW_AT_name, DW_FORM_string + .uleb128 0x8 + .uleb128 0x3a # DW_AT_decl_file, DW_FORM_data1 + .uleb128 0xb + .uleb128 0x3b # DW_AT_decl_line, DW_FORM_data1 + .uleb128 0xb + .uleb128 0x49 # DW_AT_type, DW_FORM_ref4 + .uleb128 0x13 + .uleb128 0x3f # DW_AT_external, DW_FORM_flag_present + .uleb128 0x19 + .uleb128 0x2 # DW_AT_location, DW_FORM_exprloc + .uleb128 0x18 + .byte 0 + .byte 0 + + .uleb128 0x3 # ID + .uleb128 0x24 # DW_TAG_base_type, DW_CHILDREN_no + .byte 0 + .uleb128 0xb # DW_AT_byte_size, DW_FORM_data1 + .uleb128 0xb + .uleb128 0x3e # DW_AT_encoding, DW_FORM_data1 + .uleb128 0xb + .uleb128 0x3 # DW_AT_name, DW_FORM_string + .uleb128 0x8 + .byte 0 + .byte 0 + .byte 0 diff --git a/test/ELF/conflict-debug-variable.s b/test/ELF/conflict-debug-variable.s index 297ed4bbe1ea..244ac146a01b 100644 --- a/test/ELF/conflict-debug-variable.s +++ b/test/ELF/conflict-debug-variable.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: llvm-dwarfdump %t.o | FileCheck -check-prefix=INPUT %s # RUN: not ld.lld %t.o %t.o -o %t 2>&1 | FileCheck %s @@ -7,14 +8,14 @@ # INPUT-NEXT: DW_AT_name ("foo") # INPUT-NEXT: DW_AT_decl_file ("1.c") # INPUT-NEXT: DW_AT_decl_line (1) -# INPUT-NEXT: DW_AT_type (cu + 0x0032 "int") +# INPUT-NEXT: DW_AT_type (0x00000032 "int") # INPUT-NEXT: DW_AT_external (true) # INPUT-NEXT: DW_AT_location (DW_OP_addr 0x0) # INPUT: DW_TAG_variable # INPUT-NEXT: DW_AT_name ("bar") # INPUT-NEXT: DW_AT_decl_file ("1.c") # INPUT-NEXT: DW_AT_decl_line (2) -# INPUT-NEXT: DW_AT_type (cu + 0x0032 "int") +# INPUT-NEXT: DW_AT_type (0x00000032 "int") # INPUT-NEXT: DW_AT_external (true) # INPUT-NEXT: DW_AT_location (DW_OP_addr 0x0) @@ -38,6 +39,7 @@ # Source (1.c): # int foo = 0; # int bar = 1; +# static int zed = 3; # Invocation: g++ -g -S 1.c .bss @@ -51,12 +53,16 @@ foo: .type bar, @object .size bar, 4 bar: + .byte 0 + +.local zed +zed: .text .file 1 "1.c" .section .debug_info,"",@progbits - .long 0x4b # Compile Unit: length = 0x0000004b) + .long 0x5a # Compile Unit: length = 0x0000004b) .value 0x4 # version = 0x0004 .long 0 # abbr_offset = 0x0 .byte 0x8 # addr_size = 0x08 @@ -90,6 +96,14 @@ bar: .uleb128 0x9 # DW_AT_external [DW_FORM_flag_present] (true) .byte 0x3 .quad bar # DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0) + + .uleb128 0x4 # DW_TAG_variable [2] + .string "zed" # DW_AT_name [DW_FORM_string] ("zed") + .byte 0x1 # DW_AT_decl_file [DW_FORM_data1] ("1.c") + .byte 0x3 # DW_AT_decl_line [DW_FORM_data1] (2) + .long 0x32 # DW_AT_type [DW_FORM_ref4] (cu + 0x0032 => {0x00000032}) + .quad zed # DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0) + .byte 0 # END @@ -140,5 +154,21 @@ bar: .uleb128 0x8 .byte 0 .byte 0 + + .uleb128 0x4 # ID + .uleb128 0x34 # DW_TAG_variable, DW_CHILDREN_no + .byte 0 + .uleb128 0x3 # DW_AT_name, DW_FORM_string + .uleb128 0x8 + .uleb128 0x3a # DW_AT_decl_file, DW_FORM_data1 + .uleb128 0xb + .uleb128 0x3b # DW_AT_decl_line, DW_FORM_data1 + .uleb128 0xb + .uleb128 0x49 # DW_AT_type, DW_FORM_ref4 + .uleb128 0x13 + .uleb128 0x2 # DW_AT_location, DW_FORM_exprloc + .uleb128 0x18 + .byte 0 .byte 0 + .byte 0 diff --git a/test/ELF/conflict-debug-variable2.s b/test/ELF/conflict-debug-variable2.s index 1fb9b09443b4..3fb59e6b4d02 100644 --- a/test/ELF/conflict-debug-variable2.s +++ b/test/ELF/conflict-debug-variable2.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: llvm-dwarfdump -v %t.o | FileCheck -check-prefix=INPUT %s @@ -18,7 +19,7 @@ # INPUT-NEXT: DW_AT_location [DW_FORM_exprloc] (DW_OP_addr 0x0) ## Check we use information from .debug_info in messages. -# RUN: not ld.lld %t.o %t.o -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o %t.o -o /dev/null 2>&1 | FileCheck %s # CHECK: duplicate symbol: bar # CHECK-NEXT: >>> defined at test.c:2 # CHECK-NEXT: >>> {{.*}}:(bar) diff --git a/test/ELF/conflict-variable-linkage-name.s b/test/ELF/conflict-variable-linkage-name.s new file mode 100644 index 000000000000..9b201d93a830 --- /dev/null +++ b/test/ELF/conflict-variable-linkage-name.s @@ -0,0 +1,176 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: not ld.lld %t.o %t.o -o /dev/null 2>&1 | FileCheck %s + +## Check we can report the locations of 2 different "bar" variables. +# CHECK: duplicate symbol: A::bar +# CHECK-NEXT: >>> defined at 1.cpp:2 +# CHECK-NEXT: >>> {{.*}}:(A::bar) +# CHECK-NEXT: >>> defined at 1.cpp:2 +# CHECK-NEXT: >>> {{.*}}:(.bss+0x0) +# CHECK: duplicate symbol: Z::bar +# CHECK-NEXT: >>> defined at 1.cpp:6 +# CHECK-NEXT: >>> {{.*}}:(Z::bar) +# CHECK-NEXT: >>> defined at 1.cpp:6 +# CHECK-NEXT: >>> {{.*}}:(.data+0x0) + +# Used reduced output from following code and clang version 7.0.0 (trunk 332701) +# to produce this input file: +# Source (1.cpp): +# namespace A { +# int bar; +# } +# +# namespace Z { +# int bar; +# } +# Invocation: clang-7 -g -S 1.cpp + +.text +.file "1.cpp" +.file 1 "/path" "1.cpp" + +.type _ZN1A3barE,@object +.bss +.globl _ZN1A3barE +_ZN1A3barE: + .long 0 + .size _ZN1A3barE, 4 + +.type _ZN1Z3barE,@object +.data +.globl _ZN1Z3barE +_ZN1Z3barE: + .long 1 + .size _ZN1Z3barE, 4 + +.section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 7.0.0 (trunk 332701)" # string offset=0 +.Linfo_string1: + .asciz "1.cpp" # string offset=35 +.Linfo_string2: + .asciz "/path" # string offset=41 +.Linfo_string3: + .asciz "A" # string offset=87 +.Linfo_string4: + .asciz "bar" # string offset=89 +.Linfo_string5: + .asciz "int" # string offset=93 +.Linfo_string6: + .asciz "_ZN1A3barE" # string offset=97 +.Linfo_string7: + .asciz "Z" # string offset=108 +.Linfo_string8: + .asciz "_ZN1Z3barE" # string offset=110 + +.section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .ascii "\264B" # DW_AT_GNU_pubnames + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 2 # Abbreviation Code + .byte 57 # DW_TAG_namespace + .byte 1 # DW_CHILDREN_yes + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 3 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 110 # DW_AT_linkage_name + .byte 14 # DW_FORM_strp + .byte 0 # EOM(1) + .byte 0 # EOM(2) + + .byte 4 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits + .long 96 # Length of Unit + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + + .byte 1 # Abbrev [1] 0xb:0x59 DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 4 # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .long 0 # DW_AT_stmt_list + .long .Linfo_string2 # DW_AT_comp_dir + # DW_AT_GNU_pubnames + + .byte 2 # Abbrev [2] 0x1e:0x1f DW_TAG_namespace + .long .Linfo_string3 # DW_AT_name + + .byte 3 # Abbrev [3] 0x23:0x19 DW_TAG_variable + .long .Linfo_string4 # DW_AT_name + .long 61 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .byte 9 # DW_AT_location + .byte 3 + .quad _ZN1A3barE + .long .Linfo_string6 # DW_AT_linkage_name + .byte 0 # End Of Children Mark + + .byte 4 # Abbrev [4] 0x3d:0x7 DW_TAG_base_type + .long .Linfo_string5 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + + .byte 2 # Abbrev [2] 0x44:0x1f DW_TAG_namespace + .long .Linfo_string7 # DW_AT_name + + .byte 3 # Abbrev [3] 0x49:0x19 DW_TAG_variable + .long .Linfo_string4 # DW_AT_name + .long 61 # DW_AT_type + # DW_AT_external + .byte 1 # DW_AT_decl_file + .byte 6 # DW_AT_decl_line + .byte 9 # DW_AT_location + .byte 3 + .quad _ZN1Z3barE + .long .Linfo_string8 # DW_AT_linkage_name + + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark diff --git a/test/ELF/conflict.s b/test/ELF/conflict.s index 4318759cbc11..cbe1b5b8845a 100644 --- a/test/ELF/conflict.s +++ b/test/ELF/conflict.s @@ -34,7 +34,7 @@ # ARCHIVE-NEXT: >>> defined at {{.*}}:(.text+0x0) in archive {{.*}}.a # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/conflict-debug.s -o %t-dbg.o -# RUN: not ld.lld %t-dbg.o %t-dbg.o -o %t-dbg 2>&1 | FileCheck -check-prefix=DBGINFO %s +# RUN: not ld.lld %t-dbg.o %t-dbg.o -o /dev/null 2>&1 | FileCheck -check-prefix=DBGINFO %s # DBGINFO: duplicate symbol: zed # DBGINFO-NEXT: >>> defined at conflict-debug.s:4 diff --git a/test/ELF/copy-errors.s b/test/ELF/copy-errors.s index 0af4638120d1..40f73178557d 100644 --- a/test/ELF/copy-errors.s +++ b/test/ELF/copy-errors.s @@ -7,12 +7,19 @@ // CHECK: cannot preempt symbol: bar // CHECK: >>> defined in {{.*}}.so // CHECK: >>> referenced by {{.*}}.o:(.text+0x1) -// CHECK: symbol 'zed' defined in {{.*}}.so has no type + +// CHECK: error: symbol 'zed' has no type +// CHECK-NEXT: >>> defined in {{.*}}.so +// CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x6) // RUN: not ld.lld --noinhibit-exec %t.o %t2.so -o %t 2>&1 | FileCheck %s --check-prefix=NOINHIBIT -// NOINHIBIT: warning: symbol 'zed' defined in {{.*}}.so has no type +// NOINHIBIT: warning: symbol 'zed' has no type +// NOINHIBIT-NEXT: >>> defined in {{.*}}.so +// NOINHIBIT-NEXT: >>> referenced by {{.*}}.o:(.text+0x6) .global _start _start: -call bar -call zed +.byte 0xe8 +.long bar - . +.byte 0xe8 +.long zed - . diff --git a/test/ELF/copy-in-shared.s b/test/ELF/copy-in-shared.s index 70439853c7c1..a5508932d035 100644 --- a/test/ELF/copy-in-shared.s +++ b/test/ELF/copy-in-shared.s @@ -2,9 +2,9 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-in-shared.s -o %t1.o // RUN: ld.lld -shared %t1.o -o %t1.so // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o -// RUN: not ld.lld %t2.o %t1.so -o %t2.so -shared 2>&1 | FileCheck %s +// RUN: not ld.lld %t2.o %t1.so -o /dev/null -shared 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment +// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.so // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/copy-rel-corrupted.s b/test/ELF/copy-rel-corrupted.s index 3cdad7cf8037..76f64fa7725c 100644 --- a/test/ELF/copy-rel-corrupted.s +++ b/test/ELF/copy-rel-corrupted.s @@ -1,10 +1,11 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: llvm-mc %p/Inputs/copy-rel-corrupted.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t2.o -o %t2.so -shared -// RUN: not ld.lld %t.o %t2.so -o %t.exe 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %t2.so -o /dev/null 2>&1 | FileCheck %s // CHECK: error: cannot create a copy relocation for symbol x .global _start _start: - call x + .long x - . diff --git a/test/ELF/copy-rel-pie-error.s b/test/ELF/copy-rel-pie-error.s index 6f7677e25e3a..379442e1176c 100644 --- a/test/ELF/copy-rel-pie-error.s +++ b/test/ELF/copy-rel-pie-error.s @@ -1,13 +1,14 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t2.o -o %t2.so -shared -// RUN: not ld.lld %t.o %t2.so -o %t.exe -pie 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %t2.so -o /dev/null -pie 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: bar +// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: bar in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.so // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) -// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo +// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.so // CHECK: >>> referenced by {{.*}}.o:(.text+0x8) diff --git a/test/ELF/copy-rel-pie.s b/test/ELF/copy-rel-pie.s index dcccf8e30b1d..9bf91595db12 100644 --- a/test/ELF/copy-rel-pie.s +++ b/test/ELF/copy-rel-pie.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: llvm-mc %p/Inputs/copy-rel-pie.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t2.o -o %t2.so -shared @@ -7,8 +8,10 @@ .global _start _start: - call bar - call foo + .byte 0xe8 + .long bar - . -4 + .byte 0xe8 + .long foo - . -4 // CHECK: Name: .plt // CHECK-NEXT: Type: SHT_PROGBITS diff --git a/test/ELF/copy-rel-version.s b/test/ELF/copy-rel-version.s new file mode 100644 index 000000000000..29fae8ecbb05 --- /dev/null +++ b/test/ELF/copy-rel-version.s @@ -0,0 +1,15 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-rel-version.s -o %t1.o +// RUN: echo "v1 {}; v2 {};" > %t.ver +// RUN: ld.lld %t1.o -shared -soname t1.so --version-script=%t.ver -o %t1.so +// RUN: ld.lld %t.o %t1.so -o %t +// RUN: llvm-readobj -t %t | FileCheck %s + +.global _start +_start: + leaq foo, %rax + +// CHECK: Name: foo ( +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: 8 diff --git a/test/ELF/copy-relocation-zero-abs-addr.s b/test/ELF/copy-relocation-zero-abs-addr.s new file mode 100644 index 000000000000..fae963e9bd9e --- /dev/null +++ b/test/ELF/copy-relocation-zero-abs-addr.s @@ -0,0 +1,44 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-relocation-zero-abs-addr.s -o %t.o +// RUN: ld.lld -shared -o %t2.so %t.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o +// RUN: ld.lld %t2.so %t3.o -o %t4 +// RUN: llvm-readobj -symbols %t2.so | FileCheck -check-prefix=ABSADDR %s +// RUN: llvm-readobj -s -r --expand-relocs %t4 | FileCheck %s + +// This tests that symbols with absolute addresses are properly +// handled. Normal DSO symbols are handled as usual. + +.text +.globl _start +_start: + movl $5, foo + +// ABSADDR: Name: ver1 +// ABSADDR-NEXT: Value: 0x0 +// ABSADDR-NEXT: Size: 0 +// ABSADDR-NEXT: Binding: Global +// ABSADDR-NEXT: Type: None +// ABSADDR-NEXT: Other: 0 +// ABSADDR-NEXT: Section: Absolute (0xFFF1) +// ABSADDR-NEXT: } +// ABSADDR-NEXT: Symbol { +// ABSADDR-NEXT: Name: ver2 +// ABSADDR-NEXT: Value: 0x0 +// ABSADDR-NEXT: Size: 0 +// ABSADDR-NEXT: Binding: Global +// ABSADDR-NEXT: Type: None +// ABSADDR-NEXT: Other: 0 +// ABSADDR-NEXT: Section: Absolute (0xFFF1) +// ABSADDR-NEXT: } + +// CHECK: Relocations [ +// CHECK-NEXT: Section (5) .rela.dyn { +// CHECK-NEXT: Relocation { +// CHECK-NEXT: Offset: +// CHECK-NEXT: Type: R_X86_64_COPY +// CHECK-NEXT: Symbol: foo +// CHECK-NEXT: Addend: +// CHECK-NEXT: } +// CHECK-NEXT: } +// CHECK-NEXT: ] diff --git a/test/ELF/copy-relocation-zero-nonabs-addr.s b/test/ELF/copy-relocation-zero-nonabs-addr.s new file mode 100644 index 000000000000..50876056b256 --- /dev/null +++ b/test/ELF/copy-relocation-zero-nonabs-addr.s @@ -0,0 +1,29 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/copy-relocation-zero-nonabs-addr.s -o %t1.o +// RUN: ld.lld -Ttext=0 -o %t2.so --script=%p/Inputs/copy-relocation-zero-nonabs-addr.script %t1.o -shared +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o +// RUN: ld.lld %t2.so %t3.o -o %t4 +// RUN: llvm-readobj --symbols %t2.so | FileCheck --check-prefix=CHECKSO %s +// RUN: llvm-readobj --symbols %t4 | FileCheck %s + +.text +.globl _start +_start: + movl $5, foo + +// Make sure foo has st_value == 0. +// CHECKSO: Name: foo +// CHECKSO-NEXT: Value: 0x0 +// CHECKSO-NEXT: Size: 4 +// CHECKSO-NEXT: Binding: Global +// CHECKSO-NEXT: Type: Object +// CHECKSO-NEXT: Other: 0 +// CHECKSO-NEXT: Section: .text + +// When foo has st_value == 0, it carries the section alignment. +// In this case, section alignment is 2^10, 0x202400 meets the requirement. +// CHECK: Name: foo +// CHECK-NEXT: Value: 0x202400 +// CHECK-NEXT: Size: 4 +// CHECK-NEXT: Binding: Global +// CHECK-NEXT: Type: Object diff --git a/test/ELF/corrupted-version-reference.s b/test/ELF/corrupted-version-reference.s index d37f272f445d..203dc2afd8a1 100644 --- a/test/ELF/corrupted-version-reference.s +++ b/test/ELF/corrupted-version-reference.s @@ -1,6 +1,6 @@ -# RUN: llvm-mc -triple=mips64-unknown-freebsd %s -filetype=obj -o %t.o -# RUN: not ld.lld %t.o %S/Inputs/corrupt-version-reference.so -o %t.exe 2>&1 | FileCheck %s # REQUIRES: mips +# RUN: llvm-mc -triple=mips64-unknown-freebsd %s -filetype=obj -o %t.o +# RUN: not ld.lld %t.o %S/Inputs/corrupt-version-reference.so -o /dev/null 2>&1 | FileCheck %s # CHECK: error: corrupt input file: version definition index 9 for symbol __cxa_finalize is out of bounds # CHECK: >>> defined in {{.+}}/corrupt-version-reference.so diff --git a/test/ELF/cref.s b/test/ELF/cref.s new file mode 100644 index 000000000000..2a82f4252e84 --- /dev/null +++ b/test/ELF/cref.s @@ -0,0 +1,33 @@ +// REQUIRES: x86 + +// RUN: echo '.global foo; foo:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t1.o +// RUN: echo '.global foo, bar; bar:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o +// RUN: echo '.global zed; zed:' | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %ta.o +// RUN: rm -f %t.a +// RUN: llvm-ar rcs %t.a %ta.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t3.o +// RUN: ld.lld -shared -o %t1.so %t1.o +// RUN: ld.lld -o /dev/null %t1.so %t2.o %t3.o %t.a -gc-sections -cref | FileCheck -strict-whitespace %s + +// CHECK: Symbol File +// CHECK-NEXT: bar {{.*}}2.o +// CHECK-NEXT: {{.*}}3.o +// CHECK-NEXT: foo {{.*}}1.so +// CHECK-NEXT: {{.*}}2.o +// CHECK-NEXT: {{.*}}3.o +// CHECK-NEXT: _start {{.*}}3.o +// CHECK-NEXT: baz {{.*}}3.o +// CHECK-NEXT: zed {{.*}}.a({{.*}}a.o) +// CHECK-NEXT: {{.*}}3.o +// CHECK-NOT: discarded + +.global _start, foo, bar, baz, discarded +_start: + call foo + call bar + call zed +localsym: +baz: + +.section .text.a,"ax",@progbits +discarded: diff --git a/test/ELF/ctors_dtors_priority.s b/test/ELF/ctors_dtors_priority.s index fcddcbb020f3..203bf247aa34 100644 --- a/test/ELF/ctors_dtors_priority.s +++ b/test/ELF/ctors_dtors_priority.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ // RUN: %p/Inputs/ctors_dtors_priority1.s -o %t-crtbegin.o @@ -7,7 +8,6 @@ // RUN: %p/Inputs/ctors_dtors_priority3.s -o %t-crtend.o // RUN: ld.lld %t1 %t2 %t-crtend.o %t-crtbegin.o -o %t.exe // RUN: llvm-objdump -s %t.exe | FileCheck %s -// REQUIRES: x86 .globl _start _start: diff --git a/test/ELF/defined-tls_get_addr.s b/test/ELF/defined-tls_get_addr.s index 509c293cca1d..66ec01597566 100644 --- a/test/ELF/defined-tls_get_addr.s +++ b/test/ELF/defined-tls_get_addr.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj -// RUN: ld.lld %t.o -o %t +// RUN: ld.lld %t.o -o /dev/null // Don't error if __tls_get_addr is defined. diff --git a/test/ELF/defsym-reserved-syms.s b/test/ELF/defsym-reserved-syms.s new file mode 100644 index 000000000000..fdab00fed66b --- /dev/null +++ b/test/ELF/defsym-reserved-syms.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -o %t %t.o --defsym=foo2=etext +# RUN: llvm-readobj -t -s %t | FileCheck %s + +## Check 'foo2' value is equal to value of 'etext'. +# CHECK: Symbol { +# CHECK: Name: foo2 +# CHECK-NEXT: Value: 0x[[VAL:.*]] +# CHECK: Symbol { +# CHECK: Name: etext +# CHECK-NEXT: Value: 0x[[VAL]] + +## Check 'foo2' value set correctly when using +## reserved symbol 'etext' in expression. +# RUN: ld.lld -o %t %t.o --defsym=foo2=etext+2 +# RUN: llvm-readobj -t -s %t | FileCheck %s --check-prefix=EXPR +# EXPR: Symbol { +# EXPR: Name: foo2 +# EXPR-NEXT: Value: 0x201007 +# EXPR: Symbol { +# EXPR: Name: etext +# EXPR-NEXT: Value: 0x201005 + +.globl foo1 + foo1 = 0x123 + +.global _start +_start: + movl $foo2, %edx diff --git a/test/ELF/discard-locals.s b/test/ELF/discard-locals.s index 9deaccff11c7..50cf5a04e985 100644 --- a/test/ELF/discard-locals.s +++ b/test/ELF/discard-locals.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t // RUN: ld.lld -discard-locals %t -o %t2 // RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s -// REQUIRES: x86 .global _start _start: diff --git a/test/ELF/discard-merge-locals.s b/test/ELF/discard-merge-locals.s index 01b4d337cb2d..20be35c6e4e8 100644 --- a/test/ELF/discard-merge-locals.s +++ b/test/ELF/discard-merge-locals.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %t -o %t2 -shared // RUN: llvm-readobj -t %t2 | FileCheck %s -// REQUIRES: x86 leaq .L.str(%rip), %rdi diff --git a/test/ELF/discard-none.s b/test/ELF/discard-none.s index 89e06fd7b7e4..4a42639c63f1 100644 --- a/test/ELF/discard-none.s +++ b/test/ELF/discard-none.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux -save-temp-labels %s -o %t // RUN: ld.lld -discard-none -shared %t -o %t2 // RUN: llvm-readobj -s -sd -t %t2 | FileCheck %s -// REQUIRES: x86 .text .Lmyvar: diff --git a/test/ELF/dont-export-hidden.s b/test/ELF/dont-export-hidden.s index 8088c8d94d89..161e342bea84 100644 --- a/test/ELF/dont-export-hidden.s +++ b/test/ELF/dont-export-hidden.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %p/Inputs/shared.s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: llvm-mc %s -o %t2.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t.o -o %t.so -shared diff --git a/test/ELF/driver.test b/test/ELF/driver.test index ac324cbaac45..20bc79509725 100644 --- a/test/ELF/driver.test +++ b/test/ELF/driver.test @@ -35,25 +35,35 @@ # RUN: not ld.lld -r --gc-sections %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR3 %s # ERR3: -r and --gc-sections may not be used together +## Attempt to use -r and --gdb-index together +# RUN: not ld.lld -r --gdb-index %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR4 %s +# ERR4: -r and --gdb-index may not be used together + ## Attempt to use -r and --icf together -# RUN: not ld.lld -r --icf=all %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR4 %s -# ERR4: -r and --icf may not be used together +# RUN: not ld.lld -r --icf=all %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR5 %s +# ERR5: -r and --icf may not be used together ## Attempt to use -r and -pie together -# RUN: not ld.lld -r -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR5 %s -# ERR5: -r and -pie may not be used together +# RUN: not ld.lld -r -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR6 %s +# ERR6: -r and -pie may not be used together ## Attempt to use -shared and -pie together -# RUN: not ld.lld -shared -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR6 %s -# ERR6: -shared and -pie may not be used together +# RUN: not ld.lld -shared -pie %t -o %tfail 2>&1 | FileCheck -check-prefix=ERR7 %s +# ERR7: -shared and -pie may not be used together ## "--output=foo" is equivalent to "-o foo". -# RUN: not ld.lld %t --output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR7 %s -# ERR7: cannot open output file /no/such/file +# RUN: not ld.lld %t --output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR8 %s +# ERR8: cannot open output file /no/such/file ## "-output=foo" is equivalent to "-o utput=foo". -# RUN: not ld.lld %t -output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR8 %s -# ERR8: cannot open output file utput=/no/such/file +# RUN: not ld.lld %t -output=/no/such/file 2>&1 | FileCheck -check-prefix=ERR9 %s +# ERR9: cannot open output file utput=/no/such/file + +# RUN: not ld.lld %t -z foo 2>&1 | FileCheck -check-prefix=ERR10 %s +# ERR10: unknown -z value: foo + +# RUN: not ld.lld %t -z max-page-size 2>&1 | FileCheck -check-prefix=ERR11 %s +# ERR11: unknown -z value: max-page-size .globl _start _start: diff --git a/test/ELF/dt_flags.s b/test/ELF/dt_flags.s index 431f83df7ab3..e160e0600378 100644 --- a/test/ELF/dt_flags.s +++ b/test/ELF/dt_flags.s @@ -2,19 +2,24 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: ld.lld -shared %t -o %t.so -# RUN: ld.lld -z now -z nodelete -z nodlopen -z origin -Bsymbolic %t %t.so -o %t1 -# RUN: ld.lld %t %t.so -o %t2 + +# RUN: ld.lld -z initfirst -z now -z nodelete -z nodlopen -z origin -Bsymbolic %t %t.so -o %t1 # RUN: llvm-readobj -dynamic-table %t1 | FileCheck -check-prefix=FLAGS %s + +# RUN: ld.lld %t %t.so -o %t2 +# RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s + +# RUN: ld.lld -z lazy %t %t.so -o %t2 # RUN: llvm-readobj -dynamic-table %t2 | FileCheck %s # FLAGS: DynamicSection [ # FLAGS: 0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW -# FLAGS: 0x000000006FFFFFFB FLAGS_1 NOW NODELETE NOOPEN ORIGIN +# FLAGS: 0x000000006FFFFFFB FLAGS_1 NOW NODELETE INITFIRST NOOPEN ORIGIN # FLAGS: ] # CHECK: DynamicSection [ -# CHECK-NOT: 0x000000000000001E FLAGS ORIGIN SYMBOLIC BIND_NOW -# CHECK-NOT: 0x000000006FFFFFFB FLAGS_1 NOW NODELETE NOOPEN ORIGIN +# CHECK-NOT: FLAGS +# CHECK-NOT: FLAGS_1 # CHECK: ] .globl _start diff --git a/test/ELF/duplicated-synthetic-sym.s b/test/ELF/duplicated-synthetic-sym.s index 92de33ec6278..bc4f5cf7650a 100644 --- a/test/ELF/duplicated-synthetic-sym.s +++ b/test/ELF/duplicated-synthetic-sym.s @@ -1,11 +1,17 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: cd %S -// RUN: not ld.lld %t.o --format=binary duplicated-synthetic-sym.s -o %t.elf 2>&1 | FileCheck %s -// RUN: not ld.lld %t.o --format binary duplicated-synthetic-sym.s -o %t.elf 2>&1 | FileCheck %s +// RUN: rm -rf %t.dir +// RUN: mkdir %t.dir +// RUN: cd %t.dir +// RUN: echo > file.bin -// CHECK: duplicate symbol: _binary_duplicated_synthetic_sym_s_start -// CHECK: defined at <internal>:(.data+0x0) +// RUN: not ld.lld %t.o --format=binary file.bin -o %t.elf 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o --format binary file.bin -o %t.elf 2>&1 | FileCheck %s - .globl _binary_duplicated_synthetic_sym_s_start -_binary_duplicated_synthetic_sym_s_start: - .long 0 +// CHECK: duplicate symbol: _binary_file_bin_start +// CHECK-NEXT: defined at {{.*}}.o:(.text+0x0) +// CHECK-NEXT: defined at file.bin:(.data+0x0) + +.globl _binary_file_bin_start +_binary_file_bin_start: + .long 0 diff --git a/test/ELF/dynamic-got-rela.s b/test/ELF/dynamic-got-rela.s index 0aeb6d477a26..b46afaae0fef 100644 --- a/test/ELF/dynamic-got-rela.s +++ b/test/ELF/dynamic-got-rela.s @@ -1,24 +1,45 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: ld.lld %t.o -o %t.so -shared -// RUN: llvm-readobj -r -s -l -section-data %t.so | FileCheck %s +// RUN: ld.lld %t.o -o %t.so -shared --apply-dynamic-relocs +// RUN: llvm-readobj -r -s -l -section-data %t.so | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s +// RUN: ld.lld %t.o -o %t2.so -shared +// RUN: llvm-readobj -r -s -l -section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s +// RUN: ld.lld %t.o -o %t2.so -shared --no-apply-dynamic-relocs +// RUN: llvm-readobj -r -s -l -section-data %t2.so | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s -// CHECK: Name: .got -// CHECK-NEXT: Type: SHT_PROGBITS -// CHECK-NEXT: Flags [ -// CHECK-NEXT: SHF_ALLOC -// CHECK-NEXT: SHF_WRITE -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x[[GOT:.*]] -// CHECK-NEXT: Offset: -// CHECK-NEXT: Size: -// CHECK-NEXT: Link: -// CHECK-NEXT: Info: -// CHECK-NEXT: AddressAlignment: -// CHECK-NEXT: EntrySize: -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00000000 00000000 | -// CHECK-NEXT: ) +// APPLYDYNREL: Name: .got +// APPLYDYNREL-NEXT: Type: SHT_PROGBITS +// APPLYDYNREL-NEXT: Flags [ +// APPLYDYNREL-NEXT: SHF_ALLOC +// APPLYDYNREL-NEXT: SHF_WRITE +// APPLYDYNREL-NEXT: ] +// APPLYDYNREL-NEXT: Address: 0x[[GOT:.*]] +// APPLYDYNREL-NEXT: Offset: +// APPLYDYNREL-NEXT: Size: +// APPLYDYNREL-NEXT: Link: +// APPLYDYNREL-NEXT: Info: +// APPLYDYNREL-NEXT: AddressAlignment: +// APPLYDYNREL-NEXT: EntrySize: +// APPLYDYNREL-NEXT: SectionData ( +// APPLYDYNREL-NEXT: 0000: 00200000 00000000 | +// APPLYDYNREL-NEXT: ) + +// NOAPPLYDYNREL: Name: .got +// NOAPPLYDYNREL-NEXT: Type: SHT_PROGBITS +// NOAPPLYDYNREL-NEXT: Flags [ +// NOAPPLYDYNREL-NEXT: SHF_ALLOC +// NOAPPLYDYNREL-NEXT: SHF_WRITE +// NOAPPLYDYNREL-NEXT: ] +// NOAPPLYDYNREL-NEXT: Address: 0x[[GOT:.*]] +// NOAPPLYDYNREL-NEXT: Offset: +// NOAPPLYDYNREL-NEXT: Size: +// NOAPPLYDYNREL-NEXT: Link: +// NOAPPLYDYNREL-NEXT: Info: +// NOAPPLYDYNREL-NEXT: AddressAlignment: +// NOAPPLYDYNREL-NEXT: EntrySize: +// NOAPPLYDYNREL-NEXT: SectionData ( +// NOAPPLYDYNREL-NEXT: 0000: 00000000 00000000 | +// NOAPPLYDYNREL-NEXT: ) // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { diff --git a/test/ELF/dynamic-got.s b/test/ELF/dynamic-got.s index 385394b9d342..844e4f48b3f7 100644 --- a/test/ELF/dynamic-got.s +++ b/test/ELF/dynamic-got.s @@ -3,6 +3,23 @@ // RUN: ld.lld --hash-style=sysv %t.o -o %t.so -shared // RUN: llvm-readobj -s -l -section-data -r %t.so | FileCheck %s +// CHECK: Name: .got.plt +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: +// CHECK-NEXT: Link: +// CHECK-NEXT: Info: +// CHECK-NEXT: AddressAlignment: +// CHECK-NEXT: EntrySize: +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 00300000 00000000 00000000 +// CHECK-NEXT: ) + // CHECK: Name: .got // CHECK-NEXT: Type: SHT_PROGBITS // CHECK-NEXT: Flags [ @@ -17,19 +34,19 @@ // CHECK-NEXT: AddressAlignment: // CHECK-NEXT: EntrySize: // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00200000 | +// CHECK-NEXT: 0000: 00300000 // CHECK-NEXT: ) // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rel.dyn { -// CHECK-NEXT: 0x2050 R_386_RELATIVE - 0x0 +// CHECK-NEXT: 0x3050 R_386_RELATIVE - 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] // CHECK: Type: PT_DYNAMIC -// CHECK-NEXT: Offset: 0x2000 -// CHECK-NEXT: VirtualAddress: 0x2000 -// CHECK-NEXT: PhysicalAddress: 0x2000 +// CHECK-NEXT: Offset: 0x3000 +// CHECK-NEXT: VirtualAddress: 0x3000 +// CHECK-NEXT: PhysicalAddress: 0x3000 calll .L0$pb .L0$pb: diff --git a/test/ELF/dynamic-linker.s b/test/ELF/dynamic-linker.s new file mode 100644 index 000000000000..3faf8e8a169e --- /dev/null +++ b/test/ELF/dynamic-linker.s @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t1.o +# RUN: ld.lld -shared %t1.o -o %t.so +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + +# RUN: ld.lld --dynamic-linker foo %t.o %t.so -o %t +# RUN: llvm-readelf -program-headers %t | FileCheck %s + +# RUN: ld.lld --dynamic-linker=foo %t.o %t.so -o %t +# RUN: llvm-readelf -program-headers %t | FileCheck %s + +# CHECK: [Requesting program interpreter: foo] + +# RUN: ld.lld %t.o %t.so -o %t +# RUN: llvm-readelf -program-headers %t | FileCheck --check-prefix=NO %s + +# RUN: ld.lld --dynamic-linker foo --no-dynamic-linker %t.o %t.so -o %t +# RUN: llvm-readelf -program-headers %t | FileCheck --check-prefix=NO %s + +# NO-NOT: PT_INTERP + +.globl _start +_start: + nop diff --git a/test/ELF/dynamic-list-archive.s b/test/ELF/dynamic-list-archive.s new file mode 100644 index 000000000000..5879bf1b0a57 --- /dev/null +++ b/test/ELF/dynamic-list-archive.s @@ -0,0 +1,17 @@ +# REQUIRES: x86 + +# RUN: rm -f %t.a +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t1.o +# RUN: llvm-ar rcs %t.a %t1.o + +# RUN: echo "{ foo; };" > %t.list + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o +# RUN: ld.lld -shared -o %t.so --dynamic-list %t.list %t.a %t2.o + +# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s +# CHECK-NOT: foo + +.global _start +_start: + nop diff --git a/test/ELF/dynamic-list-extern.s b/test/ELF/dynamic-list-extern.s index dfeb31d4fc07..bb06cebf5f52 100644 --- a/test/ELF/dynamic-list-extern.s +++ b/test/ELF/dynamic-list-extern.s @@ -4,12 +4,8 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo '{ \ -# RUN: extern "C" { \ -# RUN: foo; \ -# RUN: }; \ -# RUN: extern "C++" { \ -# RUN: bar; \ -# RUN: }; \ -# RUN: };' > %t.list +# RUN: echo '{ extern "C" { foo; }; extern "C++" { bar; }; };' > %t.list +# RUN: ld.lld --dynamic-list %t.list %t.o -shared -o %t.so + +# RUN: echo '{ extern "C" { foo }; extern "C++" { bar }; };' > %t.list # RUN: ld.lld --dynamic-list %t.list %t.o -shared -o %t.so diff --git a/test/ELF/dynamic-no-rosegment.s b/test/ELF/dynamic-no-rosegment.s index e5ad26e3fa44..f2b5f352d967 100644 --- a/test/ELF/dynamic-no-rosegment.s +++ b/test/ELF/dynamic-no-rosegment.s @@ -7,9 +7,9 @@ # CHECK-NEXT: Tag Type Name/Value # CHECK-NEXT: 0x0000000000000006 SYMTAB 0x120 # CHECK-NEXT: 0x000000000000000B SYMENT 24 (bytes) -# CHECK-NEXT: 0x0000000000000005 STRTAB 0x1D0 +# CHECK-NEXT: 0x0000000000000005 STRTAB 0x1D8 # CHECK-NEXT: 0x000000000000000A STRSZ 1 (bytes) # CHECK-NEXT: 0x000000006FFFFEF5 GNU_HASH 0x138 -# CHECK-NEXT: 0x0000000000000004 HASH 0x150 +# CHECK-NEXT: 0x0000000000000004 HASH 0x154 # CHECK-NEXT: 0x0000000000000000 NULL 0x0 # CHECK-NEXT: ] diff --git a/test/ELF/dynamic-reloc-in-ro.s b/test/ELF/dynamic-reloc-in-ro.s index ecdbfeb6658e..920f1d5fe349 100644 --- a/test/ELF/dynamic-reloc-in-ro.s +++ b/test/ELF/dynamic-reloc-in-ro.s @@ -1,8 +1,8 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_X86_64_64 against local symbol in readonly segment; recompile object files with -fPIC +// CHECK: can't create dynamic relocation R_X86_64_64 against local symbol in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK-NEXT: >>> defined in {{.*}}.o // CHECK-NEXT: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/dynamic-reloc-index.s b/test/ELF/dynamic-reloc-index.s index 47e8c6c4ef7d..0c14d3454571 100644 --- a/test/ELF/dynamic-reloc-index.s +++ b/test/ELF/dynamic-reloc-index.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so diff --git a/test/ELF/dynamic-reloc-weak.s b/test/ELF/dynamic-reloc-weak.s index b4da2e552e11..8e4840bb4c4b 100644 --- a/test/ELF/dynamic-reloc-weak.s +++ b/test/ELF/dynamic-reloc-weak.s @@ -1,9 +1,9 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc-weak.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so // RUN: ld.lld %t.o %t2.so -o %t // RUN: llvm-readobj -r %t | FileCheck %s -// REQUIRES: x86 .globl _start _start: diff --git a/test/ELF/dynamic-reloc.s b/test/ELF/dynamic-reloc.s index 4d95e41fb803..3a957ac0d05e 100644 --- a/test/ELF/dynamic-reloc.s +++ b/test/ELF/dynamic-reloc.s @@ -1,10 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/dynamic-reloc.s -o %t3.o // RUN: ld.lld -shared %t2.o -o %t2.so // RUN: ld.lld --hash-style=sysv %t.o %t3.o %t2.so -o %t // RUN: llvm-readobj -dynamic-table -r --expand-relocs -s %t | FileCheck %s -// REQUIRES: x86 // CHECK: Index: 1 // CHECK-NEXT: Name: .dynsym diff --git a/test/ELF/dynstr-no-rosegment.s b/test/ELF/dynstr-no-rosegment.s index 0e12721dac44..bad6300801e2 100644 --- a/test/ELF/dynstr-no-rosegment.s +++ b/test/ELF/dynstr-no-rosegment.s @@ -1,6 +1,6 @@ +# REQUIRES: x86 # Verify that a .dynstr in the .text segment has null byte terminators -# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld %t.o -no-rosegment -o %t.so -shared # RUN: llvm-objdump %t.so -s -j .dynstr | FileCheck %s diff --git a/test/ELF/edata-etext.s b/test/ELF/edata-etext.s index 2358399857de..52070cbc4ce3 100644 --- a/test/ELF/edata-etext.s +++ b/test/ELF/edata-etext.s @@ -10,10 +10,11 @@ ## greater than the address of _etext, the address of _end is same as the address ## of _edata." (https://docs.oracle.com/cd/E53394_01/html/E54766/u-etext-3c.html). ## 3) Address of _end is different from _edata because of 2. +## 4) Addresses of _edata == edata, _end == end and _etext == etext. # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .text 00000001 0000000000201000 TEXT DATA +# CHECK-NEXT: 1 .text 00000001 0000000000201000 TEXT # CHECK-NEXT: 2 .data 00000002 0000000000202000 DATA # CHECK-NEXT: 3 .bss 00000006 0000000000202004 BSS # CHECK: SYMBOL TABLE: @@ -22,6 +23,9 @@ # CHECK-NEXT: 000000000020200a .bss 00000000 _end # CHECK-NEXT: 0000000000201001 .text 00000000 _etext # CHECK-NEXT: 0000000000201000 .text 00000000 _start +# CHECK-NEXT: 0000000000202002 .data 00000000 edata +# CHECK-NEXT: 000000000020200a .bss 00000000 end +# CHECK-NEXT: 0000000000201001 .text 00000000 etext # RUN: ld.lld -r %t.o -o %t2 # RUN: llvm-objdump -t %t2 | FileCheck %s --check-prefix=RELOCATABLE @@ -29,7 +33,7 @@ # RELOCATABLE-NEXT: 0000000000000000 *UND* 00000000 _end # RELOCATABLE-NEXT: 0000000000000000 *UND* 00000000 _etext -.global _start,_end,_etext,_edata +.global _start,_end,_etext,_edata,end,etext,edata .text _start: nop diff --git a/test/ELF/eh-frame-dyn-rel.s b/test/ELF/eh-frame-dyn-rel.s index 289e6c0150d2..f54e62b5eedc 100644 --- a/test/ELF/eh-frame-dyn-rel.s +++ b/test/ELF/eh-frame-dyn-rel.s @@ -1,8 +1,8 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: not ld.lld %t.o %t.o -o %t -shared 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o %t.o -o /dev/null -shared 2>&1 | FileCheck %s -// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo +// CHECK: can't create dynamic relocation R_X86_64_64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output // CHECK: >>> defined in {{.*}}.o // CHECK: >>> referenced by {{.*}}.o:(.eh_frame+0x12) diff --git a/test/ELF/eh-frame-hdr-abs-fde.s b/test/ELF/eh-frame-hdr-abs-fde.s index c3dc862ceb49..7f75058d4b35 100644 --- a/test/ELF/eh-frame-hdr-abs-fde.s +++ b/test/ELF/eh-frame-hdr-abs-fde.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check reading PC values of FDEs and writing lookup table in the .eh_frame_hdr # if CIE augmentation string has 'L' token and PC values are encoded using # absolute (not relative) format. @@ -6,8 +7,6 @@ # RUN: ld.lld --eh-frame-hdr %t.o -o %t # RUN: llvm-objdump -s -dwarf=frames %t | FileCheck %s -# REQUIRES: mips - # CHECK: Contents of section .eh_frame_hdr: # CHECK-NEXT: 10128 011b033b 00000010 00000001 0000fed8 # ^-- 0x20000 - 0x10138 diff --git a/test/ELF/eh-frame-hdr-augmentation.s b/test/ELF/eh-frame-hdr-augmentation.s index 135f8119662a..934f9200a27c 100644 --- a/test/ELF/eh-frame-hdr-augmentation.s +++ b/test/ELF/eh-frame-hdr-augmentation.s @@ -11,6 +11,7 @@ // CHECK-NEXT: Code alignment factor: 1 // CHECK-NEXT: Data alignment factor: -8 // CHECK-NEXT: Return address column: 16 +// CHECK-NEXT: Personality Address: 00000dad // CHECK-NEXT: Augmentation data: // CHECK: DW_CFA_def_cfa: reg7 +8 @@ -19,6 +20,7 @@ // CHECK-NEXT: DW_CFA_nop: // CHECK: 00000020 00000014 00000024 FDE cie=00000024 pc=00000d98...00000d98 +// CHECK-NEXT: LSDA Address: 00000d8f // CHECK-NEXT: DW_CFA_nop: // CHECK-NEXT: DW_CFA_nop: // CHECK-NEXT: DW_CFA_nop: diff --git a/test/ELF/eh-frame-hdr-icf-fde.s b/test/ELF/eh-frame-hdr-icf-fde.s index 54c2cd8bf8c9..68de65d5724c 100644 --- a/test/ELF/eh-frame-hdr-icf-fde.s +++ b/test/ELF/eh-frame-hdr-icf-fde.s @@ -52,7 +52,7 @@ # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x200178 # CHECK-NEXT: Offset: 0x178 -# CHECK-NEXT: Size: 72 +# CHECK-NEXT: Size: 76 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 8 @@ -62,7 +62,7 @@ # CHECK-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000 # CHECK-NEXT: 0020: 680E0000 01000000 00000000 00000000 # CHECK-NEXT: 0030: 14000000 34000000 520E0000 01000000 -# CHECK-NEXT: 0040: 00000000 00000000 +# CHECK-NEXT: 0040: 00000000 00000000 00000000 # CHECK-NEXT: ) # CHECK-NEXT: } diff --git a/test/ELF/eh-frame-hdr.s b/test/ELF/eh-frame-hdr.s index 4498d7d30eaa..0c33bc6dde3e 100644 --- a/test/ELF/eh-frame-hdr.s +++ b/test/ELF/eh-frame-hdr.s @@ -60,7 +60,7 @@ _start: // HDR-NEXT: Size: 36 // HDR-NEXT: Link: 0 // HDR-NEXT: Info: 0 -// HDR-NEXT: AddressAlignment: 1 +// HDR-NEXT: AddressAlignment: 4 // HDR-NEXT: EntrySize: 0 // HDR-NEXT: SectionData ( // HDR-NEXT: 0000: 011B033B 24000000 03000000 A80E0000 @@ -92,7 +92,7 @@ _start: // HDR-NEXT: ] // HDR-NEXT: Address: 0x200180 // HDR-NEXT: Offset: 0x180 -// HDR-NEXT: Size: 96 +// HDR-NEXT: Size: 100 // HDR-NEXT: Link: 0 // HDR-NEXT: Info: 0 // HDR-NEXT: AddressAlignment: 8 @@ -104,6 +104,7 @@ _start: // HDR-NEXT: 0030: 14000000 34000000 490E0000 01000000 // HDR-NEXT: 0040: 00000000 00000000 14000000 4C000000 // HDR-NEXT: 0050: 320E0000 01000000 00000000 00000000 +// HDR-NEXT: 0060: 00000000 // HDR-NEXT: ) // CIE: 14000000 00000000 017A5200 01781001 1B0C0708 90010000 // FDE(1): 14000000 1C000000 600E0000 01000000 00000000 00000000 @@ -130,5 +131,5 @@ _start: // HDR-NEXT: Flags [ // HDR-NEXT: PF_R // HDR-NEXT: ] -// HDR-NEXT: Alignment: 1 +// HDR-NEXT: Alignment: 4 // HDR-NEXT: } diff --git a/test/ELF/eh-frame-marker.s b/test/ELF/eh-frame-marker.s index 30bac460ae25..f5696bdef36f 100644 --- a/test/ELF/eh-frame-marker.s +++ b/test/ELF/eh-frame-marker.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld --eh-frame-hdr %t.o -o %t.so -shared // RUN: llvm-readobj -t -s %t.so | FileCheck %s diff --git a/test/ELF/eh-frame-merge.s b/test/ELF/eh-frame-merge.s index 4b54c173c699..6731d90f844b 100644 --- a/test/ELF/eh-frame-merge.s +++ b/test/ELF/eh-frame-merge.s @@ -27,7 +27,7 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: // CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 96 +// CHECK-NEXT: Size: 100 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 8 @@ -39,6 +39,7 @@ // CHECK-NEXT: 0030: 14000000 34000000 D20D0000 02000000 | // CHECK-NEXT: 0040: 00000000 00000000 14000000 4C000000 | // CHECK-NEXT: 0050: B90D0000 01000000 00000000 00000000 | +// CHECK-NEXT: 0060: 00000000 // CHECK-NEXT: ) // CHECK: Name: foo diff --git a/test/ELF/eh-frame-multilpe-cie.s b/test/ELF/eh-frame-multilpe-cie.s index 12781ff5b6e9..a52e686d9d15 100644 --- a/test/ELF/eh-frame-multilpe-cie.s +++ b/test/ELF/eh-frame-multilpe-cie.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux -// RUN: ld.lld --eh-frame-hdr %t.o -o %t.so -shared +// RUN: ld.lld --eh-frame-hdr %t.o -o /dev/null -shared // We would fail to parse multiple cies in the same file. .cfi_startproc diff --git a/test/ELF/eh-frame-negative-pcrel-sdata2.s b/test/ELF/eh-frame-negative-pcrel-sdata2.s new file mode 100644 index 000000000000..30ee8560f0a3 --- /dev/null +++ b/test/ELF/eh-frame-negative-pcrel-sdata2.s @@ -0,0 +1,85 @@ +# REQUIRES: x86 + +# Test handling of FDE pc negative relative addressing with DW_EH_PE_sdata2. +# This situation can arise when .eh_frame is placed after .text. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script +# RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t +# RUN: llvm-readobj -s -section-data %t | FileCheck %s + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1001 +# CHECK-NEXT: Offset: 0x1001 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 14000000 00000000 017A5200 01010101 +# CHECK-NEXT: 0010: 1A000000 00000000 0C000000 1C000000 +# CHECK-NEXT: 0020: DFFFFFFF +# ^ +# DFFFFFFF = _start(0x1000) - PC(.eh_frame(0x1001) + 0x20) + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame_hdr +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1030 +# CHECK-NEXT: Offset: 0x1030 +# CHECK-NEXT: Size: 20 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 011B033B CDFFFFFF 01000000 D0FFFFFF +# CHECK-NEXT: 0010: E9FFFFFF +# Header (always 4 bytes): 011B033B +# CDFFFFFF = .eh_frame(0x1001) - .eh_frame_hdr(0x1030) - 4 +# 01000000 = 1 = the number of FDE pointers in the table. +# D0FFFFFF = _start(0x1000) - .eh_frame_hdr(0x1030) +# E9FFFFFF = FDE(.eh_frame(0x1001) + 0x18) - .eh_frame_hdr(0x1030) + +.text +.global _start +_start: + nop + +.section .eh_frame, "a" + .long 16 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x7A # Augmentation string: "zR" + .byte 0x52 + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x01 # LEB128 + .byte 0x1A # DW_EH_PE_pcrel | DW_EH_PE_sdata2 + + .byte 0x00 + .byte 0x00 + .byte 0x00 + + .long 10 # Size + .long 24 # ID +fde: + .long _start - fde + .word 0 diff --git a/test/ELF/eh-frame-negative-pcrel-sdata4.s b/test/ELF/eh-frame-negative-pcrel-sdata4.s new file mode 100644 index 000000000000..71b91cf1f4a6 --- /dev/null +++ b/test/ELF/eh-frame-negative-pcrel-sdata4.s @@ -0,0 +1,85 @@ +# REQUIRES: x86 + +# Test handling of FDE pc negative relative addressing with DW_EH_PE_sdata4. +# This situation can arise when .eh_frame is placed after .text. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script +# RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t +# RUN: llvm-readobj -s -section-data %t | FileCheck %s + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1001 +# CHECK-NEXT: Offset: 0x1001 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 14000000 00000000 017A5200 01010101 +# CHECK-NEXT: 0010: 1B000000 00000000 0C000000 1C000000 +# CHECK-NEXT: 0020: DFFFFFFF +# ^ +# DFFFFFFF = _start(0x1000) - PC(.eh_frame(0x1001) + 0x20) + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame_hdr +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1030 +# CHECK-NEXT: Offset: 0x1030 +# CHECK-NEXT: Size: 20 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 011B033B CDFFFFFF 01000000 D0FFFFFF +# CHECK-NEXT: 0010: E9FFFFFF +# Header (always 4 bytes): 011B033B +# CDFFFFFF = .eh_frame(0x1001) - .eh_frame_hdr(0x1030) - 4 +# 01000000 = 1 = the number of FDE pointers in the table. +# D0FFFFFF = _start(0x1000) - .eh_frame_hdr(0x1030) +# E9FFFFFF = FDE(.eh_frame(0x1001) + 0x18) - .eh_frame_hdr(0x1030) + +.text +.global _start +_start: + nop + +.section .eh_frame, "a" + .long 16 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x7A # Augmentation string: "zR" + .byte 0x52 + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x01 # LEB128 + .byte 0x1B # DW_EH_PE_pcrel | DW_EH_PE_sdata4 + + .byte 0x00 + .byte 0x00 + .byte 0x00 + + .long 12 # Size + .long 24 # ID +fde: + .long _start - fde + .long 0 diff --git a/test/ELF/eh-frame-negative-pcrel-sdata8.s b/test/ELF/eh-frame-negative-pcrel-sdata8.s new file mode 100644 index 000000000000..2c6c9f27cd38 --- /dev/null +++ b/test/ELF/eh-frame-negative-pcrel-sdata8.s @@ -0,0 +1,85 @@ +# REQUIRES: x86 + +# Test handling of FDE pc negative relative addressing with DW_EH_PE_sdata8. +# This situation can arise when .eh_frame is placed after .text. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { .text : { *(.text) } .eh_frame : { *(.eh_frame) } }" > %t.script +# RUN: ld.lld --eh-frame-hdr --script %t.script --section-start .text=0x1000 %t.o -o %t +# RUN: llvm-readobj -s -section-data %t | FileCheck %s + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1001 +# CHECK-NEXT: Offset: 0x1001 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 14000000 00000000 017A5200 01010101 +# CHECK-NEXT: 0010: 1C000000 00000000 14000000 1C000000 +# CHECK-NEXT: 0020: DFFFFFFF FFFFFFFF +# ^ +# DFFFFFFF FFFFFFFF = _start(0x1000) - PC(.eh_frame(0x1001) + 0x20) + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame_hdr +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1038 +# CHECK-NEXT: Offset: 0x1038 +# CHECK-NEXT: Size: 20 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 011B033B C5FFFFFF 01000000 C8FFFFFF +# CHECK-NEXT: 0010: E1FFFFFF +# Header (always 4 bytes): 011B033B +# C5FFFFFF = .eh_frame(0x1001) - .eh_frame_hdr(0x1038) - 4 +# 01000000 = 1 = the number of FDE pointers in the table. +# C8FFFFFF = _start(0x1000) - .eh_frame_hdr(0x1038) +# E1FFFFFF = FDE(.eh_frame(0x1001) + 0x18) - .eh_frame_hdr(0x1038) + +.text +.global _start +_start: + nop + +.section .eh_frame, "a" + .long 16 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x7A # Augmentation string: "zR" + .byte 0x52 + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x01 # LEB128 + .byte 0x1C # DW_EH_PE_pcrel | DW_EH_PE_sdata8 + + .byte 0x00 + .byte 0x00 + .byte 0x00 + + .long 16 # Size + .long 24 # ID +fde: + .quad _start - fde + .long 0 diff --git a/test/ELF/eh-frame-padding-no-rosegment.s b/test/ELF/eh-frame-padding-no-rosegment.s index e106f2989d4b..222ce0da6ca9 100644 --- a/test/ELF/eh-frame-padding-no-rosegment.s +++ b/test/ELF/eh-frame-padding-no-rosegment.s @@ -7,6 +7,7 @@ .global bar .hidden bar bar: + ret // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o @@ -37,8 +38,7 @@ bar: // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=PHDR %s // PHDR: Segment Sections -// PHDR: .text -// PHDR-SAME: .eh_frame +// PHDR: .eh_frame {{.*}}.text // Check that the CIE and FDE are padded with 0x00 and not 0xCC when the // .eh_frame section is placed in the executable segment @@ -58,7 +58,7 @@ bar: // CHECK-NEXT: EntrySize: // CHECK-NEXT: SectionData ( // CHECK-NEXT: 0000: 1C000000 00000000 017A5052 00017810 -// CHECK-NEXT: 0010: 061BBEFF FFFF1B0C 07089001 00000000 -// CHECK-NEXT: 0020: 14000000 24000000 A8FFFFFF 00000000 +// CHECK-NEXT: 0010: 061B2A00 00001B0C 07089001 00000000 +// CHECK-NEXT: 0020: 14000000 24000000 14000000 00000000 // CHECK-NEXT: 0030: 00000000 00000000 // CHECK-NEXT: ) diff --git a/test/ELF/eh-frame-pcrel-overflow.s b/test/ELF/eh-frame-pcrel-overflow.s new file mode 100644 index 000000000000..9b88edab2a93 --- /dev/null +++ b/test/ELF/eh-frame-pcrel-overflow.s @@ -0,0 +1,33 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/eh-frame-pcrel-overflow.s -o %t1.o +# RUN: ld.lld --eh-frame-hdr -Ttext=0x90000000 %t.o -o /dev/null +# RUN: not ld.lld --eh-frame-hdr %t.o %t1.o -o /dev/null 2>&1 | FileCheck %s +# CHECK: error: {{.*}}.o:(.eh_frame): PC offset is too large: 0x90000eac + +.text +.global _start +_start: + ret + +.section .eh_frame, "a" + .long 12 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x52 # Augmentation string: 'R','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x00 # DW_EH_PE_absptr + + .byte 0xFF + + .long 12 # Size + .long 0x14 # ID + .quad _start + 0x70000000 diff --git a/test/ELF/eh-frame-rel.s b/test/ELF/eh-frame-rel.s index a417dc126087..d633e6a082ec 100644 --- a/test/ELF/eh-frame-rel.s +++ b/test/ELF/eh-frame-rel.s @@ -1,6 +1,6 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o -// RUN: ld.lld %t.o %t.o -o %t -shared +// RUN: ld.lld %t.o %t.o -o /dev/null -shared // We used to try to read the relocations as RELA and error out .cfi_startproc diff --git a/test/ELF/eh-frame-value-format1.s b/test/ELF/eh-frame-value-format1.s new file mode 100644 index 000000000000..a8bcffb4fe4f --- /dev/null +++ b/test/ELF/eh-frame-value-format1.s @@ -0,0 +1,35 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld --eh-frame-hdr %t -o /dev/null + +.section .eh_frame + .byte 0x14 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x04 # DW_EH_PE_udata8 + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + + .byte 0xFF diff --git a/test/ELF/eh-frame-value-format2.s b/test/ELF/eh-frame-value-format2.s new file mode 100644 index 000000000000..6d2d82e267c7 --- /dev/null +++ b/test/ELF/eh-frame-value-format2.s @@ -0,0 +1,35 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld --eh-frame-hdr %t -o /dev/null + +.section .eh_frame + .byte 0x14 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x0C # DW_EH_PE_sdata8 + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + + .byte 0xFF diff --git a/test/ELF/eh-frame-value-format3.s b/test/ELF/eh-frame-value-format3.s new file mode 100644 index 000000000000..1f174ae60a0d --- /dev/null +++ b/test/ELF/eh-frame-value-format3.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld --eh-frame-hdr %t -o /dev/null + +.section .eh_frame + .byte 0x0E + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x0A # DW_EH_PE_sdata2 + .byte 0xFF + .byte 0xFF + .byte 0xFF diff --git a/test/ELF/eh-frame-value-format4.s b/test/ELF/eh-frame-value-format4.s new file mode 100644 index 000000000000..d10988a4fc86 --- /dev/null +++ b/test/ELF/eh-frame-value-format4.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld --eh-frame-hdr %t -o /dev/null + +.section .eh_frame + .byte 0x0E + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x02 # DW_EH_PE_udata2 + .byte 0xFF + .byte 0xFF + .byte 0xFF diff --git a/test/ELF/eh-frame-value-format5.s b/test/ELF/eh-frame-value-format5.s new file mode 100644 index 000000000000..fd5b35a8b05e --- /dev/null +++ b/test/ELF/eh-frame-value-format5.s @@ -0,0 +1,35 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld --eh-frame-hdr %t -o /dev/null + +.section .eh_frame + .byte 0x14 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x08 # DW_EH_PE_signed + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + + .byte 0xFF diff --git a/test/ELF/eh-frame-value-format6.s b/test/ELF/eh-frame-value-format6.s new file mode 100644 index 000000000000..ee76fa7a050f --- /dev/null +++ b/test/ELF/eh-frame-value-format6.s @@ -0,0 +1,35 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: ld.lld --eh-frame-hdr %t -o /dev/null + +.section .eh_frame + .byte 0x14 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x00 # DW_EH_PE_absptr + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + .byte 0xFF + + .byte 0xFF diff --git a/test/ELF/eh-frame-value-format7.s b/test/ELF/eh-frame-value-format7.s new file mode 100644 index 000000000000..90543a2b72f2 --- /dev/null +++ b/test/ELF/eh-frame-value-format7.s @@ -0,0 +1,75 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld --eh-frame-hdr --section-start .text=0x1000 %t.o -o %t +# RUN: llvm-readobj -s -section-data %t | FileCheck %s + +## Check we are able to handle DW_EH_PE_udata2 encoding. + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame_hdr +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2000 +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: Size: 20 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 011B033B 10000000 01000000 34F2FFFF +# CHECK-NEXT: 0010: 24000000 +# Header (always 4 bytes): 011B033B +# 10000000 = .eh_frame(0x2014) - .eh_frame_hdr(0x2000) - 4 +# 01000000 = 1 = the number of FDE pointers in the table. +# 34F2FFFF = foo(0x1000) - 0x234(addend) - .eh_frame_hdr(0x2000) + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2014 +# CHECK-NEXT: Offset: 0x2014 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 0C000000 00000000 01520001 010102FF +# CHECK-NEXT: 0010: 0C000000 14000000 34120000 00000000 +# ^ +# ---> ADDR(foo) + 0x234 = 0x1234 + +.text +.global foo +foo: + nop + +.section .eh_frame + .long 12 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x52 # Augmentation string: 'R','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x02 # DW_EH_PE_udata2 + + .byte 0xFF + + .long 0x6 # Size + .long 0x14 # ID + .short foo + 0x234 diff --git a/test/ELF/eh-frame-value-format8.s b/test/ELF/eh-frame-value-format8.s new file mode 100644 index 000000000000..60324706665e --- /dev/null +++ b/test/ELF/eh-frame-value-format8.s @@ -0,0 +1,74 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld --eh-frame-hdr --section-start .text=0x1000 %t.o -o %t +# RUN: llvm-readobj -s -section-data %t | FileCheck %s + +## Check we are able to handle DW_EH_PE_absptr encoding. + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame_hdr +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2000 +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: Size: 20 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 011B033B 10000000 01000000 34F2FFFF +# CHECK-NEXT: 0010: 24000000 +# Header (always 4 bytes): 011B033B +# 10000000 = .eh_frame(0x2014) - .eh_frame_hdr(0x2000) - 4 +# 01000000 = 1 = the number of FDE pointers in the table. +# 34F2FFFF = foo(0x1000) - 0x234(addend) - .eh_frame_hdr(0x2000) + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .eh_frame +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2014 +# CHECK-NEXT: Offset: 0x2014 +# CHECK-NEXT: Size: +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 0C000000 00000000 01520001 010100FF +# CHECK-NEXT: 0010: 0C000000 14000000 34120000 00000000 +# ^ +# ---> ADDR(foo) + 0x234 = 0x1234 +.text +.global foo +foo: + nop + +.section .eh_frame, "ax" + .long 12 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x52 # Augmentation string: 'R','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x00 # DW_EH_PE_absptr + + .byte 0xFF + + .long 12 # Size + .long 0x14 # ID + .quad foo + 0x234 diff --git a/test/ELF/eh-frame-value-format9.s b/test/ELF/eh-frame-value-format9.s new file mode 100644 index 000000000000..1b9ce6944eea --- /dev/null +++ b/test/ELF/eh-frame-value-format9.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld --eh-frame-hdr %t.o -o %t 2>&1 | FileCheck %s +# CHECK: error: unknown FDE size encoding + +.section .eh_frame, "ax" + .long 12 # Size + .long 0x00 # ID + .byte 0x01 # Version. + + .byte 0x52 # Augmentation string: 'R','\0' + .byte 0x00 + +# Code and data alignment factors. + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + +# Return address register. + .byte 0x01 # LEB128 + + .byte 0xFE # 'R' value: invalid <0xFE> + + .byte 0xFF + + .long 12 # Size + .long 0x14 # ID + .quad .eh_frame diff --git a/test/ELF/ehframe-relocation.s b/test/ELF/ehframe-relocation.s index 0213b1bebf83..4ab44c20f8ae 100644 --- a/test/ELF/ehframe-relocation.s +++ b/test/ELF/ehframe-relocation.s @@ -12,7 +12,7 @@ // CHECK-NEXT: ] // CHECK-NEXT: Address: 0x200120 // CHECK-NEXT: Offset: -// CHECK-NEXT: Size: 48 +// CHECK-NEXT: Size: 52 // CHECK-NOT: .eh_frame // 0x200120 = 2097440 diff --git a/test/ELF/elf-header.s b/test/ELF/elf-header.s new file mode 100644 index 000000000000..e188650f7311 --- /dev/null +++ b/test/ELF/elf-header.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t1 +# RUN: llvm-readobj -file-headers %t1 | FileCheck %s + +# RUN: ld.lld %t.o -no-rosegment -o %t2 +# RUN: llvm-readobj -file-headers %t2 | FileCheck %s + +# CHECK: ElfHeader { +# CHECK-NEXT: Ident { +# CHECK-NEXT: Magic: (7F 45 4C 46) +# CHECK-NEXT: Class: 64-bit (0x2) +# CHECK-NEXT: DataEncoding: LittleEndian (0x1) +# CHECK-NEXT: FileVersion: 1 +# CHECK-NEXT: OS/ABI: SystemV (0x0) +# CHECK-NEXT: ABIVersion: 0 +# CHECK-NEXT: Unused: (00 00 00 00 00 00 00) +# CHECK-NEXT: } diff --git a/test/ELF/emit-relocs-eh-frame.s b/test/ELF/emit-relocs-eh-frame.s new file mode 100644 index 000000000000..4df88585d341 --- /dev/null +++ b/test/ELF/emit-relocs-eh-frame.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: ld.lld --emit-relocs %t1.o -o %t +# RUN: llvm-readobj -r %t | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.eh_frame { +# CHECK-NEXT: 0x{{.*}} R_X86_64_PC32 .text 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.text +.globl foo +foo: + .cfi_startproc + .cfi_endproc diff --git a/test/ELF/emit-relocs-gc.s b/test/ELF/emit-relocs-gc.s index 0741e78ab955..9379630e7bff 100644 --- a/test/ELF/emit-relocs-gc.s +++ b/test/ELF/emit-relocs-gc.s @@ -11,8 +11,8 @@ ## .rela.text because we keep .text. # RUN: ld.lld --gc-sections --emit-relocs --print-gc-sections %t.o -o %t \ # RUN: | FileCheck --check-prefix=MSG %s -# MSG: removing unused section from '.bar' in file -# MSG: removing unused section from '.rela.bar' in file +# MSG: removing unused section {{.*}}.o:(.bar) +# MSG: removing unused section {{.*}}.o:(.rela.bar) # RUN: llvm-objdump %t -section-headers | FileCheck %s --check-prefix=GC # GC-NOT: rela.bar # GC: rela.text diff --git a/test/ELF/emit-relocs-icf.s b/test/ELF/emit-relocs-icf.s new file mode 100644 index 000000000000..59e003f38ead --- /dev/null +++ b/test/ELF/emit-relocs-icf.s @@ -0,0 +1,33 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: ld.lld --emit-relocs --icf=all %t1.o -o %t +# RUN: llvm-readobj -r %t | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section {{.*}} .rela.text { +# CHECK-NEXT: R_X86_64_32 .text 0x1 +# CHECK-NEXT: R_X86_64_PLT32 fn 0xFFFFFFFFFFFFFFFC +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.section .text.fn,"ax",@progbits,unique,0 +.globl fn +.type fn,@function +fn: + nop + +bar: + movl $bar, %edx + callq fn@PLT + nop + +.section .text.fn2,"ax",@progbits,unique,1 +.globl fn2 +.type fn2,@function +fn2: + nop + +foo: + movl $foo, %edx + callq fn2@PLT + nop diff --git a/test/ELF/emit-relocs-shared.s b/test/ELF/emit-relocs-shared.s index 65a12c15ee2e..cb87d9f84805 100644 --- a/test/ELF/emit-relocs-shared.s +++ b/test/ELF/emit-relocs-shared.s @@ -7,10 +7,10 @@ .quad foo # CHECK: Relocations [ -# CHECK-NEXT: Section (4) .rela.dyn { +# CHECK-NEXT: Section {{.*}} .rela.dyn { # CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 # CHECK-NEXT: } -# CHECK-NEXT: Section (8) .rela.data { +# CHECK-NEXT: Section {{.*}} .rela.data { # CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] diff --git a/test/ELF/emit-relocs.s b/test/ELF/emit-relocs.s index 95e70d80acf5..b91bb9abe182 100644 --- a/test/ELF/emit-relocs.s +++ b/test/ELF/emit-relocs.s @@ -13,7 +13,7 @@ # CHECK: Section { # CHECK: Index: 2 -# CHECK-NEXT: Name: .rela.text +# CHECK: Name: .rela.text # CHECK-NEXT: Type: SHT_RELA # CHECK-NEXT: Flags [ # CHECK-NEXT: SHF_INFO_LINK diff --git a/test/ELF/empty-archive.s b/test/ELF/empty-archive.s index ffb0a7814419..72232415a588 100644 --- a/test/ELF/empty-archive.s +++ b/test/ELF/empty-archive.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-ar rc %t.a // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: ld.lld -shared %t.o %t.a -o t +// RUN: ld.lld -shared %t.o %t.a -o /dev/null diff --git a/test/ELF/empty-ver2.s b/test/ELF/empty-ver2.s new file mode 100644 index 000000000000..2aceee128ba3 --- /dev/null +++ b/test/ELF/empty-ver2.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: mkdir -p %t.dir +# RUN: cd %t.dir +# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux +# RUN: ld.lld %t.o -o t.so -shared -version-script %p/Inputs/empty-ver.ver +# RUN: llvm-readobj -version-info t.so | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: @ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Name: bar@@ +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.global bar@ +bar@: diff --git a/test/ELF/emulation.s b/test/ELF/emulation.s index 05efd0b94cb2..98f78b8ec1df 100644 --- a/test/ELF/emulation.s +++ b/test/ELF/emulation.s @@ -1,3 +1,4 @@ +# REQUIRES: x86,ppc,mips,aarch64 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %tx64 # RUN: ld.lld -m elf_amd64_fbsd %tx64 -o %t2x64 # RUN: llvm-readobj -file-headers %t2x64 | FileCheck --check-prefix=AMD64 %s @@ -208,7 +209,8 @@ # PPC64-NEXT: Entry: # PPC64-NEXT: ProgramHeaderOffset: 0x40 # PPC64-NEXT: SectionHeaderOffset: -# PPC64-NEXT: Flags [ (0x0) +# PPC64-NEXT: Flags [ (0x2) +# PPC64-NEXT: 0x2 # PPC64-NEXT: ] # PPC64-NEXT: HeaderSize: 64 # PPC64-NEXT: ProgramHeaderEntrySize: 56 @@ -218,6 +220,38 @@ # PPC64-NEXT: StringTableSectionIndex: # PPC64-NEXT: } +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %tppc64le +# RUN: ld.lld -m elf64lppc %tppc64le -o %t2ppc64le +# RUN: llvm-readobj -file-headers %t2ppc64le | FileCheck --check-prefix=PPC64LE %s +# RUN: ld.lld %tppc64le -o %t3ppc64le +# RUN: llvm-readobj -file-headers %t3ppc64le | FileCheck --check-prefix=PPC64LE %s +# PPC64LE: ElfHeader { +# PPC64LE-NEXT: Ident { +# PPC64LE-NEXT: Magic: (7F 45 4C 46) +# PPC64LE-NEXT: Class: 64-bit (0x2) +# PPC64LE-NEXT: DataEncoding: LittleEndian (0x1) +# PPC64LE-NEXT: FileVersion: 1 +# PPC64LE-NEXT: OS/ABI: SystemV (0x0) +# PPC64LE-NEXT: ABIVersion: 0 +# PPC64LE-NEXT: Unused: (00 00 00 00 00 00 00) +# PPC64LE-NEXT: } +# PPC64LE-NEXT: Type: Executable (0x2) +# PPC64LE-NEXT: Machine: EM_PPC64 (0x15) +# PPC64LE-NEXT: Version: 1 +# PPC64LE-NEXT: Entry: +# PPC64LE-NEXT: ProgramHeaderOffset: 0x40 +# PPC64LE-NEXT: SectionHeaderOffset: +# PPC64LE-NEXT: Flags [ (0x2) +# PPC64LE-NEXT: 0x2 +# PPC64LE-NEXT: ] +# PPC64LE-NEXT: HeaderSize: 64 +# PPC64LE-NEXT: ProgramHeaderEntrySize: 56 +# PPC64LE-NEXT: ProgramHeaderCount: +# PPC64LE-NEXT: SectionHeaderEntrySize: 64 +# PPC64LE-NEXT: SectionHeaderCount: +# PPC64LE-NEXT: StringTableSectionIndex: +# PPC64LE-NEXT: } + # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %tmips # RUN: ld.lld -m elf32btsmip -e _start %tmips -o %t2mips # RUN: llvm-readobj -file-headers %t2mips | FileCheck --check-prefix=MIPS %s @@ -230,7 +264,7 @@ # MIPS-NEXT: DataEncoding: BigEndian (0x2) # MIPS-NEXT: FileVersion: 1 # MIPS-NEXT: OS/ABI: SystemV (0x0) -# MIPS-NEXT: ABIVersion: 0 +# MIPS-NEXT: ABIVersion: 1 # MIPS-NEXT: Unused: (00 00 00 00 00 00 00) # MIPS-NEXT: } # MIPS-NEXT: Type: Executable (0x2) @@ -259,7 +293,7 @@ # MIPSEL-NEXT: DataEncoding: LittleEndian (0x1) # MIPSEL-NEXT: FileVersion: 1 # MIPSEL-NEXT: OS/ABI: SystemV (0x0) -# MIPSEL-NEXT: ABIVersion: 0 +# MIPSEL-NEXT: ABIVersion: 1 # MIPSEL-NEXT: Unused: (00 00 00 00 00 00 00) # MIPSEL-NEXT: } # MIPSEL-NEXT: Type: Executable (0x2) @@ -333,8 +367,12 @@ # RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %taarch64 # RUN: ld.lld -m aarch64linux %taarch64 -o %t2aarch64 # RUN: llvm-readobj -file-headers %t2aarch64 | FileCheck --check-prefix=AARCH64 %s -# RUN: ld.lld %taarch64 -o %t3aarch64 +# RUN: ld.lld -m aarch64elf %taarch64 -o %t3aarch64 # RUN: llvm-readobj -file-headers %t3aarch64 | FileCheck --check-prefix=AARCH64 %s +# RUN: ld.lld -m aarch64_elf64_le_vec %taarch64 -o %t4aarch64 +# RUN: llvm-readobj -file-headers %t4aarch64 | FileCheck --check-prefix=AARCH64 %s +# RUN: ld.lld %taarch64 -o %t5aarch64 +# RUN: llvm-readobj -file-headers %t5aarch64 | FileCheck --check-prefix=AARCH64 %s # AARCH64: ElfHeader { # AARCH64-NEXT: Ident { # AARCH64-NEXT: Magic: (7F 45 4C 46) @@ -354,7 +392,5 @@ # AARCH64-NEXT: Flags [ (0x0) # AARCH64-NEXT: ] -# REQUIRES: x86,ppc,mips,aarch64 - .globl _start _start: diff --git a/test/ELF/end-preserve.s b/test/ELF/end-preserve.s index 71d86d1c8faf..d25170605cb3 100644 --- a/test/ELF/end-preserve.s +++ b/test/ELF/end-preserve.s @@ -1,5 +1,5 @@ -// Should preserve the value of the "end" symbol if it is defined. // REQUIRES: x86 +// Should preserve the value of the "end" symbol if it is defined. // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -o %t diff --git a/test/ELF/end-update.s b/test/ELF/end-update.s index afb137fd2d73..9ece23ce9ac2 100644 --- a/test/ELF/end-update.s +++ b/test/ELF/end-update.s @@ -1,5 +1,5 @@ -// Should set the value of the "end" symbol if it is undefined. // REQUIRES: x86 +// Should set the value of the "end" symbol if it is undefined. // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -o %t diff --git a/test/ELF/end.s b/test/ELF/end.s index f40c5db8b5ff..530a00783704 100644 --- a/test/ELF/end.s +++ b/test/ELF/end.s @@ -1,5 +1,5 @@ -// Should set the value of the "_end" symbol to the end of the data segment. // REQUIRES: x86 +// Should set the value of the "_end" symbol to the end of the data segment. // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o diff --git a/test/ELF/entry.s b/test/ELF/entry.s index f288bcf6ae50..cc7a7248f082 100644 --- a/test/ELF/entry.s +++ b/test/ELF/entry.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 # RUN: ld.lld -e foobar %t1 -o %t2 2>&1 | FileCheck -check-prefix=WARN1 %s diff --git a/test/ELF/exclude-libs.s b/test/ELF/exclude-libs.s index dc7530068586..c061c484b344 100644 --- a/test/ELF/exclude-libs.s +++ b/test/ELF/exclude-libs.s @@ -3,9 +3,10 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ // RUN: %p/Inputs/exclude-libs.s -o %t2.o +// RUN: llvm-as --data-layout=elf %p/Inputs/exclude-libs.ll -o %t3.o // RUN: mkdir -p %t.dir // RUN: rm -f %t.dir/exc.a -// RUN: llvm-ar rcs %t.dir/exc.a %t2.o +// RUN: llvm-ar rcs %t.dir/exc.a %t2.o %t3.o // RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s @@ -22,6 +23,9 @@ // RUN: ld.lld -shared %t.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s +// RUN: ld.lld -shared %t.o %t2.o %t3.o %t.dir/exc.a -o %t.exe --exclude-libs=ALL +// RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=DEFAULT %s + // RUN: ld.lld -shared --whole-archive %t.o %t.dir/exc.a -o %t.exe --exclude-libs foo,bar,exc.a // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s @@ -29,8 +33,13 @@ // RUN: llvm-readobj -dyn-symbols %t.exe | FileCheck --check-prefix=EXCLUDE %s // DEFAULT: Name: fn +// DEFAULT: Name: fn2 +// DEFAULT: Name: foo // EXCLUDE-NOT: Name: fn +// EXCLUDE-NOT: Name: fn2 +// EXCLUDE: Name: foo -.globl fn +.globl fn, fn2, foo foo: call fn@PLT + call fn2@PLT diff --git a/test/ELF/executable-undefined-protected-ignoreall.s b/test/ELF/executable-undefined-protected-ignoreall.s index 37911791e124..967a69388670 100644 --- a/test/ELF/executable-undefined-protected-ignoreall.s +++ b/test/ELF/executable-undefined-protected-ignoreall.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: not ld.lld %t -o %tout --unresolved-symbols=ignore-all -pie 2>&1 | FileCheck %s +# RUN: not ld.lld %t -o /dev/null --unresolved-symbols=ignore-all -pie 2>&1 | FileCheck %s # CHECK: error: undefined symbol: foo .protected foo diff --git a/test/ELF/export-dynamic-symbol.s b/test/ELF/export-dynamic-symbol.s new file mode 100644 index 000000000000..22536035424c --- /dev/null +++ b/test/ELF/export-dynamic-symbol.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 + +# RUN: rm -f %t.a +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/archive2.s -o %t1.o +# RUN: llvm-ar rcs %t.a %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o + +# RUN: ld.lld -shared -o %t.so --export-dynamic-symbol foo %t.a %t2.o +# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s + +# RUN: ld.lld -shared -o %t.so --export-dynamic --export-dynamic-symbol foo %t.a %t2.o +# RUN: llvm-readelf -dyn-symbols %t.so | FileCheck %s + +# CHECK: foo + +.global _start +_start: + nop diff --git a/test/ELF/fatal-warnings.s b/test/ELF/fatal-warnings.s index 0bc2a2b44476..51f2864a0598 100644 --- a/test/ELF/fatal-warnings.s +++ b/test/ELF/fatal-warnings.s @@ -2,11 +2,11 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/warn-common.s -o %t2.o -# RUN: ld.lld --warn-common %t1.o %t2.o -o %t1.out 2>&1 | \ +# RUN: ld.lld --warn-common %t1.o %t2.o -o /dev/null 2>&1 | \ # RUN: FileCheck -check-prefix=ERR %s # ERR: multiple common of -# RUN: not ld.lld --warn-common --fatal-warnings %t1.o %t2.o -o %t2.out 2>&1 | \ +# RUN: not ld.lld --warn-common --fatal-warnings %t1.o %t2.o -o /dev/null 2>&1 | \ # RUN: FileCheck -check-prefix=ERR %s .globl _start diff --git a/test/ELF/file-sym.s b/test/ELF/file-sym.s deleted file mode 100644 index eddb461490c6..000000000000 --- a/test/ELF/file-sym.s +++ /dev/null @@ -1,12 +0,0 @@ -# Check that we do not keep STT_FILE symbols in the symbol table - -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: ld.lld %t.o -shared -o %t.so -# RUN: llvm-readobj -symbols %t.so | FileCheck %s - -# REQUIRES: x86 - -# CHECK-NOT: xxx - -.file "xxx" -.file "" diff --git a/test/ELF/fill-trap-ppc.s b/test/ELF/fill-trap-ppc.s new file mode 100644 index 000000000000..da7d7cb320bb --- /dev/null +++ b/test/ELF/fill-trap-ppc.s @@ -0,0 +1,31 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.ppc64le +# RUN: llvm-readobj -program-headers %t.ppc64le | FileCheck %s +# RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64le | FileCheck %s -check-prefix=LE + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.ppc64 +# RUN: llvm-readobj -program-headers %t.ppc64 | FileCheck %s +# RUN: od -Ax -t x1 -N16 -j0x10ff0 %t.ppc64 | FileCheck %s -check-prefix=BE + +# CHECK: ProgramHeader { +# CHECK: Type: PT_LOAD +# CHECK: Offset: 0x10000{{$}} +# CHECK-NEXT: VirtualAddress: +# CHECK-NEXT: PhysicalAddress: +# CHECK-NEXT: FileSize: 4096 +# CHECK-NEXT: MemSize: +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] + +## Check that executable page is filled with traps at its end. +# LE: 010ff0 08 00 e0 7f 08 00 e0 7f 08 00 e0 7f 08 00 e0 7f +# BE: 010ff0 7f e0 00 08 7f e0 00 08 7f e0 00 08 7f e0 00 08 + +.globl _start +_start: + nop diff --git a/test/ELF/filter.s b/test/ELF/filter.s index 4c9104a32510..2b07c01013df 100644 --- a/test/ELF/filter.s +++ b/test/ELF/filter.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld %t.o -shared -F foo.so -F boo.so -o %t1 # RUN: llvm-readobj --dynamic-table %t1 | FileCheck %s @@ -15,5 +16,5 @@ # CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [foo.so] # CHECK-NEXT: 0x000000007FFFFFFF FILTER Filter library: [boo.so] -# RUN: not ld.lld %t.o -F x -o %t 2>&1 | FileCheck -check-prefix=ERR %s +# RUN: not ld.lld %t.o -F x -o /dev/null 2>&1 | FileCheck -check-prefix=ERR %s # ERR: -F may not be used without -shared diff --git a/test/ELF/format-binary-non-ascii.s b/test/ELF/format-binary-non-ascii.s index 5a3ad960c30e..36263e5ddaba 100644 --- a/test/ELF/format-binary-non-ascii.s +++ b/test/ELF/format-binary-non-ascii.s @@ -4,9 +4,9 @@ # RUN: ld.lld -o %t.elf %t£.o --format=binary %t£.o # RUN: llvm-readobj -symbols %t.elf | FileCheck %s -# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_start -# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_end -# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp___o_size +# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_start +# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_end +# CHECK: Name: _binary_{{[a-zA-Z0-9_]+}}test_ELF_Output_format_binary_non_ascii_s_tmp_{{[_]+}}o_size .text .align 4 diff --git a/test/ELF/gc-absolute.s b/test/ELF/gc-absolute.s index 29e671678ee7..bd0870c263a7 100644 --- a/test/ELF/gc-absolute.s +++ b/test/ELF/gc-absolute.s @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 -shared --gc-sections +# RUN: ld.lld %t -o /dev/null -shared --gc-sections .global foo foo = 0x123 diff --git a/test/ELF/gc-debuginfo-tls.s b/test/ELF/gc-debuginfo-tls.s index d1a250b9c944..e23578f58c25 100644 --- a/test/ELF/gc-debuginfo-tls.s +++ b/test/ELF/gc-debuginfo-tls.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld %t.o --gc-sections -shared -o %t1 # RUN: ld.lld %t.o -shared -o %t2 diff --git a/test/ELF/gc-merge-local-sym.s b/test/ELF/gc-merge-local-sym.s index b02a3a4e4762..b82d0cebae82 100644 --- a/test/ELF/gc-merge-local-sym.s +++ b/test/ELF/gc-merge-local-sym.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t.o -o %t.so -shared -O3 --gc-sections // RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s @@ -9,7 +10,7 @@ // CHECK-NEXT: SHF_MERGE // CHECK-NEXT: SHF_STRINGS // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1C8 +// CHECK-NEXT: Address: 0x235 // CHECK-NEXT: Offset: // CHECK-NEXT: Size: 4 // CHECK-NEXT: Link: 0 diff --git a/test/ELF/gc-sections-local-sym.s b/test/ELF/gc-sections-local-sym.s index 89121e289cc2..15bca37ca409 100644 --- a/test/ELF/gc-sections-local-sym.s +++ b/test/ELF/gc-sections-local-sym.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: ld.lld %t -o %t2 -shared --gc-sections // RUN: llvm-readobj -t -s -section-data %t2 | FileCheck %s -// REQUIRES: x86 .global foo foo: diff --git a/test/ELF/gc-sections-merge-addend.s b/test/ELF/gc-sections-merge-addend.s index 8595f5802be5..4dd95b43bfc0 100644 --- a/test/ELF/gc-sections-merge-addend.s +++ b/test/ELF/gc-sections-merge-addend.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t.o -o %t.so -shared --gc-sections // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s diff --git a/test/ELF/gc-sections-merge-implicit-addend.s b/test/ELF/gc-sections-merge-implicit-addend.s index 8a7c804a830a..36bb21126434 100644 --- a/test/ELF/gc-sections-merge-implicit-addend.s +++ b/test/ELF/gc-sections-merge-implicit-addend.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux // RUN: ld.lld %t.o -o %t.so -shared --gc-sections // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s diff --git a/test/ELF/gc-sections-merge.s b/test/ELF/gc-sections-merge.s index ef2688659871..08dfdaaea669 100644 --- a/test/ELF/gc-sections-merge.s +++ b/test/ELF/gc-sections-merge.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t.o -o %t.so -shared // RUN: ld.lld %t.o -o %t.gc.so -shared --gc-sections diff --git a/test/ELF/gc-sections-metadata-startstop.s b/test/ELF/gc-sections-metadata-startstop.s index 10c0b5477b25..ede1899698c4 100644 --- a/test/ELF/gc-sections-metadata-startstop.s +++ b/test/ELF/gc-sections-metadata-startstop.s @@ -1,5 +1,5 @@ -# LINK_ORDER cnamed sections are not kept alive by the __start_* reference. # REQUIRES: x86 +# LINK_ORDER cnamed sections are not kept alive by the __start_* reference. # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld --gc-sections %t.o -o %t diff --git a/test/ELF/gc-sections-no-undef-error.s b/test/ELF/gc-sections-no-undef-error.s new file mode 100644 index 000000000000..31945241a77a --- /dev/null +++ b/test/ELF/gc-sections-no-undef-error.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + +# Sanity check that the link will fail with the undefined error without +# gc-sections. +# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s +# CHECK: error: undefined symbol: undefined + +# RUN: ld.lld %t.o --gc-sections -o %t + +.section .text.unused,"ax",@progbits +unused: + callq undefined + +.text +.global _start +_start: + nop diff --git a/test/ELF/gc-sections-print.s b/test/ELF/gc-sections-print.s index e05824177c1f..a822e9ef3479 100644 --- a/test/ELF/gc-sections-print.s +++ b/test/ELF/gc-sections-print.s @@ -2,8 +2,8 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: ld.lld %t --gc-sections --print-gc-sections -o %t2 2>&1 | FileCheck -check-prefix=PRINT %s -# PRINT: removing unused section from '.text.x' in file -# PRINT-NEXT: removing unused section from '.text.y' in file +# PRINT: removing unused section {{.*}}:(.text.x) +# PRINT-NEXT: removing unused section {{.*}}:(.text.y) # RUN: ld.lld %t --gc-sections --print-gc-sections --no-print-gc-sections -o %t2 >& %t.log # RUN: echo >> %t.log diff --git a/test/ELF/gc-sections-protected.s b/test/ELF/gc-sections-protected.s index 9f1efed5938a..28e779b1b7a1 100644 --- a/test/ELF/gc-sections-protected.s +++ b/test/ELF/gc-sections-protected.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t.o -o %t.so -shared --gc-sections // RUN: llvm-readobj -s %t.so | FileCheck %s diff --git a/test/ELF/gc-sections-shared.s b/test/ELF/gc-sections-shared.s index 2976213e910a..c0ebf403a333 100644 --- a/test/ELF/gc-sections-shared.s +++ b/test/ELF/gc-sections-shared.s @@ -25,6 +25,15 @@ # CHECK-NEXT: Section: Undefined (0x0) # CHECK-NEXT: } # CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: qux +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Type: +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { # CHECK-NEXT: Name: bar # CHECK-NEXT: Value: # CHECK-NEXT: Size: @@ -51,15 +60,6 @@ # CHECK-NEXT: Other: # CHECK-NEXT: Section: .text # CHECK-NEXT: } -# CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: qux -# CHECK-NEXT: Value: -# CHECK-NEXT: Size: -# CHECK-NEXT: Binding: Weak -# CHECK-NEXT: Type: -# CHECK-NEXT: Other: -# CHECK-NEXT: Section: Undefined -# CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NOT: NEEDED @@ -68,64 +68,12 @@ # Test with %t.o at the end too. # RUN: ld.lld --gc-sections --export-dynamic-symbol foo -o %t --as-needed %t2.so %t3.so %t4.so %t.o -# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck --check-prefix=CHECK2 %s - -# CHECK2: DynamicSymbols [ -# CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: -# CHECK2-NEXT: Value: -# CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Local -# CHECK2-NEXT: Type: -# CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: Undefined (0x0) -# CHECK2-NEXT: } -# CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: bar -# CHECK2-NEXT: Value: -# CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Global -# CHECK2-NEXT: Type: -# CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: .text -# CHECK2-NEXT: } -# CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: baz -# CHECK2-NEXT: Value: -# CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Global -# CHECK2-NEXT: Type: -# CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: Undefined -# CHECK2-NEXT: } -# CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: qux -# CHECK2-NEXT: Value: -# CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Weak -# CHECK2-NEXT: Type: -# CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: Undefined -# CHECK2-NEXT: } -# CHECK2-NEXT: Symbol { -# CHECK2-NEXT: Name: foo -# CHECK2-NEXT: Value: -# CHECK2-NEXT: Size: -# CHECK2-NEXT: Binding: Global -# CHECK2-NEXT: Type: -# CHECK2-NEXT: Other: -# CHECK2-NEXT: Section: .text -# CHECK2-NEXT: } -# CHECK2-NEXT: ] - -# CHECK2-NOT: NEEDED -# CHECK2: NEEDED Shared library: [{{.*}}3.so] -# CHECK2-NOT: NEEDED +# RUN: llvm-readobj --dynamic-table --dyn-symbols %t | FileCheck --check-prefix=CHECK %s .section .text.foo, "ax" .globl foo foo: -call bar +.long bar - . .section .text.bar, "ax" .globl bar @@ -136,9 +84,9 @@ ret .globl _start .weak qux _start: -call baz -call qux +.long baz - . +.long qux - . ret .section .text.unused, "ax" -call bar2 +.long bar2 - . diff --git a/test/ELF/gdb-index-dup-types.s b/test/ELF/gdb-index-dup-types.s deleted file mode 100644 index f5df00c453cc..000000000000 --- a/test/ELF/gdb-index-dup-types.s +++ /dev/null @@ -1,60 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: ld.lld --gdb-index %t.o -o %t -# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s - -## Testcase is based on output produced by gcc version 5.4.1 20160904 -## it has duplicate entries in .debug_gnu_pubtypes which seems to be -## compiler bug. In that case it is useless to have them in .gdb_index -## and we filter such entries out to reduce size of .gdb_index. - -## CHECK: Constant pool offset = {{.*}}, has 1 CU vectors: -## CHECK-NOT: 0(0x0): 0x90000000 0x90000000 - -.section .debug_abbrev,"",@progbits - .byte 1 # Abbreviation Code - .byte 17 # DW_TAG_compile_unit - .byte 0 # DW_CHILDREN_no - .byte 16 # DW_AT_stmt_list - .byte 23 # DW_FORM_sec_offset - .ascii "\260B" # DW_AT_GNU_dwo_name - .byte 14 # DW_FORM_strp - .byte 27 # DW_AT_comp_dir - .byte 14 # DW_FORM_strp - .ascii "\264B" # DW_AT_GNU_pubnames - .byte 25 # DW_FORM_flag_present - .ascii "\261B" # DW_AT_GNU_dwo_id - .byte 7 # DW_FORM_data8 - .ascii "\263B" # DW_AT_GNU_addr_base - .byte 23 # DW_FORM_sec_offset - .byte 0 # EOM(1) - .byte 0 # EOM(2) - .byte 0 # EOM(3) - -.section .debug_info,"",@progbits -.Lcu_begin0: - .long 32 # Length of Unit - .short 4 # DWARF version number - .long .debug_abbrev # Offset Into Abbrev. Section - .byte 8 # Address Size (in bytes) - .byte 1 # Abbrev [1] 0xb:0x19 DW_TAG_compile_unit - .long 0 # DW_AT_stmt_list - .long 0 # DW_AT_GNU_dwo_name - .long 0 # DW_AT_comp_dir - .quad 0 # DW_AT_GNU_dwo_id - .long 0 # DW_AT_GNU_addr_base - -.section .debug_gnu_pubtypes,"",@progbits -.long .LpubTypes_end0-.LpubTypes_begin0 # Length of Public Types Info -.LpubTypes_begin0: - .short 2 # DWARF Version - .long .Lcu_begin0 # Offset of Compilation Unit Info - .long 36 # Compilation Unit Length - .long 36 # DIE offset - .byte 144 # Kind: TYPE, STATIC - .asciz "int" # External Name - .long 36 # DIE offset - .byte 144 # Kind: TYPE, STATIC - .asciz "int" # External Name - .long 0 # End Mark -.LpubTypes_end0: diff --git a/test/ELF/gdb-index-noranges.s b/test/ELF/gdb-index-noranges.s index 29ba91eb5a75..12080642e6cd 100644 --- a/test/ELF/gdb-index-noranges.s +++ b/test/ELF/gdb-index-noranges.s @@ -10,7 +10,7 @@ ## ## Debug information does not contain any address ranges. ## We crashed in that case. Check we don't. -# RUN: ld.lld --gdb-index %t1.o -o %t +# RUN: ld.lld --gdb-index %t1.o -o /dev/null .section .debug_str,"MS",@progbits,1 .Lskel_string0: diff --git a/test/ELF/gdb-index-tls.s b/test/ELF/gdb-index-tls.s index 0fd7b6115676..785e13f0056f 100644 --- a/test/ELF/gdb-index-tls.s +++ b/test/ELF/gdb-index-tls.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: ld.lld --gdb-index -shared %t.o -o %t +# RUN: ld.lld --gdb-index -shared %t.o -o /dev/null # This used to fail trying to compute R_X86_64_DTPOFF64 diff --git a/test/ELF/gdb-index.s b/test/ELF/gdb-index.s index 8fea83d145fa..e7f96066bd02 100644 --- a/test/ELF/gdb-index.s +++ b/test/ELF/gdb-index.s @@ -1,9 +1,19 @@ -# REQUIRES: x86 +# REQUIRES: x86, zlib # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/gdb-index.s -o %t2.o # RUN: ld.lld --gdb-index %t1.o %t2.o -o %t -# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s + +# RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM +# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s --check-prefix=DWARF +# RUN: llvm-readelf -sections %t | FileCheck %s --check-prefix=SECTION + +# RUN: llvm-mc -compress-debug-sections=zlib-gnu -filetype=obj -triple=x86_64-pc-linux \ +# RUN: %p/Inputs/gdb-index.s -o %t2.o +# RUN: ld.lld --gdb-index %t1.o %t2.o -o %t + # RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DISASM +# RUN: llvm-dwarfdump -gdb-index %t | FileCheck %s --check-prefix=DWARF +# RUN: llvm-readelf -sections %t | FileCheck %s --check-prefix=SECTION # DISASM: Disassembly of section .text: # DISASM: entrypoint: @@ -11,29 +21,31 @@ # DISASM-CHECK: 201001: cc int3 # DISASM-CHECK: 201002: cc int3 # DISASM-CHECK: 201003: cc int3 -# DISASM: main2: +# DISASM: aaaaaaaaaaaaaaaa: # DISASM-CHECK: 201004: 90 nop # DISASM-CHECK: 201005: 90 nop -# CHECK: .gnu_index contents: -# CHECK-NEXT: Version = 7 -# CHECK: CU list offset = 0x18, has 2 entries: -# CHECK-NEXT: 0: Offset = 0x0, Length = 0x34 -# CHECK-NEXT: 1: Offset = 0x34, Length = 0x34 -# CHECK: Address area offset = 0x38, has 2 entries: -# CHECK-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0 -# CHECK-NEXT: Low/High address = [0x201004, 0x201006) (Size: 0x2), CU id = 1 -# CHECK: Symbol table offset = 0x60, size = 1024, filled slots: -# CHECK-NEXT: 754: Name offset = 0x27, CU vector offset = 0x8 -# CHECK-NEXT: String name: int, CU vector index: 1 -# CHECK-NEXT: 822: Name offset = 0x1c, CU vector offset = 0x0 -# CHECK-NEXT: String name: entrypoint, CU vector index: 0 -# CHECK-NEXT: 956: Name offset = 0x2b, CU vector offset = 0x14 -# CHECK-NEXT: String name: main2, CU vector index: 2 -# CHECK: Constant pool offset = 0x2060, has 3 CU vectors: -# CHECK-NEXT: 0(0x0): 0x30000000 -# CHECK-NEXT: 1(0x8): 0x90000000 0x90000001 -# CHECK-NEXT: 2(0x14): 0x30000001 +# DWARF: .gnu_index contents: +# DWARF-NEXT: Version = 7 +# DWARF: CU list offset = 0x18, has 2 entries: +# DWARF-NEXT: 0: Offset = 0x0, Length = 0x34 +# DWARF-NEXT: 1: Offset = 0x34, Length = 0x34 +# DWARF: Address area offset = 0x38, has 2 entries: +# DWARF-NEXT: Low/High address = [0x201000, 0x201001) (Size: 0x1), CU id = 0 +# DWARF-NEXT: Low/High address = [0x201004, 0x201006) (Size: 0x2), CU id = 1 +# DWARF: Symbol table offset = 0x60, size = 1024, filled slots: +# DWARF-NEXT: 512: Name offset = 0x1c, CU vector offset = 0x0 +# DWARF-NEXT: String name: aaaaaaaaaaaaaaaa, CU vector index: 0 +# DWARF-NEXT: 754: Name offset = 0x38, CU vector offset = 0x10 +# DWARF-NEXT: String name: int, CU vector index: 2 +# DWARF-NEXT: 822: Name offset = 0x2d, CU vector offset = 0x8 +# DWARF-NEXT: String name: entrypoint, CU vector index: 1 +# DWARF: Constant pool offset = 0x2060, has 3 CU vectors: +# DWARF-NEXT: 0(0x0): 0x30000001 +# DWARF-NEXT: 1(0x8): 0x30000000 +# DWARF-NEXT: 2(0x10): 0x90000000 0x90000001 + +# SECTION-NOT: debug_gnu_pubnames # RUN: ld.lld --gdb-index --no-gdb-index %t1.o %t2.o -o %t2 # RUN: llvm-readobj -sections %t2 | FileCheck -check-prefix=NOGDB %s diff --git a/test/ELF/global-offset-table-position-aarch64.s b/test/ELF/global-offset-table-position-aarch64.s index 68bc4a4254ed..7fdc7978825f 100644 --- a/test/ELF/global-offset-table-position-aarch64.s +++ b/test/ELF/global-offset-table-position-aarch64.s @@ -1,7 +1,7 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-linux-gnu %s -o %t // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s -// REQUIRES: aarch64 .globl a .type a,@object .comm a,4,4 @@ -20,11 +20,11 @@ _start: .long _GLOBAL_OFFSET_TABLE_ - . // CHECK: Name: _GLOBAL_OFFSET_TABLE_ (11) -// CHECK-NEXT: Value: 0x30090 +// CHECK-NEXT: Value: 0x20008 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local (0x0) // CHECK-NEXT: Type: None (0x0) // CHECK-NEXT: Other [ (0x2) // CHECK-NEXT: STV_HIDDEN (0x2) // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got +// CHECK-NEXT: Section: .got.plt diff --git a/test/ELF/global-offset-table-position-arm.s b/test/ELF/global-offset-table-position-arm.s index 19619b2cc9e8..9abca8b46317 100644 --- a/test/ELF/global-offset-table-position-arm.s +++ b/test/ELF/global-offset-table-position-arm.s @@ -1,7 +1,7 @@ +// REQUIRES: arm // RUN: llvm-mc -filetype=obj -triple=armv7a-linux-gnueabihf %s -o %t // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s -// REQUIRES: arm // The ARM _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got .globl a diff --git a/test/ELF/global-offset-table-position-i386.s b/test/ELF/global-offset-table-position-i386.s index 9f778e1efb50..e3d343427015 100644 --- a/test/ELF/global-offset-table-position-i386.s +++ b/test/ELF/global-offset-table-position-i386.s @@ -1,9 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s -// REQUIRES: x86 -// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section. +// The X86 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt +// section. .globl a .type a,@object .comm a,4,4 @@ -21,11 +22,11 @@ addl $_GLOBAL_OFFSET_TABLE_, %eax calll f@PLT // CHECK: Name: _GLOBAL_OFFSET_TABLE_ (1) -// CHECK-NEXT: Value: 0x306C +// CHECK-NEXT: Value: 0x2000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local (0x0) // CHECK-NEXT: Type: None (0x0) // CHECK-NEXT: Other [ (0x2) // CHECK-NEXT: STV_HIDDEN (0x2) // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got (0xA) +// CHECK-NEXT: Section: .got.plt diff --git a/test/ELF/global-offset-table-position-mips.s b/test/ELF/global-offset-table-position-mips.s index 92daed1c7914..a5577f2e1421 100644 --- a/test/ELF/global-offset-table-position-mips.s +++ b/test/ELF/global-offset-table-position-mips.s @@ -1,9 +1,8 @@ +// REQUIRES: mips // RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t // RUN: ld.lld -shared %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s -// REQUIRES: mips - // The Mips _GLOBAL_OFFSET_TABLE_ should be defined at the start of the .got .globl a diff --git a/test/ELF/global-offset-table-position.s b/test/ELF/global-offset-table-position.s index f1195b2cf674..aa8083654039 100644 --- a/test/ELF/global-offset-table-position.s +++ b/test/ELF/global-offset-table-position.s @@ -1,9 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s -// REQUIRES: x86 -// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the end of the .got section. +// The X86_64 _GLOBAL_OFFSET_TABLE_ is defined at the start of the .got.plt +// section. .globl a .type a,@object .comm a,4,4 @@ -21,11 +22,11 @@ callq f@PLT .long _GLOBAL_OFFSET_TABLE_ - . // CHECK: Name: _GLOBAL_OFFSET_TABLE_ -// CHECK-NEXT: Value: 0x30D8 +// CHECK-NEXT: Value: 0x2008 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local // CHECK-NEXT: Type: None (0x0) // CHECK-NEXT: Other [ // CHECK-NEXT: STV_HIDDEN // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got +// CHECK-NEXT: Section: .got.plt diff --git a/test/ELF/global_offset_table.s b/test/ELF/global_offset_table.s index 47e95e9f9b84..3b86f00ae3ab 100644 --- a/test/ELF/global_offset_table.s +++ b/test/ELF/global_offset_table.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: ld.lld %t -o %t2 +// RUN: ld.lld %t -o /dev/null .global _start _start: .long _GLOBAL_OFFSET_TABLE_ diff --git a/test/ELF/global_offset_table_shared.s b/test/ELF/global_offset_table_shared.s index 03af02e5805e..7af6a403ac6c 100644 --- a/test/ELF/global_offset_table_shared.s +++ b/test/ELF/global_offset_table_shared.s @@ -1,14 +1,15 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld --hash-style=sysv -shared %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s .long _GLOBAL_OFFSET_TABLE_ - . // CHECK: Name: _GLOBAL_OFFSET_TABLE_ -// CHECK-NEXT: Value: 0x2060 +// CHECK-NEXT: Value: 0x2000 // CHECK-NEXT: Size: 0 // CHECK-NEXT: Binding: Local // CHECK-NEXT: Type: None // CHECK-NEXT: Other [ (0x2) // CHECK-NEXT: STV_HIDDEN (0x2) // CHECK-NEXT: ] -// CHECK-NEXT: Section: .got +// CHECK-NEXT: Section: .got.plt diff --git a/test/ELF/gnu-hash-table.s b/test/ELF/gnu-hash-table.s index fa68ba250131..ffbf19fb5c6f 100644 --- a/test/ELF/gnu-hash-table.s +++ b/test/ELF/gnu-hash-table.s @@ -4,30 +4,36 @@ # RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %te.s -o %te-i386.o # RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t-i386.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t-x86_64.o -# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %s -o %t-ppc64.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t-ppc64le.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t-ppc64.o # RUN: echo ".global zed; zed:" > %t2.s # RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %t2.s -o %t2-i386.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t2.s -o %t2-x86_64.o -# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %t2.s -o %t2-ppc64.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %t2.s -o %t2-ppc64le.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %t2.s -o %t2-ppc64.o # RUN: rm -f %t2-i386.a %t2-x86_64.a %t2-ppc64.a # RUN: llvm-ar rc %t2-i386.a %t2-i386.o # RUN: llvm-ar rc %t2-x86_64.a %t2-x86_64.o +# RUN: llvm-ar rc %t2-ppc64le.a %t2-ppc64le.o # RUN: llvm-ar rc %t2-ppc64.a %t2-ppc64.o # RUN: echo ".global xyz; xyz:" > %t3.s # RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %t3.s -o %t3-i386.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t3.s -o %t3-x86_64.o -# RUN: llvm-mc -filetype=obj -triple=powerpc64-pc-linux %t3.s -o %t3-ppc64.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %t3.s -o %t3-ppc64le.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %t3.s -o %t3-ppc64.o # RUN: ld.lld -shared %t3-i386.o -o %t3-i386.so # RUN: ld.lld -shared %t3-x86_64.o -o %t3-x86_64.so +# RUN: ld.lld -shared %t3-ppc64le.o -o %t3-ppc64le.so # RUN: ld.lld -shared %t3-ppc64.o -o %t3-ppc64.so # RUN: ld.lld -shared --hash-style=gnu -o %te-i386.so %te-i386.o # RUN: ld.lld -shared -hash-style=gnu -o %t-i386.so %t-i386.o %t2-i386.a %t3-i386.so # RUN: ld.lld -shared -hash-style=gnu -o %t-x86_64.so %t-x86_64.o %t2-x86_64.a %t3-x86_64.so +# RUN: ld.lld -shared --hash-style both -o %t-ppc64le.so %t-ppc64le.o %t2-ppc64le.a %t3-ppc64le.so # RUN: ld.lld -shared --hash-style both -o %t-ppc64.so %t-ppc64.o %t2-ppc64.a %t3-ppc64.so # RUN: llvm-readobj -dyn-symbols -gnu-hash-table %te-i386.so \ @@ -36,6 +42,8 @@ # RUN: | FileCheck %s -check-prefix=I386 # RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-x86_64.so \ # RUN: | FileCheck %s -check-prefix=X86_64 +# RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64le.so \ +# RUN: | FileCheck %s -check-prefix=PPC64 # RUN: llvm-readobj -sections -dyn-symbols -gnu-hash-table %t-ppc64.so \ # RUN: | FileCheck %s -check-prefix=PPC64 @@ -51,12 +59,12 @@ # EMPTY-NEXT: } # EMPTY-NEXT: ] # EMPTY: GnuHashTable { -# EMPTY-NEXT: Num Buckets: 0 +# EMPTY-NEXT: Num Buckets: 1 # EMPTY-NEXT: First Hashed Symbol Index: 2 # EMPTY-NEXT: Num Mask Words: 1 -# EMPTY-NEXT: Shift Count: 5 +# EMPTY-NEXT: Shift Count: 6 # EMPTY-NEXT: Bloom Filter: [0x0] -# EMPTY-NEXT: Buckets: [] +# EMPTY-NEXT: Buckets: [0] # EMPTY-NEXT: Values: [] # EMPTY-NEXT: } @@ -113,8 +121,8 @@ # I386-NEXT: Num Buckets: 1 # I386-NEXT: First Hashed Symbol Index: 4 # I386-NEXT: Num Mask Words: 1 -# I386-NEXT: Shift Count: 5 -# I386-NEXT: Bloom Filter: [0x14000220] +# I386-NEXT: Shift Count: 6 +# I386-NEXT: Bloom Filter: [0x4004204] # I386-NEXT: Buckets: [4] # I386-NEXT: Values: [0xB8860BA, 0xB887389] # I386-NEXT: } diff --git a/test/ELF/gnu-ifunc-dynsym.s b/test/ELF/gnu-ifunc-dynsym.s index fca15462dcb1..3d98ac3a4cfc 100644 --- a/test/ELF/gnu-ifunc-dynsym.s +++ b/test/ELF/gnu-ifunc-dynsym.s @@ -1,7 +1,11 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + // RUN: ld.lld -static -export-dynamic %t.o -o %tout // RUN: llvm-nm -U %tout | FileCheck %s -// REQUIRES: x86 + +// RUN: ld.lld -export-dynamic %t.o -o %tout +// RUN: llvm-nm -U %tout | FileCheck %s // CHECK: __rela_iplt_end // CHECK: __rela_iplt_start diff --git a/test/ELF/gnu-ifunc-dyntags.s b/test/ELF/gnu-ifunc-dyntags.s new file mode 100644 index 000000000000..81bd338d088d --- /dev/null +++ b/test/ELF/gnu-ifunc-dyntags.s @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -pie %t.o -o %tout +# RUN: llvm-objdump -section-headers %tout | FileCheck %s +# RUN: llvm-readobj -dynamic-table -r %tout | FileCheck %s --check-prefix=TAGS + +## Check we produce DT_PLTREL/DT_JMPREL/DT_PLTGOT and DT_PLTRELSZ tags +## when there are no other relocations except R_*_IRELATIVE. + +# CHECK: Name Size Address +# CHECK: .rela.plt 00000030 0000000000000210 +# CHECK: .got.plt 00000010 0000000000002000 + +# TAGS: Relocations [ +# TAGS-NEXT: Section {{.*}} .rela.plt { +# TAGS-NEXT: R_X86_64_IRELATIVE +# TAGS-NEXT: R_X86_64_IRELATIVE +# TAGS-NEXT: } +# TAGS-NEXT: ] + +# TAGS: Tag Type Name/Value +# TAGS: 0x0000000000000017 JMPREL 0x210 +# TAGS: 0x0000000000000002 PLTRELSZ 48 +# TAGS: 0x0000000000000003 PLTGOT 0x2000 +# TAGS: 0x0000000000000014 PLTREL RELA + +.text +.type foo STT_GNU_IFUNC +.globl foo +foo: + ret + +.type bar STT_GNU_IFUNC +.globl bar +bar: + ret + +.globl _start +_start: + call foo + call bar diff --git a/test/ELF/gnu-ifunc-i386.s b/test/ELF/gnu-ifunc-i386.s index 4eda32f378d9..f379bf1b28e8 100644 --- a/test/ELF/gnu-ifunc-i386.s +++ b/test/ELF/gnu-ifunc-i386.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s -// REQUIRES: x86 // CHECK: Sections [ // CHECK: Section { diff --git a/test/ELF/gnu-ifunc-nosym-i386.s b/test/ELF/gnu-ifunc-nosym-i386.s index d22cedbfe6de..564b87e23b32 100644 --- a/test/ELF/gnu-ifunc-nosym-i386.s +++ b/test/ELF/gnu-ifunc-nosym-i386.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-readobj -symbols %tout | FileCheck %s -// REQUIRES: x86 // Check that no __rel_iplt_end/__rel_iplt_start // appear in symtab if there is no references to them. diff --git a/test/ELF/gnu-ifunc-nosym.s b/test/ELF/gnu-ifunc-nosym.s index 08e498e97c19..4206f57d1363 100644 --- a/test/ELF/gnu-ifunc-nosym.s +++ b/test/ELF/gnu-ifunc-nosym.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-readobj -symbols %tout | FileCheck %s -// REQUIRES: x86 // Check that no __rela_iplt_end/__rela_iplt_start // appear in symtab if there is no references to them. diff --git a/test/ELF/gnu-ifunc-plt-i386.s b/test/ELF/gnu-ifunc-plt-i386.s index 243eff62fcbf..14369bf6388b 100644 --- a/test/ELF/gnu-ifunc-plt-i386.s +++ b/test/ELF/gnu-ifunc-plt-i386.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o // RUN: ld.lld %t1.o --shared -o %t.so // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o @@ -5,7 +6,6 @@ // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s -// REQUIRES: x86 // Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt // CHECK: Relocations [ @@ -70,7 +70,7 @@ bar: .globl _start _start: - call foo - call bar - call bar2 - call zed2 + call foo@plt + call bar@plt + call bar2@plt + call zed2@plt diff --git a/test/ELF/gnu-ifunc-plt.s b/test/ELF/gnu-ifunc-plt.s index 88a09931853c..b88f32cb7306 100644 --- a/test/ELF/gnu-ifunc-plt.s +++ b/test/ELF/gnu-ifunc-plt.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared2-x86-64.s -o %t1.o // RUN: ld.lld %t1.o --shared -o %t.so // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o @@ -5,7 +6,6 @@ // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-objdump -s %tout | FileCheck %s --check-prefix=GOTPLT // RUN: llvm-readobj -r -dynamic-table %tout | FileCheck %s -// REQUIRES: x86 // Check that the IRELATIVE relocations are after the JUMP_SLOT in the plt // CHECK: Relocations [ diff --git a/test/ELF/gnu-ifunc-relative.s b/test/ELF/gnu-ifunc-relative.s index dc35102c5787..d797301d03ad 100644 --- a/test/ELF/gnu-ifunc-relative.s +++ b/test/ELF/gnu-ifunc-relative.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-readobj -r -t %tout | FileCheck %s -// REQUIRES: x86 .type foo STT_GNU_IFUNC .globl foo diff --git a/test/ELF/gnu-ifunc.s b/test/ELF/gnu-ifunc.s index 4911da6bce00..faf51b4b6216 100644 --- a/test/ELF/gnu-ifunc.s +++ b/test/ELF/gnu-ifunc.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld -static %t.o -o %tout // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix=DISASM // RUN: llvm-readobj -r -symbols -sections %tout | FileCheck %s -// REQUIRES: x86 // CHECK: Sections [ // CHECK: Section { diff --git a/test/ELF/gnu-unique.s b/test/ELF/gnu-unique.s index afc0da27063d..06f370434cd8 100644 --- a/test/ELF/gnu-unique.s +++ b/test/ELF/gnu-unique.s @@ -3,6 +3,8 @@ // // RUN: ld.lld %t -shared -o %tout.so // RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=GNU %s +// RUN: ld.lld %t -shared -o %tout.so --gnu-unique +// RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=GNU %s // // RUN: ld.lld %t -shared -o %tout.so --no-gnu-unique // RUN: llvm-readobj -dyn-symbols %tout.so | FileCheck -check-prefix=NO %s diff --git a/test/ELF/gnustack.s b/test/ELF/gnustack.s index c506fb807c62..3ab6f16ac7bd 100644 --- a/test/ELF/gnustack.s +++ b/test/ELF/gnustack.s @@ -1,10 +1,15 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 + # RUN: ld.lld %t1 -z execstack -o %t # RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RWX %s + # RUN: ld.lld %t1 -o %t # RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s +# RUN: ld.lld %t1 -o %t -z noexecstack +# RUN: llvm-readobj --program-headers -s %t | FileCheck --check-prefix=RW %s + # RW: Type: PT_GNU_STACK # RW-NEXT: Offset: 0x0 # RW-NEXT: VirtualAddress: 0x0 diff --git a/test/ELF/got-aarch64.s b/test/ELF/got-aarch64.s index f46946c9f4aa..c9e20276472f 100644 --- a/test/ELF/got-aarch64.s +++ b/test/ELF/got-aarch64.s @@ -1,8 +1,8 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.o // RUN: ld.lld --hash-style=sysv -shared %t.o -o %t.so // RUN: llvm-readobj -s -r %t.so | FileCheck %s // RUN: llvm-objdump -d %t.so | FileCheck --check-prefix=DISASM %s -// REQUIRES: aarch64 // CHECK: Name: .got // CHECK-NEXT: Type: SHT_PROGBITS diff --git a/test/ELF/got-i386.s b/test/ELF/got-i386.s index 679eb2e4f5ca..7fb87e0dadbd 100644 --- a/test/ELF/got-i386.s +++ b/test/ELF/got-i386.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o // RUN: ld.lld %t.o -o %t // RUN: llvm-readobj -s -r -t %t | FileCheck %s // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s -// REQUIRES: x86 // CHECK: Name: .got // CHECK-NEXT: Type: SHT_PROGBITS diff --git a/test/ELF/got-plt-header.s b/test/ELF/got-plt-header.s index a6b10fa3a0a0..f8412e13c41d 100644 --- a/test/ELF/got-plt-header.s +++ b/test/ELF/got-plt-header.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: ld.lld %t.o -o %t.so -shared // RUN: llvm-readobj -s -section-data %t.so | FileCheck %s diff --git a/test/ELF/got.s b/test/ELF/got.s index f67ea13d3f4e..9d2d804454bf 100644 --- a/test/ELF/got.s +++ b/test/ELF/got.s @@ -1,10 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so // RUN: ld.lld --hash-style=sysv %t.o %t2.so -o %t // RUN: llvm-readobj -s -r %t | FileCheck %s // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s -// REQUIRES: x86 // CHECK: Name: .got // CHECK-NEXT: Type: SHT_PROGBITS diff --git a/test/ELF/got32-i386-pie-rw.s b/test/ELF/got32-i386-pie-rw.s index 18b019c2cc9d..45d2ec154675 100644 --- a/test/ELF/got32-i386-pie-rw.s +++ b/test/ELF/got32-i386-pie-rw.s @@ -7,8 +7,8 @@ # CHECK: .foobar PROGBITS 00001000 # CHECK: .got PROGBITS [[GOT:[0-9a-z]*]] -# CHECK: [[GOT]] 00000008 R_386_RELATIVE -# CHECK: 00001002 00000008 R_386_RELATIVE +# CHECK-DAG: 00001002 00000008 R_386_RELATIVE +# CHECK-DAG: [[GOT]] 00000008 R_386_RELATIVE foo: .section .foobar, "awx" diff --git a/test/ELF/got32-i386.s b/test/ELF/got32-i386.s index 00c7c0d6d553..dce50d0afc2e 100644 --- a/test/ELF/got32-i386.s +++ b/test/ELF/got32-i386.s @@ -20,4 +20,4 @@ _start: # CHECK: .got 00000004 0000000000012000 # RUN: not ld.lld %t.o -o %t -pie 2>&1 | FileCheck %s --check-prefix=ERR -# ERR: error: can't create dynamic relocation R_386_GOT32 against symbol: foo in readonly segment; recompile object files with -fPIC +# ERR: error: can't create dynamic relocation R_386_GOT32 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output diff --git a/test/ELF/got32x-i386.s b/test/ELF/got32x-i386.s index 1311472cc061..610051e8a962 100644 --- a/test/ELF/got32x-i386.s +++ b/test/ELF/got32x-i386.s @@ -33,15 +33,15 @@ ## 73728 == 0x12000 == ADDR(.got) # CHECK: _start: -# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 73728, %eax -# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 73728, %ebx +# CHECK-NEXT: 11001: 8b 05 {{.*}} movl 77824, %eax +# CHECK-NEXT: 11007: 8b 1d {{.*}} movl 77824, %ebx # CHECK-NEXT: 1100d: 8b 80 {{.*}} movl -4(%eax), %eax # CHECK-NEXT: 11013: 8b 83 {{.*}} movl -4(%ebx), %eax # CHECK: Sections: # CHECK: Name Size Address -# CHECK: .got 00000004 0000000000012000 +# CHECK: .got 00000004 0000000000013000 # RUN: not ld.lld %S/Inputs/i386-got32x-baseless.elf -o %t1 -pie 2>&1 | \ # RUN: FileCheck %s --check-prefix=ERR -# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC -# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC +# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output +# ERR: error: can't create dynamic relocation R_386_GOT32X against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output diff --git a/test/ELF/gotpcrelx.s b/test/ELF/gotpcrelx.s index 3ccbc56aba94..d9a7b8e048c3 100644 --- a/test/ELF/gotpcrelx.s +++ b/test/ELF/gotpcrelx.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -relax-relocations -triple x86_64-pc-linux-gnu \ // RUN: %s -o %t.o // RUN: llvm-readobj -r %t.o | FileCheck --check-prefix=RELS %s diff --git a/test/ELF/help.s b/test/ELF/help.s index 2554531532b3..aca2ceb76ee1 100644 --- a/test/ELF/help.s +++ b/test/ELF/help.s @@ -1,5 +1,5 @@ # RUN: ld.lld --help 2>&1 | FileCheck %s # CHECK: OPTIONS: -# CHECK: --output=<value> Path to file to write output -# CHECK: --output <value> Path to file to write output +# CHECK: --output=<value> Alias for -o +# CHECK: --output <value> Alias for -o # CHECK: -o <path> Path to file to write output diff --git a/test/ELF/hexagon.s b/test/ELF/hexagon.s new file mode 100644 index 000000000000..8c824ea3c78a --- /dev/null +++ b/test/ELF/hexagon.s @@ -0,0 +1,24 @@ +# REQUIRES: hexagon +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %s -o %t +# RUN: llvm-mc -filetype=obj -triple=hexagon-unknown-elf %S/Inputs/hexagon.s -o %t2 +# RUN: ld.lld %t2 %t -o %t3 +# RUN: llvm-objdump -d %t3 | FileCheck %s + +# R_HEX_B15_PCREL +if (p0) jump:nt #_start +# CHECK: if (p0) jump:nt 0x11000 + +# R_HEX_B32_PCREL_X +# R_HEX_B15_PCREL_X +if (p0) jump:nt ##_start +# CHECK: if (p0) jump:nt 0x11000 + +# R_HEX_B22_PCREL +call #_start +# CHECK: call 0x11000 + +# R_HEX_B32_PCREL_X +# R_HEX_B22_PCREL_X +call ##_start +# CHECK: immext(#4294967232) +# CHECK: call 0x11000 diff --git a/test/ELF/hidden-shared-err.s b/test/ELF/hidden-shared-err.s new file mode 100644 index 000000000000..e6d424c24824 --- /dev/null +++ b/test/ELF/hidden-shared-err.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/hidden-shared-err.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/hidden-shared-err2.s -o %t3.o + +# RUN: ld.lld -shared -o %t2.so %t2.o +# RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t2.so %t.o -o %t 2>&1 | FileCheck %s + +# RUN: not ld.lld %t.o %t3.o %t2.so -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t3.o %t.o %t2.so -o %t 2>&1 | FileCheck %s + +# CHECK: undefined symbol: foo + +.global _start +_start: +.quad foo +.hidden foo diff --git a/test/ELF/i386-debug-noabs.test b/test/ELF/i386-debug-noabs.test index 712d0a59cecc..dbc7a57f8f7a 100644 --- a/test/ELF/i386-debug-noabs.test +++ b/test/ELF/i386-debug-noabs.test @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: yaml2obj %s -o %t.o -# RUN: ld.lld %t.o -o %t.exe +# RUN: ld.lld %t.o -o /dev/null --entry 0 --fatal-warnings ## This is for https://bugs.llvm.org//show_bug.cgi?id=34852. GCC 8.0 or ## earlier have a bug which creates non-absolute R_386_GOTPC relocations diff --git a/test/ELF/i386-got-and-copy.s b/test/ELF/i386-got-and-copy.s index 81bac22fd66a..78788a55f23c 100644 --- a/test/ELF/i386-got-and-copy.s +++ b/test/ELF/i386-got-and-copy.s @@ -15,6 +15,7 @@ # CHECK: Relocations [ # CHECK-NEXT: Section (4) .rel.dyn { # CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_COPY foo +# CHECK-NEXT: 0x{{[0-9A-F]+}} R_386_GLOB_DAT foo # CHECK-NEXT: } # CHECK-NEXT: ] diff --git a/test/ELF/i386-got-value.s b/test/ELF/i386-got-value.s index 8803fcffb312..2d7bd6804d6a 100644 --- a/test/ELF/i386-got-value.s +++ b/test/ELF/i386-got-value.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -o %t.o -filetype=obj -triple=i386-pc-linux # RUN: ld.lld %t.o -o %t.so -shared # RUN: llvm-readobj --relocations --sections --section-data %t.so | FileCheck %s diff --git a/test/ELF/i386-gotpc.s b/test/ELF/i386-gotpc.s index d2c5ef3d469c..af8380b91153 100644 --- a/test/ELF/i386-gotpc.s +++ b/test/ELF/i386-gotpc.s @@ -6,15 +6,23 @@ movl $_GLOBAL_OFFSET_TABLE_, %eax +// CHECK: Name: .got.plt +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: SHF_WRITE +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x2000 + // CHECK: Name: .got // CHECK-NEXT: Type: SHT_PROGBITS // CHECK-NEXT: Flags [ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_WRITE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x2030 +// CHECK-NEXT: Address: 0x3030 // DISASM: Disassembly of section .text: // DISASM-NEXT: .text: -// DISASM-NEXT: 1000: {{.*}} movl $4144, %eax -// 0x2030 - 0x1000 = 4144 +// DISASM-NEXT: 1000: {{.*}} movl $8240, %eax +// 0x3030 - 0x1000 = 0x2030 diff --git a/test/ELF/i386-merge.s b/test/ELF/i386-merge.s index 00c954945a0f..d895c7327000 100644 --- a/test/ELF/i386-merge.s +++ b/test/ELF/i386-merge.s @@ -9,7 +9,7 @@ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_MERGE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x114 +// CHECK-NEXT: Address: 0x158 // CHECK-NEXT: Offset: // CHECK-NEXT: Size: // CHECK-NEXT: Link: @@ -35,11 +35,10 @@ // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 14010000 | +// CHECK-NEXT: 0000: 58010000 | // CHECK-NEXT: ) -// The content of .data should be the address of .mysec. 14010000 is 0x114 in -// little endian. +// The content of .data should be the address of .mysec. .data .long .mysec+4 diff --git a/test/ELF/i386-pic-plt.s b/test/ELF/i386-pic-plt.s new file mode 100644 index 000000000000..0d32436899a5 --- /dev/null +++ b/test/ELF/i386-pic-plt.s @@ -0,0 +1,12 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %p/Inputs/i386-pic-plt.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld %t.o %t2.so -o %t +// RUN: not ld.lld %t.o %t2.so -o %t -pie 2>&1 | FileCheck %s + +// CHECK: error: symbol 'foo' cannot be preempted; recompile with -fPIE + +.global _start +_start: + call foo diff --git a/test/ELF/i386-reloc-16-large-addend.s b/test/ELF/i386-reloc-16-large-addend.s new file mode 100644 index 000000000000..ceb4862d7935 --- /dev/null +++ b/test/ELF/i386-reloc-16-large-addend.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t +# RUN: ld.lld -Ttext 0x7c00 %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck %s + +# CHECK: Contents of section .text: +# CHECK-NEXT: 7c00 b800ff + +.code16 +.global _start +_start: + movw $_start+0x8300,%ax diff --git a/test/ELF/i386-reloc-16.s b/test/ELF/i386-reloc-16.s index d69e6fbc49a7..9a099a6ba3ed 100644 --- a/test/ELF/i386-reloc-16.s +++ b/test/ELF/i386-reloc-16.s @@ -4,11 +4,12 @@ // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2 // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t // RUN: ld.lld -shared %t %t1 -o %t3 +// RUN: llvm-objdump -s %t3 | FileCheck %s // CHECK: Contents of section .text: -// CHECK-NEXT: 200000 42 +// CHECK-NEXT: 1000 42 -// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s -// ERROR: relocation R_386_16 out of range: 65536 is not in [0, 65535] +// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s +// ERROR: relocation R_386_16 out of range: 65536 is not in [-32768, 32767] .short foo diff --git a/test/ELF/i386-reloc-8-large-addend.s b/test/ELF/i386-reloc-8-large-addend.s new file mode 100644 index 000000000000..61d638040847 --- /dev/null +++ b/test/ELF/i386-reloc-8-large-addend.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t +# RUN: ld.lld -Ttext 0x7c %t -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck %s + +# CHECK: Contents of section .text: +# CHECK-NEXT: 007c b4ff + +.code16 +.global _start +_start: + movb $_start+0x83,%ah diff --git a/test/ELF/i386-reloc-8.s b/test/ELF/i386-reloc-8.s index c6ae67120e22..b46aaa688261 100644 --- a/test/ELF/i386-reloc-8.s +++ b/test/ELF/i386-reloc-8.s @@ -4,11 +4,12 @@ // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-reloc-8-error.s -o %t2 // RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t // RUN: ld.lld -shared %t %t1 -o %t3 +// RUN: llvm-objdump -s %t3 | FileCheck %s // CHECK: Contents of section .text: -// CHECK-NEXT: 200000 42 +// CHECK-NEXT: 1000 ff -// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s -// ERROR: relocation R_386_8 out of range: 256 is not in [0, 255] +// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s +// ERROR: relocation R_386_8 out of range: 256 is not in [-128, 127] .byte foo diff --git a/test/ELF/i386-reloc-range.s b/test/ELF/i386-reloc-range.s index 6f72f7af73c7..4378bb6f9d18 100644 --- a/test/ELF/i386-reloc-range.s +++ b/test/ELF/i386-reloc-range.s @@ -14,7 +14,7 @@ // CHECK-NEXT: 200: {{.*}} jmp -1 // 0x10202 - 0x203 == 0xffff -// RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o %t2 2>&1 | FileCheck --check-prefix=ERR %s +// RUN: not ld.lld -Ttext 0x200 %t.o %t2.o -o /dev/null 2>&1 | FileCheck --check-prefix=ERR %s // ERR: {{.*}}:(.text+0x1): relocation R_386_PC16 out of range: 65536 is not in [-65536, 65535] diff --git a/test/ELF/i386-retpoline-nopic-linkerscript.s b/test/ELF/i386-retpoline-nopic-linkerscript.s new file mode 100644 index 000000000000..4243761d23e4 --- /dev/null +++ b/test/ELF/i386-retpoline-nopic-linkerscript.s @@ -0,0 +1,67 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: echo "SECTIONS { \ +// RUN: .text : { *(.text) } \ +// RUN: .plt : { *(.plt) } \ +// RUN: .got.plt : { *(.got.plt) } \ +// RUN: .dynstr : { *(.dynstr) } \ +// RUN: }" > %t.script +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt --script %t.script +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 10: ff 35 84 00 00 00 pushl 132 +// CHECK-NEXT: 16: 50 pushl %eax +// CHECK-NEXT: 17: a1 88 00 00 00 movl 136, %eax +// CHECK-NEXT: 1c: e8 0f 00 00 00 calll 15 <.plt+0x20> +// CHECK-NEXT: 21: f3 90 pause +// CHECK-NEXT: 23: 0f ae e8 lfence +// CHECK-NEXT: 26: eb f9 jmp -7 <.plt+0x11> +// CHECK-NEXT: 28: cc int3 +// CHECK-NEXT: 29: cc int3 +// CHECK-NEXT: 2a: cc int3 +// CHECK-NEXT: 2b: cc int3 +// CHECK-NEXT: 2c: cc int3 +// CHECK-NEXT: 2d: cc int3 +// CHECK-NEXT: 2e: cc int3 +// CHECK-NEXT: 2f: cc int3 +// CHECK-NEXT: 30: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 33: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 37: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 3b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 3d: 59 popl %ecx +// CHECK-NEXT: 3e: c3 retl +// CHECK-NEXT: 3f: cc int3 +// CHECK-NEXT: 40: 50 pushl %eax +// CHECK-NEXT: 41: a1 8c 00 00 00 movl 140, %eax +// CHECK-NEXT: 46: e8 e5 ff ff ff calll -27 <.plt+0x20> +// CHECK-NEXT: 4b: e9 d1 ff ff ff jmp -47 <.plt+0x11> +// CHECK-NEXT: 50: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 55: e9 b6 ff ff ff jmp -74 <.plt> +// CHECK-NEXT: 5a: cc int3 +// CHECK-NEXT: 5b: cc int3 +// CHECK-NEXT: 5c: cc int3 +// CHECK-NEXT: 5d: cc int3 +// CHECK-NEXT: 5e: cc int3 +// CHECK-NEXT: 5f: cc int3 +// CHECK-NEXT: 60: 50 pushl %eax +// CHECK-NEXT: 61: a1 90 00 00 00 movl 144, %eax +// CHECK-NEXT: 66: e8 c5 ff ff ff calll -59 <.plt+0x20> +// CHECK-NEXT: 6b: e9 b1 ff ff ff jmp -79 <.plt+0x11> +// CHECK-NEXT: 70: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 75: e9 96 ff ff ff jmp -106 <.plt> +// CHECK-NEXT: 7a: cc int3 +// CHECK-NEXT: 7b: cc int3 +// CHECK-NEXT: 7c: cc int3 +// CHECK-NEXT: 7d: cc int3 +// CHECK-NEXT: 7e: cc int3 +// CHECK-NEXT: 7f: cc int3 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/i386-retpoline-nopic.s b/test/ELF/i386-retpoline-nopic.s new file mode 100644 index 000000000000..79dd5a63cd69 --- /dev/null +++ b/test/ELF/i386-retpoline-nopic.s @@ -0,0 +1,65 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 11010: ff 35 04 20 01 00 pushl 73732 +// CHECK-NEXT: 11016: 50 pushl %eax +// CHECK-NEXT: 11017: a1 08 20 01 00 movl 73736, %eax +// CHECK-NEXT: 1101c: e8 0f 00 00 00 calll 15 <.plt+0x20> +// CHECK-NEXT: 11021: f3 90 pause +// CHECK-NEXT: 11023: 0f ae e8 lfence +// CHECK-NEXT: 11026: eb f9 jmp -7 <.plt+0x11> +// CHECK-NEXT: 11028: cc int3 +// CHECK-NEXT: 11029: cc int3 +// CHECK-NEXT: 1102a: cc int3 +// CHECK-NEXT: 1102b: cc int3 +// CHECK-NEXT: 1102c: cc int3 +// CHECK-NEXT: 1102d: cc int3 +// CHECK-NEXT: 1102e: cc int3 +// CHECK-NEXT: 1102f: cc int3 +// CHECK-NEXT: 11030: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 11033: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 11037: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 1103b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 1103d: 59 popl %ecx +// CHECK-NEXT: 1103e: c3 retl +// CHECK-NEXT: 1103f: cc int3 +// CHECK-NEXT: 11040: 50 pushl %eax +// CHECK-NEXT: 11041: a1 0c 20 01 00 movl 73740, %eax +// CHECK-NEXT: 11046: e8 e5 ff ff ff calll -27 <.plt+0x20> +// CHECK-NEXT: 1104b: e9 d1 ff ff ff jmp -47 <.plt+0x11> +// CHECK-NEXT: 11050: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 11055: e9 b6 ff ff ff jmp -74 <.plt> +// CHECK-NEXT: 1105a: cc int3 +// CHECK-NEXT: 1105b: cc int3 +// CHECK-NEXT: 1105c: cc int3 +// CHECK-NEXT: 1105d: cc int3 +// CHECK-NEXT: 1105e: cc int3 +// CHECK-NEXT: 1105f: cc int3 +// CHECK-NEXT: 11060: 50 pushl %eax +// CHECK-NEXT: 11061: a1 10 20 01 00 movl 73744, %eax +// CHECK-NEXT: 11066: e8 c5 ff ff ff calll -59 <.plt+0x20> +// CHECK-NEXT: 1106b: e9 b1 ff ff ff jmp -79 <.plt+0x11> +// CHECK-NEXT: 11070: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 11075: e9 96 ff ff ff jmp -106 <.plt> +// CHECK-NEXT: 1107a: cc int3 +// CHECK-NEXT: 1107b: cc int3 +// CHECK-NEXT: 1107c: cc int3 +// CHECK-NEXT: 1107d: cc int3 +// CHECK-NEXT: 1107e: cc int3 +// CHECK-NEXT: 1107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 00300100 00000000 00000000 50100100 +// CHECK-NEXT: 70100100 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/i386-retpoline-pic-linkerscript.s b/test/ELF/i386-retpoline-pic-linkerscript.s new file mode 100644 index 000000000000..6220332f91d1 --- /dev/null +++ b/test/ELF/i386-retpoline-pic-linkerscript.s @@ -0,0 +1,64 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: echo "SECTIONS { \ +// RUN: .text : { *(.text) } \ +// RUN: .plt : { *(.plt) } \ +// RUN: .got.plt : { *(.got.plt) } \ +// RUN: .dynstr : { *(.dynstr) } \ +// RUN: }" > %t.script +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt -pie --script %t.script +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 10: ff b3 84 00 00 00 pushl 132(%ebx) +// CHECK-NEXT: 16: 50 pushl %eax +// CHECK-NEXT: 17: 8b 83 88 00 00 00 movl 136(%ebx), %eax +// CHECK-NEXT: 1d: e8 0e 00 00 00 calll 14 <.plt+0x20> +// CHECK-NEXT: 22: f3 90 pause +// CHECK-NEXT: 24: 0f ae e8 lfence +// CHECK-NEXT: 27: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 29: cc int3 +// CHECK-NEXT: 2a: cc int3 +// CHECK-NEXT: 2b: cc int3 +// CHECK-NEXT: 2c: cc int3 +// CHECK-NEXT: 2d: cc int3 +// CHECK-NEXT: 2e: cc int3 +// CHECK-NEXT: 2f: cc int3 +// CHECK-NEXT: 30: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 33: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 37: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 3b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 3d: 59 popl %ecx +// CHECK-NEXT: 3e: c3 retl +// CHECK-NEXT: 3f: cc int3 +// CHECK-NEXT: 40: 50 pushl %eax +// CHECK-NEXT: 41: 8b 83 8c 00 00 00 movl 140(%ebx), %eax +// CHECK-NEXT: 47: e8 e4 ff ff ff calll -28 <.plt+0x20> +// CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 51: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 56: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 5b: cc int3 +// CHECK-NEXT: 5c: cc int3 +// CHECK-NEXT: 5d: cc int3 +// CHECK-NEXT: 5e: cc int3 +// CHECK-NEXT: 5f: cc int3 +// CHECK-NEXT: 60: 50 pushl %eax +// CHECK-NEXT: 61: 8b 83 90 00 00 00 movl 144(%ebx), %eax +// CHECK-NEXT: 67: e8 c4 ff ff ff calll -60 <.plt+0x20> +// CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 71: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 76: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 7b: cc int3 +// CHECK-NEXT: 7c: cc int3 +// CHECK-NEXT: 7d: cc int3 +// CHECK-NEXT: 7e: cc int3 +// CHECK-NEXT: 7f: cc int3 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/i386-retpoline-pic.s b/test/ELF/i386-retpoline-pic.s new file mode 100644 index 000000000000..3555950b168a --- /dev/null +++ b/test/ELF/i386-retpoline-pic.s @@ -0,0 +1,62 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux -position-independent %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld %t1.o %t2.so -o %t.exe -z retpolineplt -pie +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: ff b3 04 20 00 00 pushl 8196(%ebx) +// CHECK-NEXT: 1016: 50 pushl %eax +// CHECK-NEXT: 1017: 8b 83 08 20 00 00 movl 8200(%ebx), %eax +// CHECK-NEXT: 101d: e8 0e 00 00 00 calll 14 <.plt+0x20> +// CHECK-NEXT: 1022: f3 90 pause +// CHECK-NEXT: 1024: 0f ae e8 lfence +// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 89 0c 24 movl %ecx, (%esp) +// CHECK-NEXT: 1033: 8b 4c 24 04 movl 4(%esp), %ecx +// CHECK-NEXT: 1037: 89 44 24 04 movl %eax, 4(%esp) +// CHECK-NEXT: 103b: 89 c8 movl %ecx, %eax +// CHECK-NEXT: 103d: 59 popl %ecx +// CHECK-NEXT: 103e: c3 retl +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 50 pushl %eax +// CHECK-NEXT: 1041: 8b 83 0c 20 00 00 movl 8204(%ebx), %eax +// CHECK-NEXT: 1047: e8 e4 ff ff ff calll -28 <.plt+0x20> +// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 1051: 68 00 00 00 00 pushl $0 +// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 105b: cc int3 +// CHECK-NEXT: 105c: cc int3 +// CHECK-NEXT: 105d: cc int3 +// CHECK-NEXT: 105e: cc int3 +// CHECK-NEXT: 105f: cc int3 +// CHECK-NEXT: 1060: 50 pushl %eax +// CHECK-NEXT: 1061: 8b 83 10 20 00 00 movl 8208(%ebx), %eax +// CHECK-NEXT: 1067: e8 c4 ff ff ff calll -60 <.plt+0x20> +// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 1071: 68 08 00 00 00 pushl $8 +// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 107b: cc int3 +// CHECK-NEXT: 107c: cc int3 +// CHECK-NEXT: 107d: cc int3 +// CHECK-NEXT: 107e: cc int3 +// CHECK-NEXT: 107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 2000 00300000 00000000 00000000 51100000 +// CHECK-NEXT: 2010 71100000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/i386-tls-got.s b/test/ELF/i386-tls-got.s index 56be4a138d9b..efd45152164f 100644 --- a/test/ELF/i386-tls-got.s +++ b/test/ELF/i386-tls-got.s @@ -2,6 +2,6 @@ # RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %S/Inputs/i386-tls-got.s -o %t1.o # RUN: ld.lld %t1.o -o %t1.so -shared # RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t2.o -# RUN: ld.lld %t2.o %t1.so -o %t +# RUN: ld.lld %t2.o %t1.so -o /dev/null addl foobar@INDNTPOFF, %eax diff --git a/test/ELF/i386-tls-ie-shared.s b/test/ELF/i386-tls-ie-shared.s index 2b842a86eb0f..9e5ed1bcc462 100644 --- a/test/ELF/i386-tls-ie-shared.s +++ b/test/ELF/i386-tls-ie-shared.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o // RUN: ld.lld -shared %tso.o -o %tso diff --git a/test/ELF/icf-absolute.s b/test/ELF/icf-absolute.s index 09f6790907a1..3eef7a2d7e28 100644 --- a/test/ELF/icf-absolute.s +++ b/test/ELF/icf-absolute.s @@ -2,10 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-absolute.s -o %t2 -# RUN: ld.lld %t %t2 -o %t3 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t %t2 -o /dev/null --icf=all --print-icf-sections | FileCheck %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) .globl _start, f1, f2 _start: diff --git a/test/ELF/icf-c-identifier.s b/test/ELF/icf-c-identifier.s new file mode 100644 index 000000000000..cd11b98b57a6 --- /dev/null +++ b/test/ELF/icf-c-identifier.s @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | count 0 + +.section foo,"ax",@progbits,unique,0 +.byte 42 + +.section foo,"ax",@progbits,unique,1 +.byte 42 diff --git a/test/ELF/icf-comdat.s b/test/ELF/icf-comdat.s index aab6a00f484d..761dd2ecdc96 100644 --- a/test/ELF/icf-comdat.s +++ b/test/ELF/icf-comdat.s @@ -1,10 +1,10 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | FileCheck %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) .globl _start, f1, f2 _start: diff --git a/test/ELF/icf-different-output-sections.s b/test/ELF/icf-different-output-sections.s new file mode 100644 index 000000000000..085573120e4e --- /dev/null +++ b/test/ELF/icf-different-output-sections.s @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | count 0 + +.section .foo,"ax" +.byte 42 + +.section .bar,"ax" +.byte 42 diff --git a/test/ELF/icf-i386.s b/test/ELF/icf-i386.s index b01e0503d405..67c7262dadde 100644 --- a/test/ELF/icf-i386.s +++ b/test/ELF/icf-i386.s @@ -2,11 +2,11 @@ # This test is to make sure that we can handle implicit addends properly. # RUN: llvm-mc -filetype=obj -triple=i386-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 -# CHECK-NOT: removed .text.f3 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) +# CHECK-NOT: removing identical section {{.*}}:(.text.f3) .globl _start, f1, f2, f3 _start: diff --git a/test/ELF/icf-keep-unique.s b/test/ELF/icf-keep-unique.s new file mode 100644 index 000000000000..a6f883fc7b2a --- /dev/null +++ b/test/ELF/icf-keep-unique.s @@ -0,0 +1,43 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | FileCheck %s +# RUN: ld.lld %t -o %t2 --keep-unique f2 --keep-unique f4 --keep-unique f5 --icf=all --print-icf-sections 2>&1 | FileCheck %s -check-prefix=CHECK-KEEP + +// Base case, expect only .text.f1 to be kept +// CHECK: selected section {{.*}}:(.text.f1) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f2) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f3) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f4) +// CHECK-NEXT: removing identical section {{.*}}:(.text.f5) + +// With --keep-unique f2, f4 and f5 we expect only f3 and f5 to be removed. +// f5 is not matched by --keep-unique as it is a local symbol. +// CHECK-KEEP: warning: could not find symbol f5 to keep unique +// CHECK-KEEP: selected section {{.*}}:(.text.f1) +// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f3) +// CHECK-KEEP-NEXT: removing identical section {{.*}}:(.text.f5) + .globl _start, f1, f2, f3, f4 +_start: + ret + + .section .text.f1, "ax" +f1: + nop + + .section .text.f2, "ax" +f2: + nop + +.section .text.f3, "ax" +f3: + nop + +.section .text.f4, "ax" +f4: + nop + +# f5 is local, not found by --keep-unique f5 +.section .text.f5, "ax" +f5: + nop diff --git a/test/ELF/icf-link-order.s b/test/ELF/icf-link-order.s new file mode 100644 index 000000000000..440971de0f03 --- /dev/null +++ b/test/ELF/icf-link-order.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t --icf=all --print-icf-sections | count 0 + +.section .foo,"a",@progbits,unique,1 +foo1: +.byte 1 + +.section .foo,"a",@progbits,unique,2 +foo2: +.byte 2 + +.section .bar,"ao",@progbits,foo1,unique,1 +.byte 3 + +.section .bar,"ao",@progbits,foo2,unique,2 +.byte 3 diff --git a/test/ELF/icf-many-sections.s b/test/ELF/icf-many-sections.s new file mode 100644 index 000000000000..766a003dd77d --- /dev/null +++ b/test/ELF/icf-many-sections.s @@ -0,0 +1,62 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t +# RUN: ld.lld --icf=all --print-icf-sections %t -o /dev/null | FileCheck %s -allow-empty + +# CHECK-NOT: selected + +.macro gen_sections4 z + .section .a\z,"ax" + .section .b\z,"ax" + .section .c\z,"ax" + .section .d\z,"ax" +.endm + +.macro gen_sections8 z + gen_sections4 a\z + gen_sections4 b\z +.endm + +.macro gen_sections16 z + gen_sections8 a\z + gen_sections8 b\z +.endm + +.macro gen_sections32 x + gen_sections16 a\x + gen_sections16 b\x +.endm + +.macro gen_sections64 z + gen_sections32 a\z + gen_sections32 b\z +.endm + +.macro gen_sections128 z + gen_sections64 a\z + gen_sections64 b\z +.endm + +.macro gen_sections256 z + gen_sections128 a\z + gen_sections128 b\z +.endm + +.macro gen_sections512 z + gen_sections256 a\z + gen_sections256 b\z +.endm + +.macro gen_sections1024 z + gen_sections512 a\z + gen_sections512 b\z +.endm + +.macro gen_sections2048 z + gen_sections1024 a\z + gen_sections1024 b\z +.endm + +gen_sections2048 a + +.global _start +_start: diff --git a/test/ELF/icf-merge-sec.s b/test/ELF/icf-merge-sec.s index 1e866a0caa49..060f19d34694 100644 --- a/test/ELF/icf-merge-sec.s +++ b/test/ELF/icf-merge-sec.s @@ -2,10 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge-sec.s -o %t2 -# RUN: ld.lld %t %t2 -o %t3 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t %t2 -o /dev/null --icf=all --print-icf-sections | FileCheck %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) .section .rodata.str,"aMS",@progbits,1 .asciz "foo" diff --git a/test/ELF/icf-merge.s b/test/ELF/icf-merge.s index 06e852fe9dd5..5aa79f9d14ec 100644 --- a/test/ELF/icf-merge.s +++ b/test/ELF/icf-merge.s @@ -2,18 +2,18 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge.s -o %t1 -# RUN: ld.lld %t %t1 -o %t1.out --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t %t1 -o /dev/null --icf=all --print-icf-sections | FileCheck %s # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge2.s -o %t2 -# RUN: ld.lld %t %t2 -o %t3.out --icf=all --verbose 2>&1 | FileCheck --check-prefix=NOMERGE %s +# RUN: ld.lld %t %t2 -o %t3.out --icf=all --print-icf-sections | FileCheck --check-prefix=NOMERGE %s # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-merge3.s -o %t3 -# RUN: ld.lld %t %t3 -o %t3.out --icf=all --verbose 2>&1 | FileCheck --check-prefix=NOMERGE %s +# RUN: ld.lld %t %t3 -o %t3.out --icf=all --print-icf-sections | FileCheck --check-prefix=NOMERGE %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) -# NOMERGE-NOT: selected .text.f +# NOMERGE-NOT: selected section {{.*}}:(.text.f) .section .rodata.str,"aMS",@progbits,1 foo: diff --git a/test/ELF/icf-merge2.s b/test/ELF/icf-merge2.s new file mode 100644 index 000000000000..47c4c88d449a --- /dev/null +++ b/test/ELF/icf-merge2.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t --icf=all +# RUN: llvm-objdump -d %t | FileCheck %s + +# Test that we don't merge these. +# CHECK: leaq +# CHECK: leaq + + .section .merge1, "aM", @progbits, 8 +.Lfoo: + .quad 42 + + .section .merge2, "aM", @progbits, 4 +.Lbar: + .long 41 + + .section .text.foo, "ax", @progbits + leaq .Lfoo(%rip), %rax + + .section .text.bar, "ax", @progbits + leaq .Lbar(%rip), %rax diff --git a/test/ELF/icf-merged-sections.s b/test/ELF/icf-merged-sections.s new file mode 100644 index 000000000000..1f6e77ec5353 --- /dev/null +++ b/test/ELF/icf-merged-sections.s @@ -0,0 +1,37 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t --icf=all --ignore-data-address-equality --print-icf-sections | FileCheck -allow-empty --check-prefix=NOICF %s +# RUN: llvm-readobj -s -section-data %t | FileCheck %s + +# Check that merge synthetic sections are not merged by ICF. + +# NOICF-NOT: selected section <internal>:(.rodata) + +# CHECK: Name: .rodata +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 67452301 10325476 67452301 10325476 + +.section .rodata.cst4,"aM",@progbits,4 +rodata4: + .long 0x01234567 + .long 0x76543210 + .long 0x01234567 + .long 0x76543210 + +.section .rodata.cst8,"aM",@progbits,8 +rodata8: + .long 0x01234567 + .long 0x76543210 diff --git a/test/ELF/icf-non-mergeable.s b/test/ELF/icf-non-mergeable.s index 48ba2008cacc..978ac156b70e 100644 --- a/test/ELF/icf-non-mergeable.s +++ b/test/ELF/icf-non-mergeable.s @@ -8,10 +8,10 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ // RUN: %p/Inputs/icf-non-mergeable.s -o %t2 -// RUN: ld.lld %t1 %t2 -o %t3 --icf=all --verbose 2>&1 | FileCheck %s +// RUN: ld.lld %t1 %t2 -o /dev/null --icf=all --verbose 2>&1 | FileCheck %s -// CHECK-NOT: selected .text.f1 -// CHECK-NOT: removed .text.f2 +// CHECK-NOT: selected section '.text.f1' +// CHECK-NOT: removing identical section '.text.f2' .globl _start, f1, f2, d1, d2 _start: diff --git a/test/ELF/icf-none.s b/test/ELF/icf-none.s index 9ec1406de8a4..7c73361c2ce3 100644 --- a/test/ELF/icf-none.s +++ b/test/ELF/icf-none.s @@ -1,9 +1,9 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --icf=none --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o /dev/null --icf=all --icf=none --verbose 2>&1 | FileCheck %s -# CHECK-NOT: selected .text.f1 +# CHECK-NOT: selected section '.text.f1' .globl _start, f1, f2 _start: diff --git a/test/ELF/icf-relro.s b/test/ELF/icf-relro.s new file mode 100644 index 000000000000..874fa7b19f97 --- /dev/null +++ b/test/ELF/icf-relro.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld %t -o /dev/null --icf=all --ignore-data-address-equality --print-icf-sections | FileCheck %s + +# CHECK: selected section {{.*}}:(.data.rel.ro) +# CHECK: removing identical section {{.*}}:(.data.rel.ro.foo) + +.section .data.rel.ro,"aw" +.quad foo + +.section .data.rel.ro.foo,"aw" +foo: +.quad foo diff --git a/test/ELF/icf-safe.s b/test/ELF/icf-safe.s new file mode 100644 index 000000000000..b001fcc82ce4 --- /dev/null +++ b/test/ELF/icf-safe.s @@ -0,0 +1,182 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: llvm-objcopy %t1.o %t1copy.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/icf-safe.s -o %t2.o +# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=safe --print-icf-sections | FileCheck %s +# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections -shared | FileCheck --check-prefix=EXPORT %s +# RUN: ld.lld %t1.o %t2.o -o %t3 --icf=safe --print-icf-sections --export-dynamic | FileCheck --check-prefix=EXPORT %s +# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections | FileCheck --check-prefix=ALL %s +# RUN: ld.lld %t1.o %t2.o -o %t2 --icf=all --print-icf-sections --export-dynamic | FileCheck --check-prefix=ALL-EXPORT %s +# RUN: ld.lld %t1copy.o -o %t4 --icf=safe 2>&1 | FileCheck --check-prefix=OBJCOPY %s + +# CHECK-NOT: selected section {{.*}}:(.rodata.l1) +# CHECK: selected section {{.*}}:(.rodata.l3) +# CHECK: removing identical section {{.*}}:(.rodata.l4) + +# CHECK-NOT: selected section {{.*}}:(.text.f1) +# CHECK: selected section {{.*}}:(.text.f3) +# CHECK: removing identical section {{.*}}:(.text.f4) + +# CHECK-NOT: selected section {{.*}}:(.rodata.h1) +# CHECK: selected section {{.*}}:(.rodata.h3) +# CHECK: removing identical section {{.*}}:(.rodata.h4) + +# CHECK-NOT: selected section {{.*}}:(.rodata.g1) +# CHECK: selected section {{.*}}:(.rodata.g3) +# CHECK: removing identical section {{.*}}:(.rodata.g4) + +# CHECK-NOT: selected section {{.*}}:(.text.non_addrsig{{.}}) + +# With --icf=all address-significance implies keep-unique only for rodata, not +# text. +# ALL-NOT: selected section {{.*}}:(.rodata.l1) +# ALL: selected section {{.*}}:(.rodata.l3) +# ALL: removing identical section {{.*}}:(.rodata.l4) + +# ALL: selected section {{.*}}:(.text.f3) +# ALL: removing identical section {{.*}}:(.text.f4) + +# ALL: selected section {{.*}}:(.text.f1) +# ALL: removing identical section {{.*}}:(.text.f2) +# ALL: removing identical section {{.*}}:(.text.non_addrsig1) +# ALL: removing identical section {{.*}}:(.text.non_addrsig2) + +# ALL-NOT: selected section {{.*}}:(.rodata.h1) +# ALL: selected section {{.*}}:(.rodata.h3) +# ALL: removing identical section {{.*}}:(.rodata.h4) + +# ALL-NOT: selected section {{.*}}:(.rodata.g1) +# ALL: selected section {{.*}}:(.rodata.g3) +# ALL: removing identical section {{.*}}:(.rodata.g4) + +# llvm-mc normally emits an empty .text section into every object file. Since +# nothing actually refers to it via a relocation, it doesn't have any associated +# symbols (thus nor can anything refer to it via a relocation, making it safe to +# merge with the empty section in the other input file). Here we check that the +# only two sections merged are the two empty sections and the sections with only +# STB_LOCAL or STV_HIDDEN symbols. The dynsym entries should have prevented +# anything else from being merged. +# EXPORT-NOT: selected section +# EXPORT: selected section {{.*}}:(.rodata.l3) +# EXPORT: removing identical section {{.*}}:(.rodata.l4) +# EXPORT-NOT: selected section +# EXPORT: selected section {{.*}}:(.rodata.h3) +# EXPORT: removing identical section {{.*}}:(.rodata.h4) +# EXPORT-NOT: selected section +# EXPORT: selected section {{.*}}:(.text) +# EXPORT: removing identical section {{.*}}:(.text) +# EXPORT-NOT: selected section + +# If --icf=all is specified when exporting we can also merge the exported text +# sections, but not the exported rodata. +# ALL-EXPORT-NOT: selected section +# ALL-EXPORT: selected section {{.*}}:(.rodata.l3) +# ALL-EXPORT: removing identical section {{.*}}:(.rodata.l4) +# ALL-EXPORT-NOT: selected section +# ALL-EXPORT: selected section {{.*}}:(.text.f3) +# ALL-EXPORT: removing identical section {{.*}}:(.text.f4) +# ALL-EXPORT-NOT: selected section +# ALL-EXPORT: selected section {{.*}}:(.text.f1) +# ALL-EXPORT: removing identical section {{.*}}:(.text.f2) +# ALL-EXPORT: removing identical section {{.*}}:(.text.non_addrsig1) +# ALL-EXPORT: removing identical section {{.*}}:(.text.non_addrsig2) +# ALL-EXPORT-NOT: selected section +# ALL-EXPORT: selected section {{.*}}:(.rodata.h3) +# ALL-EXPORT: removing identical section {{.*}}:(.rodata.h4) +# ALL-EXPORT-NOT: selected section +# ALL-EXPORT: selected section {{.*}}:(.text) +# ALL-EXPORT: removing identical section {{.*}}:(.text) +# ALL-EXPORT-NOT: selected section + +# OBJCOPY: --icf=safe is incompatible with object files created using objcopy or ld -r + +.section .text.f1,"ax",@progbits +.globl f1 +f1: +ret + +.section .text.f2,"ax",@progbits +.globl f2 +f2: +ret + +.section .text.f3,"ax",@progbits +.globl f3 +f3: +ud2 + +.section .text.f4,"ax",@progbits +.globl f4 +f4: +ud2 + +.section .rodata.g1,"a",@progbits +.globl g1 +g1: +.byte 1 + +.section .rodata.g2,"a",@progbits +.globl g2 +g2: +.byte 1 + +.section .rodata.g3,"a",@progbits +.globl g3 +g3: +.byte 2 + +.section .rodata.g4,"a",@progbits +.globl g4 +g4: +.byte 2 + +.section .rodata.l1,"a",@progbits +l1: +.byte 3 + +.section .rodata.l2,"a",@progbits +l2: +.byte 3 + +.section .rodata.l3,"a",@progbits +l3: +.byte 4 + +.section .rodata.l4,"a",@progbits +l4: +.byte 4 + +.section .rodata.h1,"a",@progbits +.globl h1 +.hidden h1 +h1: +.byte 5 + +.section .rodata.h2,"a",@progbits +.globl h2 +.hidden h2 +h2: +.byte 5 + +.section .rodata.h3,"a",@progbits +.globl h3 +.hidden h3 +h3: +.byte 6 + +.section .rodata.h4,"a",@progbits +.globl h4 +.hidden h4 +h4: +.byte 6 + +.addrsig +.addrsig_sym f1 +.addrsig_sym f2 +.addrsig_sym g1 +.addrsig_sym g2 +.addrsig_sym l1 +.addrsig_sym l2 +.addrsig_sym h1 +.addrsig_sym h2 diff --git a/test/ELF/icf1.s b/test/ELF/icf1.s index e2562b5a83e7..5c6e667d53c7 100644 --- a/test/ELF/icf1.s +++ b/test/ELF/icf1.s @@ -1,10 +1,10 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections | FileCheck %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) .globl _start, f1, f2 _start: diff --git a/test/ELF/icf10.test b/test/ELF/icf10.test new file mode 100644 index 000000000000..96b4caf2f2e5 --- /dev/null +++ b/test/ELF/icf10.test @@ -0,0 +1,40 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: ld.lld --icf=all %t.o -o /dev/null --print-icf-sections 2>&1 | FileCheck %s + +# Checks that ICF does not merge 2 sections the offset of +# the relocations of which differ. + +# CHECK-NOT: selected + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_FREEBSD + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text.foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR] + Content: "FFFFFFFFFFFFFFFF" + - Name: .text.bar + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR] + Content: "FFFFFFFFFFFFFFFF" + - Name: .rela.text.foo + Type: SHT_RELA + Link: .symtab + Info: .text.foo + Relocations: + - Offset: 0x0000000000000000 + Symbol: '' + Type: R_X86_64_NONE + - Name: .rela.text.bar + Type: SHT_RELA + Link: .symtab + Info: .text.bar + Relocations: + - Offset: 0x0000000000000001 + Symbol: '' + Type: R_X86_64_NONE diff --git a/test/ELF/icf11.test b/test/ELF/icf11.test new file mode 100644 index 000000000000..8c3aa93568d7 --- /dev/null +++ b/test/ELF/icf11.test @@ -0,0 +1,52 @@ +# RUN: yaml2obj %s -o %t.o +# RUN: ld.lld --icf=all %t.o -o /dev/null --print-icf-sections 2>&1 | FileCheck %s + +# Checks that ICF does not merge 2 sections the type of +# the relocations of which differ. + +# CHECK-NOT: selected + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_FREEBSD + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_PROGBITS + Name: .text + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Content: "0000000000000000" + - Name: .text.foo + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR] + Content: "FFFFFFFFFFFFFFFF" + - Name: .text.bar + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR] + Content: "FFFFFFFFFFFFFFFF" + - Name: .rela.text.foo + Type: SHT_RELA + Link: .symtab + Info: .text.foo + Relocations: + - Offset: 0x0000000000000000 + Symbol: '' + Type: R_X86_64_NONE + - Name: .rela.text.bar + Type: SHT_RELA + Link: .symtab + Info: .text.bar + Relocations: + - Offset: 0 + Symbol: zed + Type: R_X86_64_64 +Symbols: + Global: + - Name: zed + Type: STT_FUNC + Section: .text + Value: 0x0 + Size: 8 diff --git a/test/ELF/icf12.s b/test/ELF/icf12.s new file mode 100644 index 000000000000..aa1e8af9ebd6 --- /dev/null +++ b/test/ELF/icf12.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: ld.lld %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s + +# Check that ICF does not merge 2 sections which relocations +# differs in addend only. + +# CHECK-NOT: selected + +.section .text +.globl _start +_start: + ret + +.section .text.foo, "ax" +.quad _start + 1 + +.section .text.bar, "ax" +.quad _start + 2 diff --git a/test/ELF/icf13.s b/test/ELF/icf13.s new file mode 100644 index 000000000000..2fe707f11c76 --- /dev/null +++ b/test/ELF/icf13.s @@ -0,0 +1,20 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: ld.lld -shared -z notext %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s + +## Check that ICF does not merge sections which relocations point to symbols +## that are not of the regular defined kind. + +# CHECK-NOT: selected + +.globl und + +.section .text +.globl _start +_start: + ret + +.section .text.foo, "ax" +.quad _start + +.section .text.bar, "ax" +.quad und diff --git a/test/ELF/icf14.s b/test/ELF/icf14.s new file mode 100644 index 000000000000..caa33e4d14bc --- /dev/null +++ b/test/ELF/icf14.s @@ -0,0 +1,26 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: ld.lld %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s + +# Check that ICF does not merge 2 sections which relocations +# refer to symbols that live in sections of the different types +# (regular input section and mergeable input sections in this case). + +# CHECK-NOT: selected + +.section .text +.globl _start +_start: + ret + +.section .rodata.str,"aMS",@progbits,1 +.globl rodata +rodata: +.asciz "foo" + +.section .text.foo, "ax" +.quad rodata + +.section .text.bar, "ax" +.quad _start diff --git a/test/ELF/icf15.s b/test/ELF/icf15.s new file mode 100644 index 000000000000..57c1735e1518 --- /dev/null +++ b/test/ELF/icf15.s @@ -0,0 +1,23 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: ld.lld %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s + +## Check that ICF does not merge sections which relocations have equal addends, +## but different target values. + +# CHECK-NOT: selected + +.globl und + +.section .text +.globl foo +foo: + .byte 0 +.globl bar +bar: + .byte 0 + +.section .text.foo, "ax" +.quad foo + +.section .text.bar, "ax" +.quad bar diff --git a/test/ELF/icf16.s b/test/ELF/icf16.s new file mode 100644 index 000000000000..e7650af37c3b --- /dev/null +++ b/test/ELF/icf16.s @@ -0,0 +1,23 @@ +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 +# RUN: ld.lld -shared -z notext %t1 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s + +## ICF is able to merge sections which relocations referring regular input sections +## or mergeable sections. .eh_frame is represented with a different kind of section, +## here we check that ICF code is able to handle and will not merge sections which +## relocations referring .eh_frame. + +# CHECK-NOT: selected + +.section ".eh_frame", "a", @progbits +.globl foo +foo: + .quad 0 +.globl bar +bar: + .quad 0 + +.section .text.foo, "ax" +.quad foo + +.section .text.bar, "ax" +.quad bar diff --git a/test/ELF/icf2.s b/test/ELF/icf2.s index fd0a311cbd1d..8a456c7ee018 100644 --- a/test/ELF/icf2.s +++ b/test/ELF/icf2.s @@ -2,10 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/icf2.s -o %t2 -# RUN: ld.lld %t1 %t2 -o %t --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t1 %t2 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) .globl _start, f1, f2 _start: diff --git a/test/ELF/icf3.s b/test/ELF/icf3.s index 40067cefb200..7ae4acfb131c 100644 --- a/test/ELF/icf3.s +++ b/test/ELF/icf3.s @@ -2,10 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/icf2.s -o %t2 -# RUN: ld.lld %t1 %t2 -o %t --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t1 %t2 -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s -# CHECK-NOT: Selected .text.f1 -# CHECK-NOT: Selected .text.f2 +# CHECK-NOT: selected section '.text.f1' from file +# CHECK-NOT: selected section '.text.f2' from file .globl _start, f1, f2 _start: diff --git a/test/ELF/icf4.s b/test/ELF/icf4.s index b7f40e805733..2b047968181c 100644 --- a/test/ELF/icf4.s +++ b/test/ELF/icf4.s @@ -1,10 +1,10 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s -# CHECK-NOT: Selected .text.f1 -# CHECK-NOT: Selected .text.f2 +# CHECK-NOT: selected section '.text.f1' +# CHECK-NOT: selected section '.text.f2' .globl _start, f1, f2 _start: diff --git a/test/ELF/icf5.s b/test/ELF/icf5.s index 749cc5e923a0..86c0bc4b9e40 100644 --- a/test/ELF/icf5.s +++ b/test/ELF/icf5.s @@ -1,10 +1,10 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s -# CHECK-NOT: Selected .text.f1 -# CHECK-NOT: Selected .text.f2 +# CHECK-NOT: selected section '.text.f1' +# CHECK-NOT: selected section '.text.f2' .globl _start, f1, f2 _start: diff --git a/test/ELF/icf6.s b/test/ELF/icf6.s index 6420868523bf..0819d51f1844 100644 --- a/test/ELF/icf6.s +++ b/test/ELF/icf6.s @@ -1,10 +1,10 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o /dev/null --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s -# CHECK-NOT: Selected .text.f1 -# CHECK-NOT: Selected .text.f2 +# CHECK-NOT: selected section '.text.f1' +# CHECK-NOT: selected section '.text.f2' .globl _start, f1, f2 _start: diff --git a/test/ELF/icf7.s b/test/ELF/icf7.s index 00fca793aeea..00383adbc0eb 100644 --- a/test/ELF/icf7.s +++ b/test/ELF/icf7.s @@ -1,11 +1,11 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections | FileCheck %s # RUN: llvm-objdump -t %t2 | FileCheck -check-prefix=ALIGN %s -# CHECK: selected .text.f1 -# CHECK: removed .text.f2 +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f2) # ALIGN: 0000000000201000 .text 00000000 _start # ALIGN: 0000000000201100 .text 00000000 f1 diff --git a/test/ELF/icf9.s b/test/ELF/icf9.s index de6db60f9684..809267700497 100644 --- a/test/ELF/icf9.s +++ b/test/ELF/icf9.s @@ -2,20 +2,21 @@ ### Make sure that we do not merge data. # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 --icf=all --verbose 2>&1 | FileCheck %s +# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections 2>&1 | FileCheck -allow-empty %s # RUN: llvm-readelf -S -W %t2 | FileCheck --check-prefix=SEC %s # SEC: .rodata PROGBITS 0000000000200120 000120 000002 00 A 0 0 1 -# CHECK-NOT: selected .rodata.d1 -# CHECK-NOT: selected .rodata.d2 +# CHECK-NOT: selected section {{.*}}:(.rodata.d1) +# CHECK-NOT: selected section {{.*}}:(.rodata.d2) # We do merge rodata if passed --icf-data -# RUN: ld.lld %t -o %t2 --icf=all --verbose --icf-data 2>&1 | FileCheck --check-prefix=DATA %s +# RUN: ld.lld %t -o %t2 --icf=all --print-icf-sections --ignore-data-address-equality | \ +# RUN: FileCheck --check-prefix=DATA %s # RUN: llvm-readelf -S -W %t2 | FileCheck --check-prefix=DATA-SEC %s -# DATA: selected .rodata.d1 -# DATA: removed .rodata.d2 +# DATA: selected section {{.*}}:(.rodata.d1) +# DATA: removing identical section {{.*}}:(.rodata.d2) # DATA-SEC: .rodata PROGBITS 0000000000200120 000120 000001 00 A 0 0 1 diff --git a/test/ELF/ignore-plugin.test b/test/ELF/ignore-plugin.test new file mode 100644 index 000000000000..fcd3fa64195c --- /dev/null +++ b/test/ELF/ignore-plugin.test @@ -0,0 +1,2 @@ +RUN: not ld.lld --plugin foo 2>&1 | FileCheck %s +CHECK: no input files diff --git a/test/ELF/incompatible-ar-first.s b/test/ELF/incompatible-ar-first.s index e076561d11ae..fbbe9de761ec 100644 --- a/test/ELF/incompatible-ar-first.s +++ b/test/ELF/incompatible-ar-first.s @@ -1,11 +1,11 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive.s -o %ta.o // RUN: llvm-ar rc %t.a %ta.o // RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %tb.o -// RUN: not ld.lld %t.a %tb.o 2>&1 | FileCheck %s +// RUN: not ld.lld %t.a %tb.o -o /dev/null 2>&1 | FileCheck %s // We used to crash when // * The first object seen by the symbol table is from an archive. // * -m was not used. // CHECK: .a({{.*}}a.o) is incompatible with {{.*}}b.o -// REQUIRES: x86 diff --git a/test/ELF/incompatible-section-flags.s b/test/ELF/incompatible-section-flags.s index 25d99945e009..30bbe75d766a 100644 --- a/test/ELF/incompatible-section-flags.s +++ b/test/ELF/incompatible-section-flags.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: not ld.lld -shared %t.o -o %t 2>&1 | FileCheck %s +// RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s // CHECK: error: incompatible section flags for .foo // CHECK-NEXT: >>> {{.*}}incompatible-section-flags.s.tmp.o:(.foo): 0x3 diff --git a/test/ELF/incompatible-section-types2.s b/test/ELF/incompatible-section-types2.s index 146e680ab271..3e281ce6c5da 100644 --- a/test/ELF/incompatible-section-types2.s +++ b/test/ELF/incompatible-section-types2.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s // CHECK: error: section type mismatch for .shstrtab // CHECK-NEXT: >>> <internal>:(.shstrtab): SHT_STRTAB diff --git a/test/ELF/incompatible.s b/test/ELF/incompatible.s index ce84606ad7e2..44c5b4bfcbf7 100644 --- a/test/ELF/incompatible.s +++ b/test/ELF/incompatible.s @@ -1,3 +1,4 @@ +// REQUIRES: x86,aarch64 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %ta.o // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %tb.o // RUN: ld.lld -shared %tb.o -o %ti686.so @@ -49,11 +50,10 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/archive2.s -o %ta.o // RUN: llvm-ar rc %t.a %ta.o // RUN: llvm-mc -filetype=obj -triple=i686-linux %s -o %tb.o -// RUN: not ld.lld %t.a %tb.o 2>&1 | FileCheck --check-prefix=ARCHIVE %s +// RUN: not ld.lld %t.a %tb.o 2>&1 -o %t | FileCheck --check-prefix=ARCHIVE %s // ARCHIVE: .a({{.*}}a.o) is incompatible with {{.*}}b.o .global _start _start: .data .long foo -// REQUIRES: x86,aarch64 diff --git a/test/ELF/init_fini_priority.s b/test/ELF/init_fini_priority.s index b10b925063e5..17003ce30dfe 100644 --- a/test/ELF/init_fini_priority.s +++ b/test/ELF/init_fini_priority.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: llvm-objdump -section-headers %t | FileCheck %s --check-prefix=OBJ // RUN: ld.lld %t -o %t.exe // RUN: llvm-objdump -s %t.exe | FileCheck %s -// REQUIRES: x86 // OBJ: 3 .init_array // OBJ-NEXT: 4 .init_array.100 diff --git a/test/ELF/invalid-cie-length.s b/test/ELF/invalid-cie-length.s index c6da95e609d6..7e73dd8aa5d3 100644 --- a/test/ELF/invalid-cie-length.s +++ b/test/ELF/invalid-cie-length.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s .section .eh_frame .byte 0 diff --git a/test/ELF/invalid-cie-length2.s b/test/ELF/invalid-cie-length2.s index 9140280ba5a7..a43491c17790 100644 --- a/test/ELF/invalid-cie-length2.s +++ b/test/ELF/invalid-cie-length2.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s .section .eh_frame .long 42 diff --git a/test/ELF/invalid-cie-length3.s b/test/ELF/invalid-cie-length3.s index fcbfa7f52ba8..3417efcba8fa 100644 --- a/test/ELF/invalid-cie-length3.s +++ b/test/ELF/invalid-cie-length3.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s .section .eh_frame .long 0xFFFFFFFC diff --git a/test/ELF/invalid-cie-length4.s b/test/ELF/invalid-cie-length4.s index 04f8eb2cca6b..cf3a6f513747 100644 --- a/test/ELF/invalid-cie-length4.s +++ b/test/ELF/invalid-cie-length4.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s .section .eh_frame .long 0xFFFFFFFF diff --git a/test/ELF/invalid-cie-length5.s b/test/ELF/invalid-cie-length5.s index bfa35edf7db5..223ce125853b 100644 --- a/test/ELF/invalid-cie-length5.s +++ b/test/ELF/invalid-cie-length5.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s .section .eh_frame .long 0xFFFFFFFF diff --git a/test/ELF/invalid-cie-reference.s b/test/ELF/invalid-cie-reference.s index fba2467e216a..0f64c4a429b4 100644 --- a/test/ELF/invalid-cie-reference.s +++ b/test/ELF/invalid-cie-reference.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: not ld.lld %t -o %t2 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s .section .eh_frame .long 0x14 diff --git a/test/ELF/invalid-eh-frame.s b/test/ELF/invalid-eh-frame.s new file mode 100644 index 000000000000..533442872346 --- /dev/null +++ b/test/ELF/invalid-eh-frame.s @@ -0,0 +1,17 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: corrupted .eh_frame: unexpected end of CIE +# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x8) + +.section .eh_frame + .byte 0x04 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 diff --git a/test/ELF/invalid-eh-frame2.s b/test/ELF/invalid-eh-frame2.s new file mode 100644 index 000000000000..c8995cbe1c81 --- /dev/null +++ b/test/ELF/invalid-eh-frame2.s @@ -0,0 +1,22 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: corrupted .eh_frame: corrupted CIE (failed to read string) +# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0x9) + +.section .eh_frame +.align 1 + .byte 0x08 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .byte 0x01 + .byte 0x01 + .byte 0x01 diff --git a/test/ELF/invalid-eh-frame3.s b/test/ELF/invalid-eh-frame3.s new file mode 100644 index 000000000000..44592cbe3c89 --- /dev/null +++ b/test/ELF/invalid-eh-frame3.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: corrupted .eh_frame: corrupted CIE (failed to read LEB128) +# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0xC) + +.section .eh_frame + .byte 0x08 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .byte 0x01 + .byte 0x00 + .byte 0x01 diff --git a/test/ELF/invalid-eh-frame4.s b/test/ELF/invalid-eh-frame4.s new file mode 100644 index 000000000000..4022c04476dc --- /dev/null +++ b/test/ELF/invalid-eh-frame4.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: corrupted .eh_frame: unknown .eh_frame augmentation string: + +.section .eh_frame + .byte 0x0E + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + .byte 0x01 + .byte 0x00 + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x01 + .byte 0x01 + .byte 0x01 + .byte 0x01 diff --git a/test/ELF/invalid-eh-frame5.s b/test/ELF/invalid-eh-frame5.s new file mode 100644 index 000000000000..eb153fa92c49 --- /dev/null +++ b/test/ELF/invalid-eh-frame5.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: corrupted .eh_frame: unknown .eh_frame augmentation string: + +.section .eh_frame + .byte 0x0E + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x03 + .byte 0x01 + .byte 0x00 + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x01 + .byte 0x01 + .byte 0x01 + .byte 0x01 diff --git a/test/ELF/invalid-eh-frame6.s b/test/ELF/invalid-eh-frame6.s new file mode 100644 index 000000000000..9b6b7f8bf87a --- /dev/null +++ b/test/ELF/invalid-eh-frame6.s @@ -0,0 +1,31 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: corrupted .eh_frame: unknown FDE encoding +# CHECK-NEXT: >>> defined in {{.*}}:(.eh_frame+0xE) + +.section .eh_frame + .byte 0x0E + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x01 + .byte 0x01 + .byte 0x01 + .byte 0x01 diff --git a/test/ELF/invalid-eh-frame7.s b/test/ELF/invalid-eh-frame7.s new file mode 100644 index 000000000000..81a0014049e0 --- /dev/null +++ b/test/ELF/invalid-eh-frame7.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: corrupted .eh_frame: DW_EH_PE_aligned encoding is not supported + +.section .eh_frame + .byte 0x0E + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x51 + .byte 0x01 + .byte 0x01 + .byte 0x01 diff --git a/test/ELF/invalid-eh-frame8.s b/test/ELF/invalid-eh-frame8.s new file mode 100644 index 000000000000..484fef29f8b3 --- /dev/null +++ b/test/ELF/invalid-eh-frame8.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: corrupted .eh_frame: corrupted CIE + +.section .eh_frame + .byte 0x0E + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x01 + + .byte 0x50 # Augmentation string: 'P','\0' + .byte 0x00 + + .byte 0x01 + + .byte 0x01 # LEB128 + .byte 0x01 # LEB128 + + .byte 0x03 + .byte 0x01 + .byte 0x01 + .byte 0x01 diff --git a/test/ELF/invalid-eh-frame9.s b/test/ELF/invalid-eh-frame9.s new file mode 100644 index 000000000000..73a102b4f90d --- /dev/null +++ b/test/ELF/invalid-eh-frame9.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: corrupted .eh_frame: CIE is too small + +.section .eh_frame + .byte 0x03 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 diff --git a/test/ELF/invalid-fde-rel.s b/test/ELF/invalid-fde-rel.s index f43b9da30033..f6513225b533 100644 --- a/test/ELF/invalid-fde-rel.s +++ b/test/ELF/invalid-fde-rel.s @@ -33,4 +33,4 @@ .long 0x0 .long 0x0 -// CHECK: 1 .eh_frame 00000018 +// CHECK: 1 .eh_frame 0000001c diff --git a/test/ELF/invalid-relocations.test b/test/ELF/invalid-relocations.test index cfeb44b03c67..7c32058c4353 100644 --- a/test/ELF/invalid-relocations.test +++ b/test/ELF/invalid-relocations.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s +# RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s !ELF FileHeader: diff --git a/test/ELF/invalid-undef-section-symbol.test b/test/ELF/invalid-undef-section-symbol.test index f634d6ad8c63..cb89306b781e 100644 --- a/test/ELF/invalid-undef-section-symbol.test +++ b/test/ELF/invalid-undef-section-symbol.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t.o -# RUN: not ld.lld -r %t.o -o %2.o 2>&1 | FileCheck %s +# RUN: not ld.lld -r %t.o -o /dev/null 2>&1 | FileCheck %s # We used to crash at this. # CHECK: STT_SECTION symbol should be defined diff --git a/test/ELF/invalid-z.s b/test/ELF/invalid-z.s deleted file mode 100644 index a5343c93e677..000000000000 --- a/test/ELF/invalid-z.s +++ /dev/null @@ -1,9 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: not ld.lld %t.o -o %t -z max-page-size 2>&1 | FileCheck %s -# CHECK: invalid max-page-size -# CHECK-NOT: error - -.global _start -_start: - nop diff --git a/test/ELF/invalid/Inputs/cie-version2.elf b/test/ELF/invalid/Inputs/cie-version2.elf Binary files differdeleted file mode 100644 index 87f8a5be76f4..000000000000 --- a/test/ELF/invalid/Inputs/cie-version2.elf +++ /dev/null diff --git a/test/ELF/invalid/Inputs/too-short.elf b/test/ELF/invalid/Inputs/too-short.elf Binary files differdeleted file mode 100644 index 077f392f1dc4..000000000000 --- a/test/ELF/invalid/Inputs/too-short.elf +++ /dev/null diff --git a/test/ELF/invalid/dynamic-section-size.s b/test/ELF/invalid/dynamic-section-size.s index 323dabaa9016..58a7d0688c25 100644 --- a/test/ELF/invalid/dynamic-section-size.s +++ b/test/ELF/invalid/dynamic-section-size.s @@ -1,4 +1,4 @@ ## dynamic-section-sh_size.elf has incorrect sh_size of dynamic section. -# RUN: not ld.lld %p/Inputs/dynamic-section-sh_size.elf -o %t2 2>&1 | \ +# RUN: not ld.lld %p/Inputs/dynamic-section-sh_size.elf -o /dev/null 2>&1 | \ # RUN: FileCheck %s # CHECK: error: {{.*}}: invalid sh_entsize diff --git a/test/ELF/invalid/eh-frame-hdr-no-out.s b/test/ELF/invalid/eh-frame-hdr-no-out.s index 8379253d9fd0..221ca205e591 100644 --- a/test/ELF/invalid/eh-frame-hdr-no-out.s +++ b/test/ELF/invalid/eh-frame-hdr-no-out.s @@ -1,6 +1,19 @@ // REQUIRES: x86 -// RUN: not ld.lld --eh-frame-hdr %p/Inputs/cie-version2.elf -o %t >& %t.log -// RUN: FileCheck %s < %t.log +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: not ld.lld --eh-frame-hdr %t -o /dev/null 2>&1 | FileCheck %s -// cie-version2.elf contains unsupported version of CIE = 2. -// CHECK: FDE version 1 or 3 expected, but got 2 +// CHECK: error: corrupted .eh_frame: FDE version 1 or 3 expected, but got 2 + +.section .eh_frame + .byte 0x08 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x02 + .byte 0x00 + .byte 0x00 + .byte 0x00 diff --git a/test/ELF/invalid/executable.s b/test/ELF/invalid/executable.s new file mode 100644 index 000000000000..254075146e15 --- /dev/null +++ b/test/ELF/invalid/executable.s @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld -o %t1.exe %t.o +# RUN: not ld.lld -o /dev/null %t1.exe 2>&1 | FileCheck %s +# CHECK: unknown file type + +.global _start +_start: + ret diff --git a/test/ELF/invalid/invalid-e_shnum.s b/test/ELF/invalid/invalid-e_shnum.s index 0c720ffa1713..34a742e18072 100644 --- a/test/ELF/invalid/invalid-e_shnum.s +++ b/test/ELF/invalid/invalid-e_shnum.s @@ -1,3 +1,3 @@ ## Spec says that "If a file has no section header table, e_shnum holds the value zero.", though ## in this test case it holds non-zero and lld used to crash. -# RUN: ld.lld %p/Inputs/invalid-e_shnum.elf -o %t2 +# RUN: ld.lld %p/Inputs/invalid-e_shnum.elf -o /dev/null diff --git a/test/ELF/invalid/invalid-elf.test b/test/ELF/invalid/invalid-elf.test index 8be0437c0680..80c8f41eb61d 100644 --- a/test/ELF/invalid/invalid-elf.test +++ b/test/ELF/invalid/invalid-elf.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -o %t -filetype=obj -triple x86_64-pc-linux # RUN: not ld.lld %t %p/Inputs/data-encoding.a -o %t2 2>&1 | \ diff --git a/test/ELF/invalid/merge-invalid-size.s b/test/ELF/invalid/merge-invalid-size.s index 1dbd7cf95b7d..cc2566d0ee87 100644 --- a/test/ELF/invalid/merge-invalid-size.s +++ b/test/ELF/invalid/merge-invalid-size.s @@ -1,10 +1,10 @@ // REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux -// RUN: not ld.lld %t.o -o %t.so 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s // CHECK: SHF_MERGE section size must be a multiple of sh_entsize // Test that we accept a zero sh_entsize. -// RUN: ld.lld %p/Inputs/shentsize-zero.elf -o %t2 +// RUN: ld.lld %p/Inputs/shentsize-zero.elf -o /dev/null .section .foo,"aM",@progbits,4 .short 42 diff --git a/test/ELF/invalid/mips-invalid-options-descriptor.s b/test/ELF/invalid/mips-invalid-options-descriptor.s index b23ecee6d0d2..c05e34785299 100644 --- a/test/ELF/invalid/mips-invalid-options-descriptor.s +++ b/test/ELF/invalid/mips-invalid-options-descriptor.s @@ -1,5 +1,5 @@ ## mips-invalid-options-descriptor.elf has option descriptor in ## .MIPS.options with size of zero. -# RUN: not ld.lld %p/Inputs/mips-invalid-options-descriptor.elf -o %t2 2>&1 | \ +# RUN: not ld.lld %p/Inputs/mips-invalid-options-descriptor.elf -o /dev/null 2>&1 | \ # RUN: FileCheck %s # CHECK: error: {{.*}}: invalid section offset diff --git a/test/ELF/invalid/reloc-section-reordered.test b/test/ELF/invalid/reloc-section-reordered.test new file mode 100644 index 000000000000..7ff4ed6e8ade --- /dev/null +++ b/test/ELF/invalid/reloc-section-reordered.test @@ -0,0 +1,30 @@ +# REQUIRES: x86 + +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck %s +# CHECK: unsupported relocation reference + +## YAML below lists .rela.text before .text, we do not support it. + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + OSABI: ELFOSABI_FREEBSD + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Type: SHT_REL + Name: .rela.text + Link: .symtab + Info: .text + AddressAlign: 0x04 + Relocations: + - Offset: 0 + Symbol: .text + Type: R_X86_64_NONE + - Type: SHT_PROGBITS + Name: .text + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x04 + Content: "FFFFFFFFFFFFFFFF" diff --git a/test/ELF/invalid/section-alignment2.s b/test/ELF/invalid/section-alignment2.s index aaef9f8bff5d..879ba8c03c14 100644 --- a/test/ELF/invalid/section-alignment2.s +++ b/test/ELF/invalid/section-alignment2.s @@ -1,5 +1,5 @@ ## section-alignment-notpow2.elf has section alignment ## 0xFFFFFFFF which is not a power of 2. -# RUN: not ld.lld %p/Inputs/section-alignment-notpow2.elf -o %t2 2>&1 | \ +# RUN: not ld.lld %p/Inputs/section-alignment-notpow2.elf -o /dev/null 2>&1 | \ # RUN: FileCheck %s # CHECK: section sh_addralign is not a power of 2 diff --git a/test/ELF/invalid/sht-group.s b/test/ELF/invalid/sht-group.s index f28035f0dac9..a4b684c83fd3 100644 --- a/test/ELF/invalid/sht-group.s +++ b/test/ELF/invalid/sht-group.s @@ -1,3 +1,3 @@ ## sht-group.elf contains SHT_GROUP section with invalid sh_info. -# RUN: not ld.lld %p/Inputs/sht-group.elf -o %t2 2>&1 | FileCheck %s +# RUN: not ld.lld %p/Inputs/sht-group.elf -o /dev/null 2>&1 | FileCheck %s # CHECK: invalid symbol index diff --git a/test/ELF/invalid/symbol-index.s b/test/ELF/invalid/symbol-index.s index 4ad1d6cb232c..e3989b4e1adc 100644 --- a/test/ELF/invalid/symbol-index.s +++ b/test/ELF/invalid/symbol-index.s @@ -5,6 +5,6 @@ ## [ 0] NULL 0000000000000000 000000 000000 00 0 0 0 ## ... ## [ 4] .symtab RELA 0000000000000000 000048 000030 18 1 2 8 -# RUN: not ld.lld %p/Inputs/symbol-index.elf -o %t2 2>&1 | \ +# RUN: not ld.lld %p/Inputs/symbol-index.elf -o /dev/null 2>&1 | \ # RUN: FileCheck --check-prefix=INVALID-SYMBOL-INDEX %s # INVALID-SYMBOL-INDEX: invalid symbol index diff --git a/test/ELF/invalid/symbol-name.s b/test/ELF/invalid/symbol-name.s index 8daee1a3fa78..53a20ef6af9c 100644 --- a/test/ELF/invalid/symbol-name.s +++ b/test/ELF/invalid/symbol-name.s @@ -3,5 +3,5 @@ ## symbol-name-offset.elf contains symbol with invalid (too large) ## st_name value. # RUN: not ld.lld %S/Inputs/symbol-name-offset.elf \ -# RUN: -o %t 2>&1 | FileCheck %s +# RUN: -o /dev/null 2>&1 | FileCheck %s # CHECK: invalid symbol name offset diff --git a/test/ELF/invalid/tls-symbol.s b/test/ELF/invalid/tls-symbol.s index 354ca573d5c0..99c47dc13023 100644 --- a/test/ELF/invalid/tls-symbol.s +++ b/test/ELF/invalid/tls-symbol.s @@ -1,5 +1,5 @@ # REQUIRES: x86 ## The test file contains an STT_TLS symbol but has no TLS section. -# RUN: not ld.lld %S/Inputs/tls-symbol.elf -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %S/Inputs/tls-symbol.elf -o /dev/null 2>&1 | FileCheck %s # CHECK: has an STT_TLS symbol but doesn't have an SHF_TLS section diff --git a/test/ELF/invalid/too-short.s b/test/ELF/invalid/too-short.s deleted file mode 100644 index deaf8218d6e0..000000000000 --- a/test/ELF/invalid/too-short.s +++ /dev/null @@ -1,5 +0,0 @@ -# REQUIRES: x86 - -## too-short.elf file is a truncated ELF. -# RUN: not ld.lld %S/Inputs/too-short.elf -o %t 2>&1 | FileCheck %s -# CHECK: file is too short diff --git a/test/ELF/just-symbols-cref.s b/test/ELF/just-symbols-cref.s new file mode 100644 index 000000000000..8581c53eb5df --- /dev/null +++ b/test/ELF/just-symbols-cref.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t1.exe -Ttext=0x10000 + +# RUN: ld.lld -just-symbols=%t1.exe -o %t2.exe -cref | FileCheck %s + +# CHECK: Symbol File +# CHECK-NEXT: bar {{.*exe}} +# CHECK-NEXT: foo {{.*exe}} + +.globl foo, bar +foo: + ret + +.section .data +.type bar, @object +.size bar, 40 +bar: + .zero 40 diff --git a/test/ELF/just-symbols.s b/test/ELF/just-symbols.s new file mode 100644 index 000000000000..856cf8c581ec --- /dev/null +++ b/test/ELF/just-symbols.s @@ -0,0 +1,20 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t1.exe -Ttext=0x10000 + +# RUN: ld.lld -just-symbols=%t1.exe -o %t2.exe +# RUN: llvm-readelf -symbols %t2.exe | FileCheck %s + +# CHECK: 0000000000011000 40 OBJECT GLOBAL DEFAULT ABS bar +# CHECK: 0000000000010000 0 NOTYPE GLOBAL DEFAULT ABS foo + +.globl foo, bar +foo: + ret + +.section .data +.type bar, @object +.size bar, 40 +bar: + .zero 40 diff --git a/test/ELF/libsearch.s b/test/ELF/libsearch.s index d21baf9dd95f..246a5d13951e 100644 --- a/test/ELF/libsearch.s +++ b/test/ELF/libsearch.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ // RUN: %p/Inputs/libsearch-dyn.s -o %tdyn.o @@ -10,7 +11,6 @@ // RUN: cp -f %t.dir/libls.so %t.dir/libls2.so // RUN: rm -f %t.dir/libls.a // RUN: llvm-ar rcs %t.dir/libls.a %tst.o -// REQUIRES: x86 // Should fail if no library specified // RUN: not ld.lld -l 2>&1 \ diff --git a/test/ELF/linkerscript/Inputs/addr.s b/test/ELF/linkerscript/Inputs/addr.s new file mode 100644 index 000000000000..65d99dcf99cd --- /dev/null +++ b/test/ELF/linkerscript/Inputs/addr.s @@ -0,0 +1,12 @@ +.text +.globl _start +_start: + +.section .foo.1,"a" +.quad 1 + +.section .foo.2,"a" +.quad 2 + +.section .foo.3,"a" +.quad 3 diff --git a/test/ELF/linkerscript/Inputs/align.s b/test/ELF/linkerscript/Inputs/align.s new file mode 100644 index 000000000000..c804536aa543 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/align.s @@ -0,0 +1,13 @@ +.global _start +_start: + nop + +.section .aaa, "a" +.quad 0 + +.section .bbb, "a" +.quad 0 + +.section .ccc, "a" +.quad 0 + diff --git a/test/ELF/linkerscript/Inputs/alignof.s b/test/ELF/linkerscript/Inputs/alignof.s new file mode 100644 index 000000000000..b288f94a12c9 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/alignof.s @@ -0,0 +1,15 @@ +.global _start +_start: + nop + +.section .aaa,"a" + .align 8 + .quad 0 + +.section .bbb,"a" + .align 16 + .quad 0 + +.section .ccc,"a" + .align 32 + .quad 0 diff --git a/test/ELF/linkerscript/Inputs/at2.s b/test/ELF/linkerscript/Inputs/at2.s new file mode 100644 index 000000000000..8c6548b53f69 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/at2.s @@ -0,0 +1,14 @@ +.section .foo1, "ax" +.quad 0 + +.section .foo2, "ax" +.quad 0 + +.section .bar1, "aw" +.quad 0 + +.section .bar2, "aw" +.quad 0 + +.section .bar3, "aw" +.quad 0 diff --git a/test/ELF/linkerscript/Inputs/at3.s b/test/ELF/linkerscript/Inputs/at3.s new file mode 100644 index 000000000000..8005c75723dd --- /dev/null +++ b/test/ELF/linkerscript/Inputs/at3.s @@ -0,0 +1,8 @@ +.section .foo1, "a" +.quad 0 + +.section .foo2, "ax" +.quad 0 + +.section .foo3, "ax" +.quad 0 diff --git a/test/ELF/linkerscript/Inputs/data-commands.s b/test/ELF/linkerscript/Inputs/data-commands.s new file mode 100644 index 000000000000..d5d78cfd9beb --- /dev/null +++ b/test/ELF/linkerscript/Inputs/data-commands.s @@ -0,0 +1,35 @@ +.global a +a = 0x11 + +.global b +b = 0x1122 + +.global c +c = 0x11223344 + +.global d +d = 0x1122334455667788 + +.section .foo.1, "a" + .byte 0xFF + +.section .foo.2, "a" + .byte 0xFF + +.section .foo.3, "a" + .byte 0xFF + +.section .foo.4, "a" + .byte 0xFF + +.section .bar.1, "a" + .byte 0xFF + +.section .bar.2, "a" + .byte 0xFF + +.section .bar.3, "a" + .byte 0xFF + +.section .bar.4, "a" + .byte 0xFF diff --git a/test/ELF/linkerscript/Inputs/data-segment-relro.s b/test/ELF/linkerscript/Inputs/data-segment-relro.s new file mode 100644 index 000000000000..668a2e2ca2a4 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/data-segment-relro.s @@ -0,0 +1,11 @@ +.global _start +_start: + .long bar + jmp *bar2@GOTPCREL(%rip) + +.section .data,"aw" +.quad 0 + +.zero 4 +.section .foo,"aw" +.section .bss,"",@nobits diff --git a/test/ELF/linkerscript/Inputs/define.s b/test/ELF/linkerscript/Inputs/define.s new file mode 100644 index 000000000000..bc60a233dcb4 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/define.s @@ -0,0 +1,8 @@ +.global defined +defined = 0 + +.section .foo,"a" +.quad 1 + +.section .bar,"a" +.quad 1 diff --git a/test/ELF/linkerscript/Inputs/eh-frame-reloc-out-of-range.s b/test/ELF/linkerscript/Inputs/eh-frame-reloc-out-of-range.s new file mode 100644 index 000000000000..19e50488050e --- /dev/null +++ b/test/ELF/linkerscript/Inputs/eh-frame-reloc-out-of-range.s @@ -0,0 +1,11 @@ +.text +.globl _start +_start: + .cfi_startproc + .cfi_lsda 0, _ex + nop + .cfi_endproc + +.data +_ex: + .word 0 diff --git a/test/ELF/linkerscript/Inputs/extend-pt-load.s b/test/ELF/linkerscript/Inputs/extend-pt-load.s new file mode 100644 index 000000000000..8993fb163346 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/extend-pt-load.s @@ -0,0 +1,3 @@ +nop +.section .data.rel.ro, "aw" +.byte 0 diff --git a/test/ELF/linkerscript/Inputs/fill.s b/test/ELF/linkerscript/Inputs/fill.s new file mode 100644 index 000000000000..b8eed890601b --- /dev/null +++ b/test/ELF/linkerscript/Inputs/fill.s @@ -0,0 +1,11 @@ +.text +.globl _start +_start: + +.section .aaa, "a" +.align 1 +.byte 0xAA + +.section .bbb, "a" +.align 1 +.byte 0xBB diff --git a/test/ELF/linkerscript/Inputs/implicit-program-header.script b/test/ELF/linkerscript/Inputs/implicit-program-header.script deleted file mode 100644 index 27dbea84c4e4..000000000000 --- a/test/ELF/linkerscript/Inputs/implicit-program-header.script +++ /dev/null @@ -1,12 +0,0 @@ -PHDRS -{ - ph_write PT_LOAD FLAGS(2); - ph_exec PT_LOAD FLAGS(1); -} - -SECTIONS -{ - .bar : { *(.bar) } : ph_exec - .foo : { *(.foo) } - .text : { *(.text) } : ph_write -} diff --git a/test/ELF/linkerscript/Inputs/insert-after.s b/test/ELF/linkerscript/Inputs/insert-after.s new file mode 100644 index 000000000000..88a6044cc968 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/insert-after.s @@ -0,0 +1,11 @@ +.section .foo.text,"ax" +.quad 0 + +.section .foo.data,"aw" +.quad 0 + +.section .text.1,"ax" +.quad 0 + +.section .data.1,"aw" +.quad 0 diff --git a/test/ELF/linkerscript/Inputs/insert-after.script b/test/ELF/linkerscript/Inputs/insert-after.script new file mode 100644 index 000000000000..cb95878bc5cf --- /dev/null +++ b/test/ELF/linkerscript/Inputs/insert-after.script @@ -0,0 +1,4 @@ +SECTIONS { + .text : { *(.text.*) } + .data : { *(.data.*) } +} diff --git a/test/ELF/linkerscript/Inputs/map-file2.s b/test/ELF/linkerscript/Inputs/map-file2.s new file mode 100644 index 000000000000..daf994eca172 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/map-file2.s @@ -0,0 +1,19 @@ +.global _start +_start: +.global _Z1fi +_Z1fi: +.cfi_startproc +nop +.cfi_endproc + +.section .aaa, "a"; +.quad 1; + +.section .bbb, "a"; +.quad 2; + +.section .ccc, "a"; +.quad 3; + +.section .ddd, "a"; +.quad 4 diff --git a/test/ELF/linkerscript/Inputs/provide-shared2.s b/test/ELF/linkerscript/Inputs/provide-shared2.s new file mode 100644 index 000000000000..f02fd650106a --- /dev/null +++ b/test/ELF/linkerscript/Inputs/provide-shared2.s @@ -0,0 +1,3 @@ +.global foo +.data +.dc.a foo diff --git a/test/ELF/linkerscript/Inputs/sections-va-overflow.s b/test/ELF/linkerscript/Inputs/sections-va-overflow.s new file mode 100644 index 000000000000..6bb049031c7d --- /dev/null +++ b/test/ELF/linkerscript/Inputs/sections-va-overflow.s @@ -0,0 +1,6 @@ +.global _start +_start: + retq + +.bss +.space 0x2000 diff --git a/test/ELF/linkerscript/Inputs/synthetic-symbols.s b/test/ELF/linkerscript/Inputs/synthetic-symbols.s new file mode 100644 index 000000000000..670e65cb80f4 --- /dev/null +++ b/test/ELF/linkerscript/Inputs/synthetic-symbols.s @@ -0,0 +1,16 @@ +.global _start +_start: + nop + +.section .foo,"a" + .quad 0 + +.section .bar,"a" + .long 0 + +.section .dah,"ax",@progbits + .cfi_startproc + nop + .cfi_endproc + +.global _begin_sec, _end_sec, _end_sec_abs diff --git a/test/ELF/linkerscript/absolute-expr.s b/test/ELF/linkerscript/absolute-expr.test index a9a674b859f4..9e8f517d0ac4 100644 --- a/test/ELF/linkerscript/absolute-expr.s +++ b/test/ELF/linkerscript/absolute-expr.test @@ -1,21 +1,19 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { \ -# RUN: .text : { \ -# RUN: bar1 = ALIGNOF(.text); \ -# RUN: bar2 = CONSTANT (MAXPAGESIZE); \ -# RUN: bar3 = SIZEOF (.text); \ -# RUN: bar4 = SIZEOF_HEADERS; \ -# RUN: bar5 = 0x42; \ -# RUN: bar6 = foo + 1; \ -# RUN: *(.text) \ -# RUN: } \ -# RUN: };" > %t.script -# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: echo ".global foo; foo = 0x123" | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o +# RUN: ld.lld -o %t.so --script %s %t.o -shared # RUN: llvm-readobj -t %t.so | FileCheck %s -.global foo -foo = 0x123 +SECTIONS { + .text : { + bar1 = ALIGNOF(.text); + bar2 = CONSTANT (MAXPAGESIZE); + bar3 = SIZEOF (.text); + bar4 = SIZEOF_HEADERS; + bar5 = 0x42; + bar6 = foo + 1; + *(.text) + } +} # CHECK: Symbol { # CHECK: Name: foo diff --git a/test/ELF/linkerscript/addr-zero.s b/test/ELF/linkerscript/addr-zero.test index 71251d3acfff..6253f619381b 100644 --- a/test/ELF/linkerscript/addr-zero.s +++ b/test/ELF/linkerscript/addr-zero.test @@ -1,7 +1,6 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { foo = ADDR(.text) - ABSOLUTE(ADDR(.text)); };" > %t.script -# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: ld.lld -o %t.so --script %s %t.o -shared # RUN: llvm-readobj --symbols %t.so | FileCheck %s # Test that the script creates a non absolute symbol with value @@ -9,10 +8,14 @@ # CHECK: Symbol { # CHECK: Name: foo -# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Value: 0x70 # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: None # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .text # CHECK-NEXT: } + +SECTIONS { + foo = ADDR(.text) - ABSOLUTE(ADDR(.text)); +}; diff --git a/test/ELF/linkerscript/addr.s b/test/ELF/linkerscript/addr.s deleted file mode 100644 index 2d3a7ab35767..000000000000 --- a/test/ELF/linkerscript/addr.s +++ /dev/null @@ -1,32 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { \ -# RUN: . = 0x1000; \ -# RUN: .text : { *(.text*) } \ -# RUN: .foo.1 : { *(.foo.1) } \ -# RUN: .foo.2 ADDR(.foo.1) + 0x100 : { *(.foo.2) } \ -# RUN: .foo.3 : { *(.foo.3) } \ -# RUN: }" > %t.script -# RUN: ld.lld %t --script %t.script -o %t1 -# RUN: llvm-objdump -section-headers %t1 | FileCheck %s - -# CHECK: Sections: -# CHECK-NEXT: Idx Name Size Address Type -# CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .text 00000000 0000000000001000 TEXT DATA -# CHECK-NEXT: 2 .foo.1 00000008 0000000000001000 DATA -# CHECK-NEXT: 3 .foo.2 00000008 0000000000001100 DATA -# CHECK-NEXT: 4 .foo.3 00000008 0000000000001108 DATA - -.text -.globl _start -_start: - -.section .foo.1,"a" - .quad 1 - -.section .foo.2,"a" - .quad 2 - -.section .foo.3,"a" - .quad 3 diff --git a/test/ELF/linkerscript/addr.test b/test/ELF/linkerscript/addr.test new file mode 100644 index 000000000000..db0568e56c76 --- /dev/null +++ b/test/ELF/linkerscript/addr.test @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/addr.s -o %t +# RUN: ld.lld %t --script %s -o %t1 +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000000 0000000000001000 TEXT +# CHECK-NEXT: 2 .foo.1 00000008 0000000000001000 DATA +# CHECK-NEXT: 3 .foo.2 00000008 0000000000001100 DATA +# CHECK-NEXT: 4 .foo.3 00000008 0000000000001108 DATA + +SECTIONS { + . = 0x1000; + .text : { *(.text*) } + .foo.1 : { *(.foo.1) } + .foo.2 ADDR(.foo.1) + 0x100 : { *(.foo.2) } + .foo.3 : { *(.foo.3) } +} diff --git a/test/ELF/linkerscript/address-expr-symbols.s b/test/ELF/linkerscript/address-expr-symbols.s new file mode 100644 index 000000000000..0b76c91a5c8b --- /dev/null +++ b/test/ELF/linkerscript/address-expr-symbols.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "SECTIONS { .bar (foo) : { } };" > %t.script +# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s +# CHECK: symbol not found: foo + +# RUN: echo "SECTIONS { .bar : AT(foo) { } };" > %t.script +# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s + +# RUN: echo "SECTIONS { .bar : ALIGN(foo) { } };" > %t.script +# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s + +# RUN: echo "SECTIONS { .bar : SUBALIGN(foo) { } };" > %t.script +# RUN: not ld.lld -o %t --script %t.script %t.o 2>&1 | FileCheck %s diff --git a/test/ELF/linkerscript/align-empty.s b/test/ELF/linkerscript/align-empty.s deleted file mode 100644 index 3ff71578410a..000000000000 --- a/test/ELF/linkerscript/align-empty.s +++ /dev/null @@ -1,18 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: abc : { } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: foo : { *(foo) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -shared -# RUN: llvm-objdump -section-headers %t1 | FileCheck %s -# CHECK: Sections: -# CHECK-NEXT: Idx Name Size Address -# CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 foo 00000001 0000000000001000 - - .section foo, "a" - .byte 0 diff --git a/test/ELF/linkerscript/align-empty.test b/test/ELF/linkerscript/align-empty.test new file mode 100644 index 000000000000..63fe32882c0b --- /dev/null +++ b/test/ELF/linkerscript/align-empty.test @@ -0,0 +1,22 @@ +# REQUIRES: x86 +# RUN: echo '.section foo, "a"; .byte 0' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o + +# RUN: ld.lld -o %t1 --script %s %t.o -shared +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s + +SECTIONS { + . = SIZEOF_HEADERS; + abc : {} + . = ALIGN(0x1000); + foo : { *(foo) } +} + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .dynsym 00000018 0000000000000190 +# CHECK-NEXT: 2 .gnu.hash 0000001c 00000000000001a8 +# CHECK-NEXT: 3 .hash 00000010 00000000000001c4 +# CHECK-NEXT: 4 .dynstr 00000001 00000000000001d4 +# CHECK-NEXT: 5 foo 00000001 0000000000001000 diff --git a/test/ELF/linkerscript/align-r.test b/test/ELF/linkerscript/align-r.test new file mode 100644 index 000000000000..684ac1e92328 --- /dev/null +++ b/test/ELF/linkerscript/align-r.test @@ -0,0 +1,21 @@ +# REQUIRES: x86 + +## Check output section ALIGN modifier with -r + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t1.o +# RUN: ld.lld -r -o %t2.o --script %s %t1.o +# RUN: llvm-readelf -s %t2.o | FileCheck %s + +# CHECK: Section Headers: +# CHECK-NEXT: Name Type Address Off Size ES Flg Lk Inf Al +# CHECK-NEXT: NULL 0000000000000000 000000 000000 00 +# CHECK-NEXT: .aaa PROGBITS 0000000000000000 000040 000008 00 A 0 0 1 +# CHECK-NEXT: .bbb PROGBITS 0000000000000000 001000 000008 00 A 0 0 4096 +# CHECK-NEXT: .ccc PROGBITS 0000000000000000 004000 000008 00 A 0 0 16384 + +SECTIONS { + . = 0x10000; + .aaa : { *(.aaa) } + .bbb : ALIGN(4096) { *(.bbb) } + .ccc : ALIGN(4096 * 4) { *(.ccc) } +} diff --git a/test/ELF/linkerscript/align-section-offset.s b/test/ELF/linkerscript/align-section-offset.s deleted file mode 100644 index 9c1603a19853..000000000000 --- a/test/ELF/linkerscript/align-section-offset.s +++ /dev/null @@ -1,11 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .foo : ALIGN(2M) { *(.foo) } }" > %t.script -# RUN: ld.lld -o %t --script %t.script %t.o -shared -# RUN: llvm-readelf -S -l %t | FileCheck %s - -# CHECK: .foo PROGBITS 0000000000200000 200000 000008 00 WA 0 0 2097152 -# CHECK: LOAD 0x200000 0x0000000000200000 0x0000000000200000 {{.*}} RW 0x200000 - - .section .foo, "aw" - .quad 42 diff --git a/test/ELF/linkerscript/align-section-offset.test b/test/ELF/linkerscript/align-section-offset.test new file mode 100644 index 000000000000..66508c472e94 --- /dev/null +++ b/test/ELF/linkerscript/align-section-offset.test @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: echo '.section .foo, "aw"; .quad 42' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o +# RUN: ld.lld -o %t --script %s %t.o -shared +# RUN: llvm-readelf -S -l %t | FileCheck %s + +SECTIONS { + .foo : ALIGN(2M) { *(.foo) } +} + +# CHECK: .foo PROGBITS 0000000000200000 200000 000008 00 WA 0 0 2097152 +# CHECK: LOAD 0x200000 0x0000000000200000 0x0000000000200000 {{.*}} RW 0x200000 diff --git a/test/ELF/linkerscript/align-section.s b/test/ELF/linkerscript/align-section.s deleted file mode 100644 index d26f15c87329..000000000000 --- a/test/ELF/linkerscript/align-section.s +++ /dev/null @@ -1,6 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .foo : ALIGN(2M) { } }" > %t.script -# RUN: ld.lld -o %t --script %t.script %t.o -shared - -# We would crash if an empty section had an ALIGN. diff --git a/test/ELF/linkerscript/align-section.test b/test/ELF/linkerscript/align-section.test new file mode 100644 index 000000000000..7a28fef2076e --- /dev/null +++ b/test/ELF/linkerscript/align-section.test @@ -0,0 +1,7 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o +# RUN: ld.lld -o %t --script %s %t.o -shared + +# lld shouldn't crash. + +SECTIONS { .foo : ALIGN(2M) {} } diff --git a/test/ELF/linkerscript/align.s b/test/ELF/linkerscript/align.s deleted file mode 100644 index 99e7382daa59..000000000000 --- a/test/ELF/linkerscript/align.s +++ /dev/null @@ -1,125 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -## Check that ALIGN command workable using location counter -# RUN: echo "SECTIONS { \ -# RUN: . = 0x10000; \ -# RUN: .aaa : { *(.aaa) } \ -# RUN: . = ALIGN(4096); \ -# RUN: .bbb : { *(.bbb) } \ -# RUN: . = ALIGN(4096 * 4); \ -# RUN: .ccc : { *(.ccc) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | FileCheck %s - -## Check that the two argument version of ALIGN command works -# RUN: echo "SECTIONS { \ -# RUN: . = ALIGN(0x1234, 0x10000); \ -# RUN: .aaa : { *(.aaa) } \ -# RUN: . = ALIGN(., 4096); \ -# RUN: .bbb : { *(.bbb) } \ -# RUN: . = ALIGN(., 4096 * 4); \ -# RUN: .ccc : { *(.ccc) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | FileCheck %s - -# CHECK: Sections: -# CHECK-NEXT: Idx Name Size Address Type -# CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA -# CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA -# CHECK-NEXT: 3 .ccc 00000008 0000000000014000 DATA - -## Check output sections ALIGN modificator -# RUN: echo "SECTIONS { \ -# RUN: . = 0x10000; \ -# RUN: .aaa : { *(.aaa) } \ -# RUN: .bbb : ALIGN(4096) { *(.bbb) } \ -# RUN: .ccc : ALIGN(4096 * 4) { *(.ccc) } \ -# RUN: }" > %t2.script -# RUN: ld.lld -o %t2 --script %t2.script %t -# RUN: llvm-objdump -section-headers %t2 | FileCheck %s - -## Check use of variables in align expressions: -# RUN: echo "VAR = 0x1000; \ -# RUN: __code_base__ = 0x10000; \ -# RUN: SECTIONS { \ -# RUN: . = __code_base__; \ -# RUN: .aaa : { *(.aaa) } \ -# RUN: .bbb : ALIGN(VAR) { *(.bbb) } \ -# RUN: . = ALIGN(., VAR * 4); \ -# RUN: .ccc : { *(.ccc) } \ -# RUN: __start_bbb = ADDR(.bbb); \ -# RUN: __end_bbb = ALIGN(__start_bbb + SIZEOF(.bbb), VAR); \ -# RUN: }" > %t3.script -# RUN: ld.lld -o %t3 --script %t3.script %t -# RUN: llvm-objdump -section-headers %t3 | FileCheck %s -# RUN: llvm-objdump -t %t3 | FileCheck -check-prefix SYMBOLS %s - -# SYMBOLS-LABEL: SYMBOL TABLE: -# SYMBOLS-NEXT: 0000000000000000 *UND* 00000000 -# SYMBOLS-NEXT: 0000000000014008 .text 00000000 _start -# SYMBOLS-NEXT: 0000000000010000 *ABS* 00000000 __code_base__ -# SYMBOLS-NEXT: 0000000000001000 *ABS* 00000000 VAR -# SYMBOLS-NEXT: 0000000000011000 .bbb 00000000 __start_bbb -# SYMBOLS-NEXT: 0000000000012000 .bbb 00000000 __end_bbb - -## Check that ALIGN zero do nothing and does not crash #1. -# RUN: echo "SECTIONS { . = ALIGN(0x123, 0); .aaa : { *(.aaa) } }" > %t.script -# RUN: ld.lld -o %t4 --script %t.script %t -# RUN: llvm-objdump -section-headers %t4 | FileCheck %s -check-prefix=ZERO - -# ZERO: Sections: -# ZERO-NEXT: Idx Name Size Address Type -# ZERO-NEXT: 0 00000000 0000000000000000 -# ZERO-NEXT: 1 .aaa 00000008 0000000000000123 DATA - -## Check that ALIGN zero do nothing and does not crash #2. -# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0); .aaa : { *(.aaa) } }" > %t.script -# RUN: ld.lld -o %t5 --script %t.script %t -# RUN: llvm-objdump -section-headers %t5 | FileCheck %s -check-prefix=ZERO - -## Test we fail gracefuly when alignment value is not a power of 2 (#1). -# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0x123, 3); .aaa : { *(.aaa) } }" > %t.script -# RUN: not ld.lld -o %t6 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR %s -# ERR: {{.*}}.script:1: alignment must be power of 2 - -## Test we fail gracefuly when alignment value is not a power of 2 (#2). -# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(3); .aaa : { *(.aaa) } }" > %t.script -# RUN: not ld.lld -o %t7 --script %t.script %t 2>&1 | FileCheck -check-prefix=ERR %s - -# RUN: echo "SECTIONS { \ -# RUN: . = 0xff8; \ -# RUN: .aaa : { \ -# RUN: *(.aaa) \ -# RUN: foo = ALIGN(., 0x100); \ -# RUN: bar = .; \ -# RUN: zed1 = ALIGN(., 0x100) + 1; \ -# RUN: zed2 = ALIGN(., 0x100) - 1; \ -# RUN: } \ -# RUN: .bbb : { *(.bbb); } \ -# RUN: .ccc : { *(.ccc); } \ -# RUN: .text : { *(.text); } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=OFFSET %s - -# OFFSET: 0000000000001000 .aaa 00000000 foo -# OFFSET: 0000000000001000 .aaa 00000000 bar -# OFFSET: 0000000000001001 .aaa 00000000 zed1 -# OFFSET: 0000000000000fff .aaa 00000000 zed2 - -.global _start -_start: - nop - -.section .aaa, "a" -.quad 0 - -.section .bbb, "a" -.quad 0 - -.section .ccc, "a" -.quad 0 diff --git a/test/ELF/linkerscript/align1.test b/test/ELF/linkerscript/align1.test new file mode 100644 index 000000000000..5804bf933740 --- /dev/null +++ b/test/ELF/linkerscript/align1.test @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o +# RUN: ld.lld -o %t --script %s %t.o +# RUN: llvm-objdump -section-headers %t | FileCheck %s + +SECTIONS { + . = 0x10000; + .aaa : { *(.aaa) } + . = ALIGN(4096); + .bbb : { *(.bbb) } + . = ALIGN(4096 * 4); + .ccc : { *(.ccc) } +} + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA +# CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA +# CHECK-NEXT: 3 .ccc 00000008 0000000000014000 DATA + +## Check that ALIGN zero do nothing and does not crash #1. +# RUN: echo "SECTIONS { . = ALIGN(0x123, 0); .aaa : { *(.aaa) } }" > %t.script +# RUN: ld.lld -o %t4 --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t4 | FileCheck %s -check-prefix=ZERO + +# ZERO: Sections: +# ZERO-NEXT: Idx Name Size Address Type +# ZERO-NEXT: 0 00000000 0000000000000000 +# ZERO-NEXT: 1 .aaa 00000008 0000000000000123 DATA + +## Check that ALIGN zero do nothing and does not crash #2. +# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0); .aaa : { *(.aaa) } }" > %t.script +# RUN: ld.lld -o %t5 --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t5 | FileCheck %s -check-prefix=ZERO + +## Test we fail gracefuly when alignment value is not a power of 2 (#1). +# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(0x123, 3); .aaa : { *(.aaa) } }" > %t.script +# RUN: not ld.lld -o %t6 --script %t.script %t.o 2>&1 | FileCheck -check-prefix=ERR %s + +# RUN: echo "SECTIONS { . = 0x123; . = ALIGN(3); .aaa : { *(.aaa) } }" > %t.script +# RUN: not ld.lld -o %t7 --script %t.script %t.o 2>&1 | FileCheck -check-prefix=ERR %s + +# ERR: {{.*}}.script:1: alignment must be power of 2 diff --git a/test/ELF/linkerscript/align2.test b/test/ELF/linkerscript/align2.test new file mode 100644 index 000000000000..a9003a403d75 --- /dev/null +++ b/test/ELF/linkerscript/align2.test @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o +# RUN: ld.lld -o %t --script %s %t.o +# RUN: llvm-objdump -section-headers %t | FileCheck %s + +SECTIONS { + . = ALIGN(0x1234, 0x10000); + .aaa : { *(.aaa) } + . = ALIGN(., 4096); + .bbb : { *(.bbb) } + . = ALIGN(., 4096 * 4); + .ccc : { *(.ccc) } +} + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA +# CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA +# CHECK-NEXT: 3 .ccc 00000008 0000000000014000 DATA diff --git a/test/ELF/linkerscript/align3.test b/test/ELF/linkerscript/align3.test new file mode 100644 index 000000000000..2a091fcbd6bd --- /dev/null +++ b/test/ELF/linkerscript/align3.test @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o +# RUN: ld.lld -o %t --script %s %t.o +# RUN: llvm-objdump -section-headers %t | FileCheck %s + +SECTIONS { + . = 0x10000; + .aaa : { *(.aaa) } + .bbb : ALIGN(4096) { *(.bbb) } + .ccc : ALIGN(4096 * 4) { *(.ccc) } +} + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .aaa 00000008 0000000000010000 DATA +# CHECK-NEXT: 2 .bbb 00000008 0000000000011000 DATA +# CHECK-NEXT: 3 .ccc 00000008 0000000000014000 DATA diff --git a/test/ELF/linkerscript/align4.test b/test/ELF/linkerscript/align4.test new file mode 100644 index 000000000000..9440d60f6385 --- /dev/null +++ b/test/ELF/linkerscript/align4.test @@ -0,0 +1,25 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o +# RUN: ld.lld -o %t --script %s %t.o +# RUN: llvm-objdump -t %t | FileCheck %s + +# CHECK-LABEL: SYMBOL TABLE: +# CHECK-NEXT: 0000000000000000 *UND* 00000000 +# CHECK-NEXT: 0000000000014008 .text 00000000 _start +# CHECK-NEXT: 0000000000010000 *ABS* 00000000 __code_base__ +# CHECK-NEXT: 0000000000001000 *ABS* 00000000 VAR +# CHECK-NEXT: 0000000000011000 .bbb 00000000 __start_bbb +# CHECK-NEXT: 0000000000012000 .bbb 00000000 __end_bbb + +VAR = 0x1000; +__code_base__ = 0x10000; + +SECTIONS { + . = __code_base__; + .aaa : { *(.aaa) } + .bbb : ALIGN(VAR) { *(.bbb) } + . = ALIGN(., VAR * 4); + .ccc : { *(.ccc) } + __start_bbb = ADDR(.bbb); + __end_bbb = ALIGN(__start_bbb + SIZEOF(.bbb), VAR); +} diff --git a/test/ELF/linkerscript/align5.test b/test/ELF/linkerscript/align5.test new file mode 100644 index 000000000000..47b5c8c03490 --- /dev/null +++ b/test/ELF/linkerscript/align5.test @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/align.s -o %t.o +# RUN: ld.lld -o %t --script %s %t.o +# RUN: llvm-objdump -t %t | FileCheck %s + +SECTIONS { + . = 0xff8; + .aaa : { + *(.aaa) + foo = ALIGN(., 0x100); + bar = .; + zed1 = ALIGN(., 0x100) + 1; + zed2 = ALIGN(., 0x100) - 1; + } + .bbb : { *(.bbb); } + .ccc : { *(.ccc); } + .text : { *(.text); } +} + +# CHECK: 0000000000001000 .aaa 00000000 foo +# CHECK: 0000000000001000 .aaa 00000000 bar +# CHECK: 0000000000001001 .aaa 00000000 zed1 +# CHECK: 0000000000000fff .aaa 00000000 zed2 diff --git a/test/ELF/linkerscript/alignof.s b/test/ELF/linkerscript/alignof.s deleted file mode 100644 index 8880634df243..000000000000 --- a/test/ELF/linkerscript/alignof.s +++ /dev/null @@ -1,41 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -# RUN: echo "SECTIONS { \ -# RUN: .aaa : { *(.aaa) } \ -# RUN: .bbb : { *(.bbb) } \ -# RUN: .ccc : { *(.ccc) } \ -# RUN: _aaa = ALIGNOF(.aaa); \ -# RUN: _bbb = ALIGNOF(.bbb); \ -# RUN: _ccc = ALIGNOF(.ccc); \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -# RUN: llvm-objdump -t %t1 | FileCheck %s -# CHECK: SYMBOL TABLE: -# CHECK: 0000000000000008 *ABS* 00000000 _aaa -# CHECK-NEXT: 0000000000000010 *ABS* 00000000 _bbb -# CHECK-NEXT: 0000000000000020 *ABS* 00000000 _ccc - -## Check that we error out if trying to get alignment of -## section that does not exist. -# RUN: echo "SECTIONS { \ -# RUN: _aaa = ALIGNOF(.foo); \ -# RUN: }" > %t.script -# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 \ -# RUN: | FileCheck -check-prefix=ERR %s -# ERR: {{.*}}.script:1: undefined section .foo -.global _start -_start: - nop - -.section .aaa,"a" - .align 8 - .quad 0 - -.section .bbb,"a" - .align 16 - .quad 0 - -.section .ccc,"a" - .align 32 - .quad 0 diff --git a/test/ELF/linkerscript/alignof.test b/test/ELF/linkerscript/alignof.test new file mode 100644 index 000000000000..0e3abf6133c9 --- /dev/null +++ b/test/ELF/linkerscript/alignof.test @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/alignof.s -o %t +# RUN: ld.lld -o %t1 --script %s %t +# RUN: llvm-objdump -t %t1 | FileCheck %s +# CHECK: SYMBOL TABLE: +# CHECK: 0000000000000008 *ABS* 00000000 _aaa +# CHECK-NEXT: 0000000000000010 *ABS* 00000000 _bbb +# CHECK-NEXT: 0000000000000020 *ABS* 00000000 _ccc + +SECTIONS { + .aaa : { *(.aaa) } + .bbb : { *(.bbb) } + .ccc : { *(.ccc) } + _aaa = ALIGNOF(.aaa); + _bbb = ALIGNOF(.bbb); + _ccc = ALIGNOF(.ccc); +} + +## Check that we error out if trying to get alignment of +## section that does not exist. +# RUN: echo "SECTIONS { _aaa = ALIGNOF(.foo); }" > %t.script +# RUN: not ld.lld -o %t1 --script %t.script %t 2>&1 \ +# RUN: | FileCheck -check-prefix=ERR %s +# ERR: {{.*}}.script:1: undefined section .foo diff --git a/test/ELF/linkerscript/arm-exidx-order.s b/test/ELF/linkerscript/arm-exidx-order.s deleted file mode 100644 index 1ff1711e60be..000000000000 --- a/test/ELF/linkerscript/arm-exidx-order.s +++ /dev/null @@ -1,19 +0,0 @@ -# REQUIRES: arm -# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o -# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; \ -# RUN: .ARM.exidx : { *(.ARM.exidx*) } \ -# RUN: .foo : { _foo = 0; } }" > %t.script -# RUN: ld.lld -T %t.script %t.o -shared -o %t.so -# RUN: llvm-readobj -s %t.so | FileCheck %s - -# CHECK: Section { -# CHECK: Index: -# CHECK: Name: .foo -# CHECK-NEXT: Type: SHT_NOBITS -# CHECK-NEXT: Flags [ -# CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: ] - -.fnstart -.cantunwind -.fnend diff --git a/test/ELF/linkerscript/arm-exidx-order.test b/test/ELF/linkerscript/arm-exidx-order.test new file mode 100644 index 000000000000..60abddfd77da --- /dev/null +++ b/test/ELF/linkerscript/arm-exidx-order.test @@ -0,0 +1,19 @@ +# REQUIRES: arm +# RUN: echo ".fnstart; .cantunwind; .fnend" \ +# RUN: | llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi - -o %t.o +# RUN: ld.lld -T %s %t.o -shared -o %t.so +# RUN: llvm-readobj -s %t.so | FileCheck %s + +SECTIONS { + . = SIZEOF_HEADERS; + .ARM.exidx : { *(.ARM.exidx*) } + .foo : { _foo = 0; } +} + +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .foo +# CHECK-NEXT: Type: SHT_NOBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] diff --git a/test/ELF/linkerscript/arm-exidx-phdrs.s b/test/ELF/linkerscript/arm-exidx-phdrs.s deleted file mode 100644 index 971702f55d7b..000000000000 --- a/test/ELF/linkerscript/arm-exidx-phdrs.s +++ /dev/null @@ -1,16 +0,0 @@ -// REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o -// RUN: echo "PHDRS { ph_text PT_LOAD; } \ -// RUN: SECTIONS { \ -// RUN: . = SIZEOF_HEADERS; \ -// RUN: .text : { *(.text) } : ph_text \ -// RUN: }" > %t.script -// RUN: ld.lld -T %t.script %t.o -shared -o %t.so -// RUN: llvm-readobj --program-headers %t.so | FileCheck %s - -// CHECK: Type: PT_ARM_EXIDX - -.fnstart -bx lr -.cantunwind -.fnend diff --git a/test/ELF/linkerscript/arm-exidx-phdrs.test b/test/ELF/linkerscript/arm-exidx-phdrs.test new file mode 100644 index 000000000000..208d4d72ad43 --- /dev/null +++ b/test/ELF/linkerscript/arm-exidx-phdrs.test @@ -0,0 +1,13 @@ +# REQUIRES: arm +# RUN: echo ".fnstart; bx lr; .cantunwind; .fnend" \ +# RUN: | llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi - -o %t.o +# RUN: ld.lld -T %s %t.o -shared -o %t.so +# RUN: llvm-readobj --program-headers %t.so | FileCheck %s + +# CHECK: Type: PT_ARM_EXIDX + +PHDRS { ph_text PT_LOAD; } +SECTIONS { + . = SIZEOF_HEADERS; + .text : { *(.text) } : ph_text +} diff --git a/test/ELF/linkerscript/arm-lscript.s b/test/ELF/linkerscript/arm-lscript.s deleted file mode 100644 index c377764e9776..000000000000 --- a/test/ELF/linkerscript/arm-lscript.s +++ /dev/null @@ -1,9 +0,0 @@ -// REQUIRES: arm -// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o -// RUN: echo "SECTIONS { \ -// RUN: .rel.dyn : { } \ -// RUN: .zed : { PROVIDE_HIDDEN (foobar = .); } \ -// RUN: }" > %t.script -// This is a test case for PR33029. Making sure that linker can digest -// the above script without dumping core. -// RUN: ld.lld -emit-relocs -T %t.script %t.o -shared -o %t.so diff --git a/test/ELF/linkerscript/arm-lscript.test b/test/ELF/linkerscript/arm-lscript.test new file mode 100644 index 000000000000..af2e6316ea43 --- /dev/null +++ b/test/ELF/linkerscript/arm-lscript.test @@ -0,0 +1,11 @@ +# REQUIRES: arm +# RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi /dev/null -o %t.o + +# This is a test case for PR33029. Making sure that linker can digest +# the above script without dumping core. +# RUN: ld.lld -emit-relocs -T %s %t.o -shared -o %t.so + +SECTIONS { + .rel.dyn : {} + .zed : { PROVIDE_HIDDEN (foobar = .); } +} diff --git a/test/ELF/linkerscript/assert.s b/test/ELF/linkerscript/assert.s index 73cc940669b9..f7113e5b25f0 100644 --- a/test/ELF/linkerscript/assert.s +++ b/test/ELF/linkerscript/assert.s @@ -6,7 +6,7 @@ # RUN: llvm-readobj %t1 > /dev/null # RUN: echo "SECTIONS { ASSERT(0, fail) }" > %t3.script -# RUN: not ld.lld -shared -o %t3 --script %t3.script %t1.o > %t.log 2>&1 +# RUN: not ld.lld -shared -o /dev/null --script %t3.script %t1.o > %t.log 2>&1 # RUN: FileCheck %s -check-prefix=FAIL < %t.log # FAIL: fail @@ -30,10 +30,11 @@ # RUN: ld.lld -shared -o %t6 --script %t6.script %t1.o # RUN: llvm-readobj %t6 > /dev/null +## Unlike the GNU ld, we accept the ASSERT without the semicolon. +## It is consistent with how ASSERT can be written outside of the +## output section declaration. # RUN: echo "SECTIONS { .foo : { ASSERT(1, \"true\") } }" > %t7.script -# RUN: not ld.lld -shared -o %t7 --script %t7.script %t1.o > %t.log 2>&1 -# RUN: FileCheck %s -check-prefix=CHECK-SEMI < %t.log -# CHECK-SEMI: error: {{.*}}.script:1: ; expected, but got } +# RUN: ld.lld -shared -o /dev/null --script %t7.script %t1.o .section .foo, "a" .quad 0 diff --git a/test/ELF/linkerscript/at-self-reference.s b/test/ELF/linkerscript/at-self-reference.s new file mode 100644 index 000000000000..7208a4b9fcd4 --- /dev/null +++ b/test/ELF/linkerscript/at-self-reference.s @@ -0,0 +1,63 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: . = 0x1000; \ +# RUN: .aaa : AT(ADDR(.aaa)) { *(.aaa) } \ +# RUN: .bbb : AT(ADDR(.bbb)) { *(.bbb) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x1000 +# CHECK-NEXT: FileSize: 3 +# CHECK-NEXT: MemSize: 3 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1008 +# CHECK-NEXT: VirtualAddress: 0x1008 +# CHECK-NEXT: PhysicalAddress: 0x1008 +# CHECK-NEXT: FileSize: 9 +# CHECK-NEXT: MemSize: 9 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_GNU_STACK (0x6474E551) +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: 0 +# CHECK-NEXT: MemSize: 0 +# CHECK-NEXT: Flags [ (0x6) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_W (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 0 +# CHECK-NEXT: } +# CHECK-NEXT:] + +.global _start +_start: + nop + + +.section .aaa, "a" +.asciz "aa" + +.section .bbb, "a" +.align 8 +.quad 0 diff --git a/test/ELF/linkerscript/at2.test b/test/ELF/linkerscript/at2.test new file mode 100644 index 000000000000..82c9ae1d2252 --- /dev/null +++ b/test/ELF/linkerscript/at2.test @@ -0,0 +1,58 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/at2.s -o %t.o +# RUN: ld.lld -o %t.exe %t.o --script %s +# RUN: llvm-readobj -program-headers %t.exe | FileCheck %s +# RUN: llvm-objdump -section-headers %t.exe | FileCheck %s --check-prefix=SECTIONS + +MEMORY { + AX (ax) : ORIGIN = 0x2000, LENGTH = 0x100 + AW (aw) : ORIGIN = 0x3000, LENGTH = 0x100 + FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x100 + RAM (aw) : ORIGIN = 0x7000, LENGTH = 0x100 +} + +SECTIONS { + .foo1 : { *(.foo1) } > AX AT>FLASH + .foo2 : { *(.foo2) } > AX + .bar1 : { *(.bar1) } > AW AT> RAM + .bar2 : { *(.bar2) } > AW AT > RAM + .bar3 : { *(.bar3) } > AW AT >RAM +} + +# CHECK: ProgramHeaders [ +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x2000 +# CHECK-NEXT: PhysicalAddress: 0x6000 +# CHECK-NEXT: FileSize: 16 +# CHECK-NEXT: MemSize: 16 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_X +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: +# CHECK-NEXT: } +# CHECK-NEXT: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x2000 +# CHECK-NEXT: VirtualAddress: 0x3000 +# CHECK-NEXT: PhysicalAddress: 0x7000 +# CHECK-NEXT: FileSize: 24 +# CHECK-NEXT: MemSize: 24 +# CHECK-NEXT: Flags [ +# CHECK-NEXT: PF_R +# CHECK-NEXT: PF_W +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } + +# SECTIONS: Sections: +# SECTIONS-NEXT: Idx Name Size Address +# SECTIONS-NEXT: 0 00000000 0000000000000000 +# SECTIONS-NEXT: 1 .foo1 00000008 0000000000002000 +# SECTIONS-NEXT: 2 .foo2 00000008 0000000000002008 +# SECTIONS-NEXT: 3 .text 00000000 0000000000002010 +# SECTIONS-NEXT: 4 .bar1 00000008 0000000000003000 +# SECTIONS-NEXT: 5 .bar2 00000008 0000000000003008 +# SECTIONS-NEXT: 6 .bar3 00000008 0000000000003010 diff --git a/test/ELF/linkerscript/at3.test b/test/ELF/linkerscript/at3.test new file mode 100644 index 000000000000..6344f38b304d --- /dev/null +++ b/test/ELF/linkerscript/at3.test @@ -0,0 +1,31 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/at3.s -o %t.o +# RUN: ld.lld %t.o --script %s -o %t +# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s + +MEMORY { + FOO (ax) : ORIGIN = 0x1000, LENGTH = 0x100 + BAR (ax) : ORIGIN = 0x2000, LENGTH = 0x100 + ZED (ax) : ORIGIN = 0x3000, LENGTH = 0x100 + FLASH (ax) : ORIGIN = 0x6000, LENGTH = 0x200 +} + +SECTIONS { + .foo1 : { *(.foo1) } > FOO AT>FLASH + .foo2 : { *(.foo2) BYTE(0x42) } > BAR AT>FLASH + .foo3 : { *(.foo3) } > ZED AT>FLASH +} + +# CHECK: .foo1 PROGBITS 0000000000001000 001000 +# CHECK: .foo2 PROGBITS 0000000000002000 002000 +# CHECK: .foo3 PROGBITS 0000000000003000 003000 + +# CHECK: Program Headers: +# CHECK-NOT: LOAD + +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000006000 +# CHECK-NEXT: LOAD 0x002000 0x0000000000002000 0x0000000000006008 +# CHECK-NEXT: LOAD 0x003000 0x0000000000003000 0x0000000000006011 + +# CHECK-NOT: LOAD diff --git a/test/ELF/linkerscript/at4.s b/test/ELF/linkerscript/at4.s new file mode 100644 index 000000000000..a6fa50820376 --- /dev/null +++ b/test/ELF/linkerscript/at4.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: echo "SECTIONS { \ +# RUN: . = 0x1000; \ +# RUN: .aaa : { *(.aaa) } \ +# RUN: .bbb : AT(0x2008) { *(.bbb) } \ +# RUN: .ccc : { *(.ccc) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-readobj -program-headers %t2 | FileCheck %s + +# CHECK: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x1000 +# CHECK-NEXT: PhysicalAddress: 0x1000 +# CHECK-NEXT: FileSize: 8 +# CHECK-NEXT: MemSize: 8 +# CHECK: Type: PT_LOAD +# CHECK-NEXT: Offset: 0x1008 +# CHECK-NEXT: VirtualAddress: 0x1008 +# CHECK-NEXT: PhysicalAddress: 0x2008 +# CHECK-NEXT: FileSize: 17 +# CHECK-NEXT: MemSize: 17 + +.global _start +_start: + nop + +.section .aaa, "a" +.quad 0 + +.section .bbb, "a" +.quad 0 + +.section .ccc, "a" +.quad 0 diff --git a/test/ELF/linkerscript/at5.test b/test/ELF/linkerscript/at5.test new file mode 100644 index 000000000000..8e1ed93bcad9 --- /dev/null +++ b/test/ELF/linkerscript/at5.test @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld -o %t.exe %t.o --script %s 2>&1 | FileCheck %s + +MEMORY { + FLASH (ax) : ORIGIN = 0x2000, LENGTH = 0x100 + RAM (aw) : ORIGIN = 0x5000, LENGTH = 0x100 +} + +SECTIONS { + .foo1 : AT(0x500) { *(.foo1) } > FLASH AT>FLASH +} + +# CHECK: error: section can't have both LMA and a load region diff --git a/test/ELF/linkerscript/broken-memory-declaration.s b/test/ELF/linkerscript/broken-memory-declaration.s new file mode 100644 index 000000000000..197c9cd22b6d --- /dev/null +++ b/test/ELF/linkerscript/broken-memory-declaration.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 + +## Check we do not crash. + +# RUN: echo "MEMORY { FLASH (rx) : ORIGIN = 0x1000< LENGTH" > %t.script +# RUN: not ld.lld -o %t --script %t.script 2>&1 | FileCheck %s +# CHECK: unexpected EOF + +# RUN: echo "MEMORY { FLASH (rx) : ORIGIN = 0x1000< ORIGIN" > %t.script +# RUN: not ld.lld -o %t --script %t.script 2>&1 | FileCheck %s + +# RUN: echo "MEMORY { FLASH (rx) : ORIGIN = 0x1000, LENGTH = CONSTANT" > %t.script +# RUN: not ld.lld -o %t --script %t.script 2>&1 | FileCheck %s diff --git a/test/ELF/linkerscript/bss-fill.s b/test/ELF/linkerscript/bss-fill.s deleted file mode 100644 index 92f9fdf56190..000000000000 --- a/test/ELF/linkerscript/bss-fill.s +++ /dev/null @@ -1,7 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { .bss : { . += 0x10000; *(.bss) } =0xFF };" > %t.script -# RUN: ld.lld -o %t --script %t.script %t.o - -.section .bss,"",@nobits -.short 0 diff --git a/test/ELF/linkerscript/bss-fill.test b/test/ELF/linkerscript/bss-fill.test new file mode 100644 index 000000000000..b7ed47656172 --- /dev/null +++ b/test/ELF/linkerscript/bss-fill.test @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: echo '.section .bss,"",@nobits; .short 0' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld -o %t --script %s %t.o + +## Check we do not crash. + +SECTIONS { + .bss : { + . += 0x10000; + *(.bss) + } =0xFF +} diff --git a/test/ELF/linkerscript/common-filespec.s b/test/ELF/linkerscript/common-filespec.test index 25bb486ed445..2afd91d3d5b7 100644 --- a/test/ELF/linkerscript/common-filespec.s +++ b/test/ELF/linkerscript/common-filespec.test @@ -1,11 +1,17 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfile0.o +# RUN: echo '.long 0; .comm common_uniq_0,4,4; .comm common_multiple,8,8' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %tfile0.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec1.s -o %tfile1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/common-filespec2.s -o %tfile2.o -# RUN: echo "SECTIONS { .common_0 : { *file0.o(COMMON) } .common_1 : { *file1.o(COMMON) } .common_2 : { *file2.o(COMMON) } }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %tfile0.o %tfile1.o %tfile2.o +# RUN: ld.lld -o %t1 --script %s %tfile0.o %tfile1.o %tfile2.o # RUN: llvm-readobj -s -t %t1 | FileCheck %s +SECTIONS { + .common_0 : { *file0.o(COMMON) } + .common_1 : { *file1.o(COMMON) } + .common_2 : { *file2.o(COMMON) } +} + # Make sure all 3 sections are allocated and they have sizes and alignments # corresponding to the commons assigned to them # CHECK: Section { @@ -96,10 +102,3 @@ # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: .common_2 # CHECK-NEXT: } - -.globl _start -_start: - jmp _start - -.comm common_uniq_0,4,4 -.comm common_multiple,8,8 diff --git a/test/ELF/linkerscript/compress-debug-sections-custom.s b/test/ELF/linkerscript/compress-debug-sections-custom.s new file mode 100644 index 000000000000..31fdd56381b0 --- /dev/null +++ b/test/ELF/linkerscript/compress-debug-sections-custom.s @@ -0,0 +1,35 @@ +# REQUIRES: x86, zlib + +# RUN: echo "SECTIONS { \ +# RUN: .text : { . += 0x10; *(.text) } \ +# RUN: .debug_str : { . += 0x10; *(.debug_str) } \ +# RUN: .debug_info : { . += 0x10; *(.debug_info) } \ +# RUN: }" > %t.script + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/../Inputs/compress-debug.s -o %t2.o +# RUN: ld.lld %t2.o %t.o -o %t1 --compress-debug-sections=zlib -T %t.script +# RUN: llvm-dwarfdump %t1 -debug-str | FileCheck %s +# These two checks correspond to the patched values of a_sym and a_debug_sym. +# T = 0x54 - address of .text input section for this file (the start address of +# .text is 0 by default, the size of the preceding .text in the other input +# file is 0x44, and the linker script adds an additional 0x10). +# S = 0x53 - offset of .debug_info section for this file (the size of +# the preceding .debug_info from the other input file is 0x43, and the +# linker script adds an additional 0x10). +# Also note that the .debug_str offsets are also offset by 0x10, as directed by +# the linker script. +# CHECK: 0x00000010: "T" +# CHECK: 0x00000014: "S" + +.text +a_sym: +nop + +.section .debug_str,"",@progbits +.long a_sym +.long a_debug_sym + +.section .debug_info,"",@progbits +a_debug_sym: +.long 0x88776655 diff --git a/test/ELF/linkerscript/constructor.s b/test/ELF/linkerscript/constructor.test index acb86fd88e27..edd2cd297997 100644 --- a/test/ELF/linkerscript/constructor.s +++ b/test/ELF/linkerscript/constructor.test @@ -1,7 +1,7 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { foo : { *(.foo) CONSTRUCTORS } }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t.o +# RUN: echo '.section foo, "a"; .byte 0' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld -o %t1 --script %s %t.o # RUN: llvm-objdump -section-headers %t1 | FileCheck %s # CHECK: Sections: @@ -9,5 +9,9 @@ # CHECK-NEXT: 0 00000000 # CHECK-NEXT: 1 foo 00000001 -.section foo, "a" -.byte 0 +SECTIONS { + foo : { + *(.foo) + CONSTRUCTORS + } +} diff --git a/test/ELF/linkerscript/copy-rel-symbol-value-err.s b/test/ELF/linkerscript/copy-rel-symbol-value-err.s index f134edbb1d0c..cd5262b142f5 100644 --- a/test/ELF/linkerscript/copy-rel-symbol-value-err.s +++ b/test/ELF/linkerscript/copy-rel-symbol-value-err.s @@ -3,7 +3,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/copy-rel-symbol-value.s -o %t2.o # RUN: ld.lld %t2.o -o %t2.so -shared # RUN: echo "SECTIONS { . = . + SIZEOF_HEADERS; foo = bar; }" > %t.script -# RUN: not ld.lld %t.o %t2.so --script %t.script -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o %t2.so --script %t.script -o /dev/null 2>&1 | FileCheck %s # CHECK: symbol not found: bar diff --git a/test/ELF/linkerscript/data-commands-gc.s b/test/ELF/linkerscript/data-commands-gc.s index 1afcc9a3bb81..6d5ae8c9ef9d 100644 --- a/test/ELF/linkerscript/data-commands-gc.s +++ b/test/ELF/linkerscript/data-commands-gc.s @@ -4,7 +4,7 @@ # RUN: ld.lld --gc-sections -o %t %t.o --script %t.script # RUN: llvm-objdump -t %t | FileCheck %s -# CHECK: 0000000000000011 .rodata 00000000 bar +# CHECK: 0000000000000008 .rodata 00000000 bar .section .rodata.bar .quad 0x1122334455667788 diff --git a/test/ELF/linkerscript/data-commands.s b/test/ELF/linkerscript/data-commands.s deleted file mode 100644 index 5a5655620dd9..000000000000 --- a/test/ELF/linkerscript/data-commands.s +++ /dev/null @@ -1,117 +0,0 @@ -# REQUIRES: x86,mips -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS \ -# RUN: { \ -# RUN: .foo : { \ -# RUN: *(.foo.1) \ -# RUN: BYTE(0x11) \ -# RUN: *(.foo.2) \ -# RUN: SHORT(0x1122) \ -# RUN: *(.foo.3) \ -# RUN: LONG(0x11223344) \ -# RUN: *(.foo.4) \ -# RUN: QUAD(0x1122334455667788) \ -# RUN: } \ -# RUN: .bar : { \ -# RUN: *(.bar.1) \ -# RUN: BYTE(a + 1) \ -# RUN: *(.bar.2) \ -# RUN: SHORT(b) \ -# RUN: *(.bar.3) \ -# RUN: LONG(c + 2) \ -# RUN: *(.bar.4) \ -# RUN: QUAD(d) \ -# RUN: } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t %t.o --script %t.script -# RUN: llvm-objdump -s %t | FileCheck %s - -# CHECK: Contents of section .foo: -# CHECK-NEXT: ff11ff22 11ff4433 2211ff88 77665544 -# CHECK-NEXT: 332211 - -# CHECK: Contents of section .bar: -# CHECK-NEXT: ff12ff22 11ff4633 2211ff88 77665544 -# CHECK-NEXT: 332211 - -# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %tmips64be -# RUN: ld.lld --script %t.script %tmips64be -o %t2 -# RUN: llvm-objdump -s %t2 | FileCheck %s --check-prefix=BE -# BE: Contents of section .foo: -# BE-NEXT: ff11ff11 22ff1122 3344ff11 22334455 -# BE-NEXT: 667788 -# BE-NEXT: Contents of section .bar: -# BE-NEXT: ff12ff11 22ff1122 3346ff11 22334455 -# BE-NEXT: 667788 - -# RUN: echo "MEMORY { \ -# RUN: rom (rwx) : ORIGIN = 0x00, LENGTH = 2K \ -# RUN: } \ -# RUN: SECTIONS { \ -# RUN: .foo : { \ -# RUN: *(.foo.1) \ -# RUN: BYTE(0x11) \ -# RUN: *(.foo.2) \ -# RUN: SHORT(0x1122) \ -# RUN: *(.foo.3) \ -# RUN: LONG(0x11223344) \ -# RUN: *(.foo.4) \ -# RUN: QUAD(0x1122334455667788) \ -# RUN: } > rom \ -# RUN: .bar : { \ -# RUN: *(.bar.1) \ -# RUN: BYTE(a + 1) \ -# RUN: *(.bar.2) \ -# RUN: SHORT(b) \ -# RUN: *(.bar.3) \ -# RUN: LONG(c + 2) \ -# RUN: *(.bar.4) \ -# RUN: QUAD(d) \ -# RUN: } > rom \ -# RUN: }" > %t-memory.script -# RUN: ld.lld -o %t-memory %t.o --script %t-memory.script -# RUN: llvm-objdump -s %t-memory | FileCheck %s --check-prefix=MEM - -# MEM: Contents of section .foo: -# MEM-NEXT: 0000 ff11ff22 11ff4433 2211ff88 77665544 -# MEM-NEXT: 0010 332211 - -# MEM: Contents of section .bar: -# MEM-NEXT: 0013 ff12ff22 11ff4633 2211ff88 77665544 -# MEM-NEXT: 0023 332211 - -.global a -a = 0x11 - -.global b -b = 0x1122 - -.global c -c = 0x11223344 - -.global d -d = 0x1122334455667788 - -.section .foo.1, "a" - .byte 0xFF - -.section .foo.2, "a" - .byte 0xFF - -.section .foo.3, "a" - .byte 0xFF - -.section .foo.4, "a" - .byte 0xFF - -.section .bar.1, "a" - .byte 0xFF - -.section .bar.2, "a" - .byte 0xFF - -.section .bar.3, "a" - .byte 0xFF - -.section .bar.4, "a" - .byte 0xFF diff --git a/test/ELF/linkerscript/data-commands1.test b/test/ELF/linkerscript/data-commands1.test new file mode 100644 index 000000000000..32c5978c30a8 --- /dev/null +++ b/test/ELF/linkerscript/data-commands1.test @@ -0,0 +1,45 @@ +# REQUIRES: x86,mips +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/data-commands.s -o %t.o +# RUN: ld.lld -o %t %t.o --script %s +# RUN: llvm-objdump -s %t | FileCheck %s + +SECTIONS { + .foo : { + *(.foo.1) + BYTE(0x11) + *(.foo.2) + SHORT(0x1122) + *(.foo.3) + LONG(0x11223344) + *(.foo.4) + QUAD(0x1122334455667788) + } + .bar : { + *(.bar.1) + BYTE(a + 1) + *(.bar.2) + SHORT(b) + *(.bar.3) + LONG(c + 2) + *(.bar.4) + QUAD(d) + } +} + +# CHECK: Contents of section .foo: +# CHECK-NEXT: ff11ff22 11ff4433 2211ff88 77665544 +# CHECK-NEXT: 332211 + +# CHECK: Contents of section .bar: +# CHECK-NEXT: ff12ff22 11ff4633 2211ff88 77665544 +# CHECK-NEXT: 332211 + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %p/Inputs/data-commands.s -o %t2.o +# RUN: ld.lld --script %s %t2.o -o %t2 +# RUN: llvm-objdump -s %t2 | FileCheck -check-prefix=BIGENDIAN %s +# BIGENDIAN: Contents of section .foo: +# BIGENDIAN-NEXT: ff11ff11 22ff1122 3344ff11 22334455 +# BIGENDIAN-NEXT: 667788 +# BIGENDIAN-NEXT: Contents of section .bar: +# BIGENDIAN-NEXT: ff12ff11 22ff1122 3346ff11 22334455 +# BIGENDIAN-NEXT: 667788 diff --git a/test/ELF/linkerscript/data-commands2.test b/test/ELF/linkerscript/data-commands2.test new file mode 100644 index 000000000000..e1efa35965cb --- /dev/null +++ b/test/ELF/linkerscript/data-commands2.test @@ -0,0 +1,40 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/data-commands.s -o %t.o +# RUN: ld.lld -o %t %t.o --script %s +# RUN: llvm-objdump -s %t | FileCheck %s + +MEMORY { + rom (rwx) : ORIGIN = 0x00, LENGTH = 2K +} + +SECTIONS { + .foo : { + *(.foo.1) + BYTE(0x11) + *(.foo.2) + SHORT(0x1122) + *(.foo.3) + LONG(0x11223344) + *(.foo.4) + QUAD(0x1122334455667788) + } > rom + + .bar : { + *(.bar.1) + BYTE(a + 1) + *(.bar.2) + SHORT(b) + *(.bar.3) + LONG(c + 2) + *(.bar.4) + QUAD(d) + } > rom +} + +# CHECK: Contents of section .foo: +# CHECK-NEXT: 0000 ff11ff22 11ff4433 2211ff88 77665544 +# CHECK-NEXT: 0010 332211 + +# CHECK: Contents of section .bar: +# CHECK-NEXT: 0013 ff12ff22 11ff4633 2211ff88 77665544 +# CHECK-NEXT: 0023 332211 diff --git a/test/ELF/linkerscript/data-segment-relro.s b/test/ELF/linkerscript/data-segment-relro.test index e835f42e22c6..aeaf08540871 100644 --- a/test/ELF/linkerscript/data-segment-relro.s +++ b/test/ELF/linkerscript/data-segment-relro.test @@ -1,29 +1,37 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/data-segment-relro.s -o %t1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o # RUN: ld.lld -shared %t2.o -o %t2.so -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: .plt : { *(.plt) } \ -# RUN: .text : { *(.text) } \ -# RUN: . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); \ -# RUN: .dynamic : { *(.dynamic) } \ -# RUN: .got : { *(.got) } \ -# RUN: . = DATA_SEGMENT_RELRO_END (1 ? 24 : 0, .); \ -# RUN: .got.plt : { *(.got.plt) } \ -# RUN: .data : { *(.data) } \ -# RUN: .bss : { *(.bss) } \ -# RUN: . = DATA_SEGMENT_END (.); \ -# RUN: }" > %t.script - ## With relro or without DATA_SEGMENT_RELRO_END just aligns to ## page boundary. -# RUN: ld.lld --hash-style=sysv -z norelro %t1.o %t2.so --script %t.script -o %t + +# RUN: ld.lld --hash-style=sysv -z norelro %t1.o %t2.so --script %s -o %t # RUN: llvm-readobj -s %t | FileCheck %s -# RUN: ld.lld --hash-style=sysv -z relro %t1.o %t2.so --script %t.script -o %t2 + +# RUN: ld.lld --hash-style=sysv -z relro %t1.o %t2.so --script %s -o %t2 # RUN: llvm-readobj -s %t2 | FileCheck %s +SECTIONS { + . = SIZEOF_HEADERS; + + .plt : { *(.plt) } + .text : { *(.text) } + + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + + .dynamic : { *(.dynamic) } + .got : { *(.got) } + + . = DATA_SEGMENT_RELRO_END (1 ? 24 : 0, .); + + .got.plt : { *(.got.plt) } + .data : { *(.data) } + .bss : { *(.bss) } + + . = DATA_SEGMENT_END (.); +} + # CHECK: Section { # CHECK: Index: # CHECK: Name: .got @@ -56,15 +64,3 @@ # CHECK-NEXT: AddressAlignment: # CHECK-NEXT: EntrySize: # CHECK-NEXT: } - -.global _start -_start: - .long bar - jmp *bar2@GOTPCREL(%rip) - -.section .data,"aw" -.quad 0 - -.zero 4 -.section .foo,"aw" -.section .bss,"",@nobits diff --git a/test/ELF/linkerscript/define.s b/test/ELF/linkerscript/define.s deleted file mode 100644 index b5f0b76e9e6b..000000000000 --- a/test/ELF/linkerscript/define.s +++ /dev/null @@ -1,25 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -# RUN: echo "SECTIONS \ -# RUN: { \ -# RUN: . = DEFINED(defined) ? 0x11000 : .; \ -# RUN: .foo : { *(.foo*) } \ -# RUN: . = DEFINED(notdefined) ? 0x12000 : 0x13000; \ -# RUN: .bar : { *(.bar*) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | FileCheck %s - -# CHECK: 1 .foo 00000008 0000000000011000 DATA -# CHECK: 2 .bar 00000008 0000000000013000 DATA -# CHECK: 3 .text 00000000 0000000000013008 TEXT DATA - -.global defined -defined = 0 - -.section .foo,"a" -.quad 1 - -.section .bar,"a" -.quad 1 diff --git a/test/ELF/linkerscript/define.test b/test/ELF/linkerscript/define.test new file mode 100644 index 000000000000..3a2e242e015c --- /dev/null +++ b/test/ELF/linkerscript/define.test @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/define.s -o %t.o +# RUN: ld.lld -o %t --script %s %t.o +# RUN: llvm-objdump -section-headers %t | FileCheck %s + +SECTIONS { + . = DEFINED(defined) ? 0x11000 : .; + .foo : { *(.foo*) } + . = DEFINED(notdefined) ? 0x12000 : 0x13000; + .bar : { *(.bar*) } +} + +# CHECK: 1 .foo 00000008 0000000000011000 DATA +# CHECK: 2 .bar 00000008 0000000000013000 DATA +# CHECK: 3 .text 00000000 0000000000013008 TEXT diff --git a/test/ELF/linkerscript/defsym.s b/test/ELF/linkerscript/defsym.s new file mode 100644 index 000000000000..467adaeea2f8 --- /dev/null +++ b/test/ELF/linkerscript/defsym.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "foo = 0x22;" > %t.script + +## This testcase checks that we apply -defsym and linker script +## in the same order are they specified in a command line. + +## Check that linker script can override -defsym assignments. +# RUN: ld.lld %t.o -defsym=foo=0x11 -script %t.script -o %t +# RUN: llvm-readobj -t %t | FileCheck %s +# CHECK: Name: foo +# CHECK-NEXT: Value: 0x22 + +## Check that -defsym can override linker script. Check that multiple +## -defsym commands for the same symbol are allowed. +# RUN: ld.lld %t.o -script %t.script -defsym=foo=0x11 -defsym=foo=0x33 -o %t +# RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=REORDER +# REORDER: Name: foo +# REORDER-NEXT: Value: 0x33 diff --git a/test/ELF/linkerscript/diag1.test b/test/ELF/linkerscript/diag1.test new file mode 100644 index 000000000000..73a627ff4ef5 --- /dev/null +++ b/test/ELF/linkerscript/diag1.test @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck -strict-whitespace %s + +SECTIONS { + .text + { *(.text) } + .keep : { *(.keep) } /* + comment line 1 + comment line 2 */ + .temp : { *(.temp) } +} + +CHECK: 6: malformed number: + +CHECK-NEXT: >>> .text + { *(.text) } +CHECK-NEXT: >>> ^ diff --git a/test/ELF/linkerscript/diag2.test b/test/ELF/linkerscript/diag2.test new file mode 100644 index 000000000000..05cd4c3a752a --- /dev/null +++ b/test/ELF/linkerscript/diag2.test @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck -strict-whitespace %s + +UNKNOWN_TAG { + .text : { *(.text) } + .keep : { *(.keep) } + .temp : { *(.temp) } +} + +CHECK: 5: unknown directive: UNKNOWN_TAG +CHECK-NEXT: >>> UNKNOWN_TAG { +CHECK-NEXT: >>> ^ diff --git a/test/ELF/linkerscript/diag3.test b/test/ELF/linkerscript/diag3.test new file mode 100644 index 000000000000..8ffc9d4d864c --- /dev/null +++ b/test/ELF/linkerscript/diag3.test @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck -strict-whitespace %s + +SECTIONS { + .text : { *(.text) } + .keep : { *(.keep) } + boom .temp : { *(.temp) } +} + +# CHECK: 8: malformed number: .temp +# CHECK-NEXT: >>> boom .temp : { *(.temp) } +# CHECK-NEXT: >>> ^ diff --git a/test/ELF/linkerscript/diag4.test b/test/ELF/linkerscript/diag4.test new file mode 100644 index 000000000000..484bdf26fe72 --- /dev/null +++ b/test/ELF/linkerscript/diag4.test @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: echo "INCLUDE \"%s\"" > %t.script +# RUN: not ld.lld -shared %t.o -o %t --script %t.script 2>&1 | FileCheck -strict-whitespace %s + +SECTIONS { + .text : { *(.text) } + .keep : { *(.keep) } + boom .temp : { *(.temp) } +} + +# CHECK: 9: malformed number: .temp +# CHECK-NEXT: >>> boom .temp : { *(.temp) } +# CHECK-NEXT: >>> ^
\ No newline at end of file diff --git a/test/ELF/linkerscript/diag5.test b/test/ELF/linkerscript/diag5.test new file mode 100644 index 000000000000..38a774e747ab --- /dev/null +++ b/test/ELF/linkerscript/diag5.test @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: echo "INCLUDE \"%s\"" > %t.script +# RUN: not ld.lld -shared %t.o -o %t --script %t.script 2>&1 | FileCheck -strict-whitespace %s + +SECTIONS { + .text : { *(.text) } + .keep : { *(.keep) } + boom .temp : { *(.temp) } +} + +# CHECK: 9: malformed number: .temp +# CHECK-NEXT: >>> boom .temp : { *(.temp) } +# CHECK-NEXT: >>> ^ diff --git a/test/ELF/linkerscript/diag6.test b/test/ELF/linkerscript/diag6.test new file mode 100644 index 000000000000..e4ad4d96d1dd --- /dev/null +++ b/test/ELF/linkerscript/diag6.test @@ -0,0 +1,7 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld -shared %t.o -o %t --script %s 2>&1 | FileCheck %s + +SECTIONS /* + +CHECK: error: unclosed comment in a linker script diff --git a/test/ELF/linkerscript/diagnostic.s b/test/ELF/linkerscript/diagnostic.s deleted file mode 100644 index af185729c430..000000000000 --- a/test/ELF/linkerscript/diagnostic.s +++ /dev/null @@ -1,106 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -## Take some valid script with multiline comments -## and check it actually works: -# RUN: echo "SECTIONS {" > %t.script -# RUN: echo ".text : { *(.text) }" >> %t.script -# RUN: echo ".keep : { *(.keep) } /*" >> %t.script -# RUN: echo "comment line 1" >> %t.script -# RUN: echo "comment line 2 */" >> %t.script -# RUN: echo ".temp : { *(.temp) } }" >> %t.script -# RUN: ld.lld -shared %t -o %t1 --script %t.script - -## Change ":" to "+" at line 2, check that error -## message starts from correct line number: -# RUN: echo "SECTIONS {" > %t.script -# RUN: echo ".text + { *(.text) }" >> %t.script -# RUN: echo ".keep : { *(.keep) } /*" >> %t.script -# RUN: echo "comment line 1" >> %t.script -# RUN: echo "comment line 2 */" >> %t.script -# RUN: echo ".temp : { *(.temp) } }" >> %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR1 %s -# ERR1: {{.*}}.script:2: - -## Change ":" to "+" at line 3 now, check correct error line number: -# RUN: echo "SECTIONS {" > %t.script -# RUN: echo ".text : { *(.text) }" >> %t.script -# RUN: echo ".keep + { *(.keep) } /*" >> %t.script -# RUN: echo "comment line 1" >> %t.script -# RUN: echo "comment line 2 */" >> %t.script -# RUN: echo ".temp : { *(.temp) } }" >> %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR2 %s -# ERR2: {{.*}}.script:3: - -## Change ":" to "+" at line 6, after multiline comment, -## check correct error line number: -# RUN: echo "SECTIONS {" > %t.script -# RUN: echo ".text : { *(.text) }" >> %t.script -# RUN: echo ".keep : { *(.keep) } /*" >> %t.script -# RUN: echo "comment line 1" >> %t.script -# RUN: echo "comment line 2 */" >> %t.script -# RUN: echo ".temp + { *(.temp) } }" >> %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | FileCheck -check-prefix=ERR5 %s -# ERR5: {{.*}}.script:6: - -## Check that text of lines and pointer to 'bad' token are working ok. -# RUN: echo "UNKNOWN_TAG {" > %t.script -# RUN: echo ".text : { *(.text) }" >> %t.script -# RUN: echo ".keep : { *(.keep) }" >> %t.script -# RUN: echo ".temp : { *(.temp) } }" >> %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \ -# RUN: FileCheck -check-prefix=ERR6 -strict-whitespace %s -# ERR6: error: {{.*}}.script:1: unknown directive: UNKNOWN_TAG -# ERR6-NEXT: >>> UNKNOWN_TAG { -# ERR6-NEXT: >>> ^ - -## One more check that text of lines and pointer to 'bad' token are working ok. -# RUN: echo "SECTIONS {" > %t.script -# RUN: echo ".text : { *(.text) }" >> %t.script -# RUN: echo ".keep : { *(.keep) }" >> %t.script -# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \ -# RUN: FileCheck -check-prefix=ERR7 -strict-whitespace %s -# ERR7: error: {{.*}}.script:4: malformed number: .temp -# ERR7-NEXT: >>> boom .temp : { *(.temp) } } -# ERR7-NEXT: >>> ^ - -## Check tokenize() error -# RUN: echo "SECTIONS {}" > %t.script -# RUN: echo "\"" >> %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \ -# RUN: FileCheck -check-prefix=ERR8 -strict-whitespace %s -# ERR8: {{.*}}.script:2: unclosed quote - -## Check tokenize() error in included script file -# RUN: echo "SECTIONS {}" > %t.script.inc -# RUN: echo "\"" >> %t.script.inc -# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \ -# RUN: FileCheck -check-prefix=ERR9 -strict-whitespace %s -# ERR9: {{.*}}.script.inc:2: unclosed quote - -## Check error reporting correctness for included files. -# RUN: echo "SECTIONS {" > %t.script.inc -# RUN: echo ".text : { *(.text) }" >> %t.script.inc -# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc -# RUN: echo "boom .temp : { *(.temp) } }" >> %t.script.inc -# RUN: echo "INCLUDE \"%t.script.inc\"" > %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \ -# RUN: FileCheck -check-prefix=ERR10 -strict-whitespace %s -# ERR10: error: {{.*}}.script.inc:4: malformed number: .temp -# ERR10-NEXT: >>> boom .temp : { *(.temp) } } -# ERR10-NEXT: >>> ^ - -## Check error reporting in script with INCLUDE directive. -# RUN: echo "SECTIONS {" > %t.script.inc -# RUN: echo ".text : { *(.text) }" >> %t.script.inc -# RUN: echo ".keep : { *(.keep) }" >> %t.script.inc -# RUN: echo ".temp : { *(.temp) } }" >> %t.script.inc -# RUN: echo "/* One line before INCLUDE */" > %t.script -# RUN: echo "INCLUDE \"%t.script.inc\"" >> %t.script -# RUN: echo "/* One line ater INCLUDE */" >> %t.script -# RUN: echo "Error" >> %t.script -# RUN: not ld.lld -shared %t -o %t1 --script %t.script 2>&1 | \ -# RUN: FileCheck -check-prefix=ERR11 -strict-whitespace %s -# ERR11: error: {{.*}}.script:4: unexpected EOF diff --git a/test/ELF/linkerscript/discard-gnu-hash.s b/test/ELF/linkerscript/discard-gnu-hash.s new file mode 100644 index 000000000000..77f168de9caf --- /dev/null +++ b/test/ELF/linkerscript/discard-gnu-hash.s @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t + +# RUN: ld.lld --hash-style both -shared -o %t1 %t +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s +# CHECK: .gnu.hash +# CHECK: .hash + +# RUN: echo "SECTIONS { /DISCARD/ : { *(.hash) } }" > %t.script +# RUN: ld.lld --hash-style both -shared -o %t1 --script %t.script %t +# RUN: llvm-objdump -section-headers %t1 \ +# RUN: | FileCheck %s --check-prefix=HASH +# HASH-NOT: .hash +# HASH: .gnu.hash +# HASH-NOT: .hash + +# RUN: echo "SECTIONS { /DISCARD/ : { *(.gnu.hash) } }" > %t.script +# RUN: ld.lld --hash-style both -shared -o %t1 --script %t.script %t +# RUN: llvm-objdump -section-headers %t1 \ +# RUN: | FileCheck %s --check-prefix=GNUHASH +# GNUHASH-NOT: .gnu.hash +# GNUHASH: .hash +# GNUHASH-NOT: .gnu.hash diff --git a/test/ELF/linkerscript/discard-interp.s b/test/ELF/linkerscript/discard-interp.s deleted file mode 100644 index 261509e2e76b..000000000000 --- a/test/ELF/linkerscript/discard-interp.s +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o -// RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/../Inputs/shared.s -o %t2.o -// RUN: ld.lld -shared %t2.o -o %t2.so -// RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; } \ -// RUN: SECTIONS { . = SIZEOF_HEADERS; .text : { *(.text) } : text }" > %t.script -// RUN: ld.lld -dynamic-linker /lib64/ld-linux-x86-64.so.2 -rpath foo -rpath bar --script %t.script --export-dynamic %t.o %t2.so -o %t -// RUN: llvm-readobj -s %t | FileCheck %s - -// CHECK-NOT: Name: .interp - -.global _start -_start: diff --git a/test/ELF/linkerscript/discard-interp.test b/test/ELF/linkerscript/discard-interp.test new file mode 100644 index 000000000000..02e97b99958c --- /dev/null +++ b/test/ELF/linkerscript/discard-interp.test @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux /dev/null -o %t.o +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/../Inputs/shared.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t2.so +# RUN: ld.lld -dynamic-linker foo -rpath bar -rpath baz --script %s --export-dynamic %t.o %t2.so -o %t +# RUN: llvm-readobj -s %t | FileCheck %s + +# CHECK-NOT: Name: .interp + +PHDRS { text PT_LOAD FILEHDR PHDRS; } +SECTIONS { + . = SIZEOF_HEADERS; + .text : { *(.text) } : text +} diff --git a/test/ELF/linkerscript/discard-print-gc.s b/test/ELF/linkerscript/discard-print-gc.s index 2a230e53dc2b..c9233ce7b0eb 100644 --- a/test/ELF/linkerscript/discard-print-gc.s +++ b/test/ELF/linkerscript/discard-print-gc.s @@ -15,5 +15,5 @@ .section .foo,"a" .quad 0 -# CHECK: removing unused section from '.foo' -# QUIET-NOT: removing unused section from '.foo' +# CHECK: removing unused section {{.*}}:(.foo) +# QUIET-NOT: removing unused section {{.*}}:(.foo) diff --git a/test/ELF/linkerscript/discard-section-err.s b/test/ELF/linkerscript/discard-section-err.s index 8ad5b486cb39..f1d3b96691ba 100644 --- a/test/ELF/linkerscript/discard-section-err.s +++ b/test/ELF/linkerscript/discard-section-err.s @@ -22,4 +22,14 @@ # RUN: FileCheck -check-prefix=DYNSTR %s # DYNSTR: discarding .dynstr section is not allowed +# RUN: echo "SECTIONS { /DISCARD/ : { *(.rela.plt) } }" > %t.script +# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \ +# RUN: FileCheck -check-prefix=RELAPLT %s +# RELAPLT: discarding .rela.plt section is not allowed + +# RUN: echo "SECTIONS { /DISCARD/ : { *(.rela.dyn) } }" > %t.script +# RUN: not ld.lld -pie -o %t --script %t.script %t.o 2>&1 | \ +# RUN: FileCheck -check-prefix=RELADYN %s +# RELADYN: discarding .rela.dyn section is not allowed + .comm foo,4,4 diff --git a/test/ELF/linkerscript/dot-is-not-abs.s b/test/ELF/linkerscript/dot-is-not-abs.s index 4532cd59f2a1..a93d1c8b4344 100644 --- a/test/ELF/linkerscript/dot-is-not-abs.s +++ b/test/ELF/linkerscript/dot-is-not-abs.s @@ -1,9 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .text : { *(.text) } \ -# RUN: foo = .; \ -# RUN: .bar : { *(.bar) } }" > %t1.script +# RUN: echo "SECTIONS { .text : { *(.text) } foo = .; .bar : { *(.bar) } }" > %t1.script # RUN: ld.lld -o %t1 --script %t1.script %t.o -shared # RUN: llvm-readobj -t -s -section-data %t1 | FileCheck %s diff --git a/test/ELF/linkerscript/double-bss.s b/test/ELF/linkerscript/double-bss.s deleted file mode 100644 index c24332f5e5a6..000000000000 --- a/test/ELF/linkerscript/double-bss.s +++ /dev/null @@ -1,21 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; " > %t.script -# RUN: echo ".text : { *(.text*) }" >> %t.script -# RUN: echo ".bss1 : { *(.bss) }" >> %t.script -# RUN: echo ".bss2 : { *(COMMON) }" >> %t.script -# RUN: echo "}" >> %t.script - -# RUN: ld.lld -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | FileCheck %s -# CHECK: .bss1 00000004 0000000000000122 BSS -# CHECK-NEXT: .bss2 00000080 0000000000000128 BSS - -.globl _start -_start: - jmp _start - -.bss -.zero 4 - -.comm q,128,8 diff --git a/test/ELF/linkerscript/double-bss.test b/test/ELF/linkerscript/double-bss.test new file mode 100644 index 000000000000..32b796d01c2e --- /dev/null +++ b/test/ELF/linkerscript/double-bss.test @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: echo '.short 0; .bss; .zero 4; .comm q,128,8' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t +# RUN: ld.lld -o %t1 --script %s %t +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s +# CHECK: .bss1 00000004 0000000000000122 BSS +# CHECK-NEXT: .bss2 00000080 0000000000000128 BSS + +SECTIONS { + . = SIZEOF_HEADERS; + .text : { *(.text*) } + .bss1 : { *(.bss) } + .bss2 : { *(COMMON) } +} diff --git a/test/ELF/linkerscript/edata-etext.s b/test/ELF/linkerscript/edata-etext.s index ab723ce1316e..c15cf4c865c0 100644 --- a/test/ELF/linkerscript/edata-etext.s +++ b/test/ELF/linkerscript/edata-etext.s @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS { }" > %t.script -# RUN: not ld.lld %t.o -script %t.script -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o -script %t.script -o /dev/null 2>&1 | FileCheck %s # CHECK: error: undefined symbol: _edata # CHECK: >>> referenced by {{.*}}:(.text+0x0) # CHECK: error: undefined symbol: _etext diff --git a/test/ELF/linkerscript/eh-frame-emit-relocs.s b/test/ELF/linkerscript/eh-frame-emit-relocs.s new file mode 100644 index 000000000000..d951cbc261b9 --- /dev/null +++ b/test/ELF/linkerscript/eh-frame-emit-relocs.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: echo "SECTIONS { .foo : { *(.eh_frame) } }" > %t.script +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld --emit-relocs %t.o -T %t.script -o %t +# RUN: llvm-objdump -section-headers %t | FileCheck %s + +# CHECK-NOT: eh_frame +# CHECK: .rela.foo +# CHECK-NOT: eh_frame + +.text + .cfi_startproc + .cfi_endproc diff --git a/test/ELF/linkerscript/eh-frame-hdr.s b/test/ELF/linkerscript/eh-frame-hdr.s index d1545be632a3..a7892b2259e0 100644 --- a/test/ELF/linkerscript/eh-frame-hdr.s +++ b/test/ELF/linkerscript/eh-frame-hdr.s @@ -1,13 +1,10 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { \ -# RUN: .eh_frame_hdr : {} \ -# RUN: .eh_frame : {} \ -# RUN: }" > %t.script +# RUN: echo "SECTIONS { .eh_frame_hdr : {} .eh_frame : {} }" > %t.script # RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t # RUN: llvm-objdump -s -section=".eh_frame_hdr" %t1 | FileCheck %s -# CHECK: 011b033b 14000000 01000000 49000000 +# CHECK: 011b033b 14000000 01000000 4d000000 # CHECK-NEXT: 30000000 .global _start diff --git a/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s b/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s deleted file mode 100644 index 817e458fa5ef..000000000000 --- a/test/ELF/linkerscript/eh-frame-reloc-out-of-range.s +++ /dev/null @@ -1,27 +0,0 @@ -## Check that error is correctly reported when .eh_frame reloc -## is out of range - -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "PHDRS { eh PT_LOAD; text PT_LOAD; } \ -# RUN: SECTIONS { . = 0x10000; \ -# RUN: .eh_frame_hdr : { *(.eh_frame_hdr*) } : eh \ -# RUN: .eh_frame : { *(.eh_frame) } : eh \ -# RUN: . = 0xF00000000; \ -# RUN: .text : { *(.text*) } : text \ -# RUN: }" > %t.script -# RUN: not ld.lld %t.o -T %t.script -o %t 2>&1 | FileCheck %s - -# CHECK: error: {{.*}}:(.eh_frame+0x20): relocation R_X86_64_PC32 out of range: 64424443872 is not in [-2147483648, 2147483647] - - .text - .globl _start -_start: - .cfi_startproc - .cfi_lsda 0, _ex - nop - .cfi_endproc - - .data -_ex: - .word 0 diff --git a/test/ELF/linkerscript/eh-frame-reloc-out-of-range.test b/test/ELF/linkerscript/eh-frame-reloc-out-of-range.test new file mode 100644 index 000000000000..7f4df21fd4c4 --- /dev/null +++ b/test/ELF/linkerscript/eh-frame-reloc-out-of-range.test @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/eh-frame-reloc-out-of-range.s -o %t.o +# RUN: not ld.lld %t.o -T %s -o %t 2>&1 | FileCheck %s + +PHDRS { eh PT_LOAD; text PT_LOAD; } +SECTIONS { . = 0x10000; + .eh_frame_hdr : { *(.eh_frame_hdr*) } : eh + .eh_frame : { *(.eh_frame) } : eh + . = 0xF00000000; + .text : { *(.text*) } : text +} + +# CHECK: error: {{.*}}:(.eh_frame+0x20): relocation R_X86_64_PC32 out of range: 64424443872 is not in [-2147483648, 2147483647] diff --git a/test/ELF/linkerscript/eh-frame.s b/test/ELF/linkerscript/eh-frame.s index 750f74eb36c6..5e43ec738f7b 100644 --- a/test/ELF/linkerscript/eh-frame.s +++ b/test/ELF/linkerscript/eh-frame.s @@ -1,8 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { \ -# RUN: .eh_frame : { *(.eh_frame) } \ -# RUN: }" > %t.script +# RUN: echo "SECTIONS { .eh_frame : { *(.eh_frame) } }" > %t.script # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -s -section=".eh_frame" %t1 | FileCheck %s diff --git a/test/ELF/linkerscript/emit-reloc-section-names.s b/test/ELF/linkerscript/emit-reloc-section-names.s index 8661ff060a79..7f76057322e8 100644 --- a/test/ELF/linkerscript/emit-reloc-section-names.s +++ b/test/ELF/linkerscript/emit-reloc-section-names.s @@ -1,7 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { .text.zed : { *(.text.foo) } \ -# RUN: .text.qux : { *(.text.bar) } }" > %t.script +# RUN: echo "SECTIONS { .text.zed : { *(.text.foo) } .text.qux : { *(.text.bar) } }" > %t.script # RUN: ld.lld -T %t.script --emit-relocs %t.o -o %t # RUN: llvm-objdump -section-headers %t | FileCheck %s diff --git a/test/ELF/linkerscript/emit-reloc.s b/test/ELF/linkerscript/emit-reloc.s index 2fe127af8590..43ab4e8e47d8 100644 --- a/test/ELF/linkerscript/emit-reloc.s +++ b/test/ELF/linkerscript/emit-reloc.s @@ -9,9 +9,9 @@ # CHECK: Relocations [ # CHECK-NEXT: Section ({{.*}}) .rela.dyn { -# CHECK-NEXT: 0x66 R_X86_64_64 .foo 0x0 +# CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0 # CHECK-NEXT: } # CHECK-NEXT: Section ({{.*}}) .rela.data { -# CHECK-NEXT: 0x66 R_X86_64_64 .foo 0x0 +# CHECK-NEXT: 0x68 R_X86_64_64 .foo 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] diff --git a/test/ELF/linkerscript/empty-link-order.test b/test/ELF/linkerscript/empty-link-order.test new file mode 100644 index 000000000000..b63b60ca8c15 --- /dev/null +++ b/test/ELF/linkerscript/empty-link-order.test @@ -0,0 +1,21 @@ +# REQUIRES: arm +# RUN: llvm-mc -filetype=obj -triple=arm-arm-none-eabi -o %t.o < /dev/null + +SECTIONS { + .foo : { + bar = .; + *(.ARM.exidx*) + } +} + +# RUN: ld.lld %t.o -o %t --script %s + +## Check we do not crash and do not set SHF_LINK_ORDER flag for .foo +# RUN: llvm-readobj -s %t | FileCheck %s +# CHECK: Section { +# CHECK: Index: +# CHECK: Name: .foo +# CHECK-NEXT: Type: SHT_ARM_EXIDX +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] diff --git a/test/ELF/linkerscript/empty-load.s b/test/ELF/linkerscript/empty-load.s index ea58d71402d1..a2b7d8227f60 100644 --- a/test/ELF/linkerscript/empty-load.s +++ b/test/ELF/linkerscript/empty-load.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { .rw : { *(.rw) } .text : { *(.text) } }" > %t.script +# RUN: echo "SECTIONS { .rw : { *(.rw) } .text : { *(.text) } }" > %t.script # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -private-headers %t1 | FileCheck %s diff --git a/test/ELF/linkerscript/empty-section-size.test b/test/ELF/linkerscript/empty-section-size.test new file mode 100644 index 000000000000..665ddf1ddf01 --- /dev/null +++ b/test/ELF/linkerscript/empty-section-size.test @@ -0,0 +1,17 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: ld.lld %t.o --script %s -o %t1 +# RUN: llvm-readobj -symbols %t1 | FileCheck %s + +## We had a bug when LLD increased the size of the output section even +## if it was empty. That happened because of empty synthetic sections included. +## Here we check that size of empty output section is zero. + +# CHECK: Name: foo +# CHECK-NEXT: Value: 0x0 + +SECTIONS { + . = 0x1000; + .bss : { *(.bss*) *(COMMON) } + foo = SIZEOF(.bss); +} diff --git a/test/ELF/linkerscript/empty-sections-expressions.s b/test/ELF/linkerscript/empty-sections-expressions.s new file mode 100644 index 000000000000..3c9a9edf5786 --- /dev/null +++ b/test/ELF/linkerscript/empty-sections-expressions.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +## We remove empty sections that do not reference symbols in address, +## LMA, align and subalign expressions. Here we check that. + +# RUN: echo "SECTIONS { .debug_info 0 : { *(.debug_info) } }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t | FileCheck %s +# CHECK-NOT: .debug_info + +# RUN: echo "SECTIONS { .debug_info foo : { *(.debug_info) } }" > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %t.o +# RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=SEC +# SEC: .debug_info + +.globl foo +foo: diff --git a/test/ELF/linkerscript/empty-synthetic-removed-flags.s b/test/ELF/linkerscript/empty-synthetic-removed-flags.s new file mode 100644 index 000000000000..54a8baba3bec --- /dev/null +++ b/test/ELF/linkerscript/empty-synthetic-removed-flags.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { .foo : { *(.foo) } .bar : { *(.got.plt) BYTE(0x11) }}" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -s %t | FileCheck %s + +## We have ".got.plt" synthetic section with SHF_ALLOC|SHF_WRITE flags. +## It is empty, so linker removes it, but it has to keep ".got.plt" output +## section because of the BYTE command. Here we check that the output section +## still remembers what the flags of .got.plt are. + +# CHECK: Section { +# CHECK: Index: 2 +# CHECK: Name: .bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] + +## Check flags are not the same if we omit empty synthetic section in script. +# RUN: echo "SECTIONS { .foo : { *(.foo) } .bar : { BYTE(0x11) }}" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -s %t | FileCheck --check-prefix=EMPTY %s + +# EMPTY: Section { +# EMPTY: Index: 2 +# EMPTY: Name: .bar +# EMPTY-NEXT: Type: SHT_PROGBITS +# EMPTY-NEXT: Flags [ +# EMPTY-NEXT: SHF_ALLOC +# EMPTY-NEXT: SHF_EXECINSTR +# EMPTY-NEXT: ] + +.section .foo,"ax" +.quad 0 diff --git a/test/ELF/linkerscript/empty-tls.s b/test/ELF/linkerscript/empty-tls.s deleted file mode 100644 index 919ccbffbe43..000000000000 --- a/test/ELF/linkerscript/empty-tls.s +++ /dev/null @@ -1,14 +0,0 @@ -// REQUIRES: x86 -// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: echo "PHDRS { ph_tls PT_TLS; }" > %t.script -// RUN: ld.lld -o %t.so -T %t.script %t.o -shared -// RUN: llvm-readobj -l %t.so | FileCheck %s - -// test that we don't crash with an empty PT_TLS - -// CHECK: Type: PT_TLS -// CHECK-NEXT: Offset: 0x0 -// CHECK-NEXT: VirtualAddress: 0x0 -// CHECK-NEXT: PhysicalAddress: 0x0 -// CHECK-NEXT: FileSize: 0 -// CHECK-NEXT: MemSize: 0 diff --git a/test/ELF/linkerscript/empty-tls.test b/test/ELF/linkerscript/empty-tls.test new file mode 100644 index 000000000000..2f473cb55f8c --- /dev/null +++ b/test/ELF/linkerscript/empty-tls.test @@ -0,0 +1,17 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o +# RUN: ld.lld -o %t.so -T %s %t.o -shared +# RUN: llvm-readobj -l %t.so | FileCheck %s + +PHDRS { + ph_tls PT_TLS; +} + +# Test that we don't crash with an empty PT_TLS + +# CHECK: Type: PT_TLS +# CHECK-NEXT: Offset: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: FileSize: 0 +# CHECK-NEXT: MemSize: 0 diff --git a/test/ELF/linkerscript/exidx-crash.s b/test/ELF/linkerscript/exidx-crash.s deleted file mode 100644 index c29d0135414d..000000000000 --- a/test/ELF/linkerscript/exidx-crash.s +++ /dev/null @@ -1,7 +0,0 @@ -# REQUIRES: aarch64 - -# We used to crash on this. - -# RUN: llvm-mc %s -o %t.o -filetype=obj -triple=aarch64-pc-linux -# RUN: echo "SECTIONS { .ARM.exidx : { *(.foo) } }" > %t.script -# RUN: ld.lld -T %t.script %t.o -o %t diff --git a/test/ELF/linkerscript/exidx-crash.test b/test/ELF/linkerscript/exidx-crash.test new file mode 100644 index 000000000000..4d765f4d3380 --- /dev/null +++ b/test/ELF/linkerscript/exidx-crash.test @@ -0,0 +1,10 @@ +# REQUIRES: aarch64 + +# We used to crash on this. + +# RUN: llvm-mc /dev/null -o %t.o -filetype=obj -triple=aarch64-pc-linux +# RUN: ld.lld -T %s %t.o -o %t + +SECTIONS { + .ARM.exidx : { *(.foo) } +} diff --git a/test/ELF/linkerscript/expr-invalid-sec.s b/test/ELF/linkerscript/expr-invalid-sec.s deleted file mode 100644 index 5687751b6806..000000000000 --- a/test/ELF/linkerscript/expr-invalid-sec.s +++ /dev/null @@ -1,6 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { foo = ADDR(.text) + ADDR(.text); };" > %t.script -# RUN: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s - -# CHECK: error: {{.*}}.script:1: at least one side of the expression must be absolute diff --git a/test/ELF/linkerscript/expr-invalid-sec.test b/test/ELF/linkerscript/expr-invalid-sec.test new file mode 100644 index 000000000000..946062a0c575 --- /dev/null +++ b/test/ELF/linkerscript/expr-invalid-sec.test @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld -o %t.so --script %s %t.o -shared 2>&1 | FileCheck %s + +# CHECK: error: {{.*}}.test:8: at least one side of the expression must be absolute + +SECTIONS { + foo = ADDR(.text) + ADDR(.text); +}; diff --git a/test/ELF/linkerscript/expr-sections.s b/test/ELF/linkerscript/expr-sections.s deleted file mode 100644 index eb60009cd971..000000000000 --- a/test/ELF/linkerscript/expr-sections.s +++ /dev/null @@ -1,22 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { \ -# RUN: . = . + 4; \ -# RUN: .text : { \ -# RUN: *(.text) \ -# RUN: foo1 = ADDR(.text) + 1; bar1 = 1 + ADDR(.text); \ -# RUN: foo2 = ADDR(.text) & 1; bar2 = 1 & ADDR(.text); \ -# RUN: foo3 = ADDR(.text) | 1; bar3 = 1 | ADDR(.text); \ -# RUN: } \ -# RUN: };" > %t.script -# RUN: ld.lld -o %t.so --script %t.script %t.o -shared -# RUN: llvm-objdump -t -h %t.so | FileCheck %s - -# CHECK: 1 .text 00000000 0000000000000004 TEXT DATA - -# CHECK: 0000000000000005 .text 00000000 foo1 -# CHECK: 0000000000000005 .text 00000000 bar1 -# CHECK: 0000000000000000 .text 00000000 foo2 -# CHECK: 0000000000000000 .text 00000000 bar2 -# CHECK: 0000000000000005 .text 00000000 foo3 -# CHECK: 0000000000000005 .text 00000000 bar3 diff --git a/test/ELF/linkerscript/expr-sections.test b/test/ELF/linkerscript/expr-sections.test new file mode 100644 index 000000000000..1d16cc2239e9 --- /dev/null +++ b/test/ELF/linkerscript/expr-sections.test @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: ld.lld -o %t.so --script %s %t.o -shared +# RUN: llvm-objdump -t -h %t.so | FileCheck %s + +SECTIONS { + . = . + 4; + .text : { + *(.text) + foo1 = ADDR(.text) + 1; bar1 = 1 + ADDR(.text); + foo2 = ADDR(.text) & 1; bar2 = 1 & ADDR(.text); + foo3 = ADDR(.text) | 1; bar3 = 1 | ADDR(.text); + } +}; + +# CHECK: 5 .text 00000000 000000000000014c + +# CHECK: 000000000000014d .text 00000000 foo1 +# CHECK: 000000000000014d .text 00000000 bar1 +# CHECK: 0000000000000000 .text 00000000 foo2 +# CHECK: 0000000000000000 .text 00000000 bar2 +# CHECK: 000000000000014d .text 00000000 foo3 +# CHECK: 000000000000014d .text 00000000 bar3 diff --git a/test/ELF/linkerscript/extend-pt-load.s b/test/ELF/linkerscript/extend-pt-load.s deleted file mode 100644 index 72740f1092ee..000000000000 --- a/test/ELF/linkerscript/extend-pt-load.s +++ /dev/null @@ -1,68 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o - -# This test demonstrates an odd consequence of the way we handle sections with just symbol -# assignments. - -# First, run a test with no such section. - -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: .dynsym : { } \ -# RUN: .hash : { } \ -# RUN: .dynstr : { } \ -# RUN: .text : { *(.text) } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: .data.rel.ro : { *(.data.rel.ro) } \ -# RUN: }" > %t.script -# RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t.o -shared -# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck --check-prefix=CHECK1 %s - -# CHECK1: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX -# CHECK1-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA - -# CHECK1: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E -# CHECK1-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW - -# Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now -# cover the padding bits created by ALIGN. - -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: .dynsym : { } \ -# RUN: .hash : { } \ -# RUN: .dynstr : { } \ -# RUN: .text : { *(.text) } \ -# RUN: bar : { . = ALIGN(0x1000); } \ -# RUN: .data.rel.ro : { *(.data.rel.ro) } \ -# RUN: }" > %t.script -# RUN: ld.lld --hash-style=sysv -o %t2 --script %t.script %t.o -shared -# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck --check-prefix=CHECK2 %s - -# CHECK2: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX -# CHECK2-NEXT: bar NOBITS 00000000000001bd 0001bd 000e43 00 AX -# CHECK2-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA - -# CHECK2: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x001000 R E -# CHECK2-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW - -# If the current behavior becomes a problem we should consider just moving the commands out -# of the section. That is, handle the above like the following test. - -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: .dynsym : { } \ -# RUN: .hash : { } \ -# RUN: .dynstr : { } \ -# RUN: .text : { *(.text) } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: HIDDEN(bar_sym = .); \ -# RUN: .data.rel.ro : { *(.data.rel.ro) } \ -# RUN: }" > %t.script -# RUN: ld.lld --hash-style=sysv -o %t3 --script %t.script %t.o -shared -# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK1 %s - -nop - -.section .data.rel.ro, "aw" -.byte 0 diff --git a/test/ELF/linkerscript/extend-pt-load1.test b/test/ELF/linkerscript/extend-pt-load1.test new file mode 100644 index 000000000000..a1359eace186 --- /dev/null +++ b/test/ELF/linkerscript/extend-pt-load1.test @@ -0,0 +1,23 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o +# RUN: ld.lld --hash-style=sysv -o %t1 --script %s %t.o -shared +# RUN: llvm-readobj --elf-output-style=GNU -l -s %t1 | FileCheck %s + +# This test demonstrates an odd consequence of the way we handle sections with just symbol +# assignments. + +SECTIONS { + . = SIZEOF_HEADERS; + .dynsym : {} + .hash : {} + .dynstr : {} + .text : { *(.text) } + . = ALIGN(0x1000); + .data.rel.ro : { *(.data.rel.ro) } +} + +# CHECK: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX +# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA + +# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW diff --git a/test/ELF/linkerscript/extend-pt-load2.test b/test/ELF/linkerscript/extend-pt-load2.test new file mode 100644 index 000000000000..1aa943703f27 --- /dev/null +++ b/test/ELF/linkerscript/extend-pt-load2.test @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o +# RUN: ld.lld --hash-style=sysv -o %t2 --script %s %t.o -shared +# RUN: llvm-readobj --elf-output-style=GNU -l -s %t2 | FileCheck %s + +# Then add the section bar. Note how bar is given AX flags, which causes the PT_LOAD to now +# cover the padding bits created by ALIGN. + +SECTIONS { + . = SIZEOF_HEADERS; + .dynsym : {} + .hash : {} + .dynstr : {} + .text : { *(.text) } + bar : { . = ALIGN(0x1000); } + .data.rel.ro : { *(.data.rel.ro) } +} + +# CHECK: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX +# CHECK-NEXT: bar NOBITS 00000000000001bd 0001bd 000e43 00 AX +# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA + +# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x001000 R E +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW diff --git a/test/ELF/linkerscript/extend-pt-load3.test b/test/ELF/linkerscript/extend-pt-load3.test new file mode 100644 index 000000000000..1b7ef6fdbf94 --- /dev/null +++ b/test/ELF/linkerscript/extend-pt-load3.test @@ -0,0 +1,24 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/extend-pt-load.s -o %t.o +# RUN: ld.lld --hash-style=sysv -o %t3 --script %s %t.o -shared +# RUN: llvm-readobj --elf-output-style=GNU -l -s %t3 | FileCheck --check-prefix=CHECK %s + +# If the current behavior becomes a problem we should consider just moving the commands out +# of the section. That is, handle the above like the following test. + +SECTIONS { + . = SIZEOF_HEADERS; + .dynsym : {} + .hash : {} + .dynstr : {} + .text : { *(.text) } + . = ALIGN(0x1000); + HIDDEN(bar_sym = .); + .data.rel.ro : { *(.data.rel.ro) } +} + +# CHECK: .text PROGBITS 00000000000001bc 0001bc 000001 00 AX +# CHECK-NEXT: .data.rel.ro PROGBITS 0000000000001000 001000 000001 00 WA + +# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0001bd 0x0001bd R E +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000001000 0x000068 0x000068 RW
\ No newline at end of file diff --git a/test/ELF/linkerscript/filename-spec.s b/test/ELF/linkerscript/filename-spec.s index 5f075a8e5005..66fd4178387c 100644 --- a/test/ELF/linkerscript/filename-spec.s +++ b/test/ELF/linkerscript/filename-spec.s @@ -1,55 +1,43 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tfirst.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tx.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ -# RUN: %p/Inputs/filename-spec.s -o %tsecond.o +# RUN: %p/Inputs/filename-spec.s -o %ty.o -# RUN: echo "SECTIONS { .foo : { \ -# RUN: KEEP(*first.o(.foo)) \ -# RUN: KEEP(*second.o(.foo)) } }" > %t1.script -# RUN: ld.lld -o %t1 --script %t1.script %tfirst.o %tsecond.o -# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTSECOND %s -# FIRSTSECOND: Contents of section .foo: -# FIRSTSECOND-NEXT: 01000000 00000000 11000000 00000000 +# RUN: echo "SECTIONS{.foo :{ KEEP(*x.o(.foo)) KEEP(*y.o(.foo)) }}" > %t1.script +# RUN: ld.lld -o %t1 --script %t1.script %tx.o %ty.o +# RUN: llvm-objdump -s %t1 | FileCheck --check-prefix=FIRSTY %s +# FIRSTY: Contents of section .foo: +# FIRSTY-NEXT: 01000000 00000000 11000000 00000000 -# RUN: echo "SECTIONS { .foo : { \ -# RUN: KEEP(*second.o(.foo)) \ -# RUN: KEEP(*first.o(.foo)) } }" > %t2.script -# RUN: ld.lld -o %t2 --script %t2.script %tfirst.o %tsecond.o +# RUN: echo "SECTIONS{.foo :{ KEEP(*y.o(.foo)) KEEP(*x.o(.foo)) }}" > %t2.script +# RUN: ld.lld -o %t2 --script %t2.script %tx.o %ty.o # RUN: llvm-objdump -s %t2 | FileCheck --check-prefix=SECONDFIRST %s # SECONDFIRST: Contents of section .foo: # SECONDFIRST-NEXT: 11000000 00000000 01000000 00000000 ## Now the same tests but without KEEP. Checking that file name inside ## KEEP is parsed fine. -# RUN: echo "SECTIONS { .foo : { \ -# RUN: *first.o(.foo) \ -# RUN: *second.o(.foo) } }" > %t3.script -# RUN: ld.lld -o %t3 --script %t3.script %tfirst.o %tsecond.o -# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTSECOND %s +# RUN: echo "SECTIONS{.foo :{ *x.o(.foo) *y.o(.foo) }}" > %t3.script +# RUN: ld.lld -o %t3 --script %t3.script %tx.o %ty.o +# RUN: llvm-objdump -s %t3 | FileCheck --check-prefix=FIRSTY %s -# RUN: echo "SECTIONS { .foo : { \ -# RUN: *second.o(.foo) \ -# RUN: *first.o(.foo) } }" > %t4.script -# RUN: ld.lld -o %t4 --script %t4.script %tfirst.o %tsecond.o +# RUN: echo "SECTIONS{.foo :{ *y.o(.foo) *x.o(.foo) }}" > %t4.script +# RUN: ld.lld -o %t4 --script %t4.script %tx.o %ty.o # RUN: llvm-objdump -s %t4 | FileCheck --check-prefix=SECONDFIRST %s -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o filename-spec1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %T/filename-spec1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ -# RUN: %p/Inputs/filename-spec.s -o filename-spec2.o +# RUN: %p/Inputs/filename-spec.s -o %T/filename-spec2.o -# RUN: echo "SECTIONS { .foo : { \ -# RUN: filename-spec2.o(.foo) \ -# RUN: filename-spec1.o(.foo) } }" > %t5.script +# RUN: echo "SECTIONS{.foo :{ %T/filename-spec2.o(.foo) %T/filename-spec1.o(.foo) }}" > %t5.script # RUN: ld.lld -o %t5 --script %t5.script \ -# RUN: filename-spec1.o filename-spec2.o +# RUN: %T/filename-spec1.o %T/filename-spec2.o # RUN: llvm-objdump -s %t5 | FileCheck --check-prefix=SECONDFIRST %s -# RUN: echo "SECTIONS { .foo : { \ -# RUN: filename-spec1.o(.foo) \ -# RUN: filename-spec2.o(.foo) } }" > %t6.script +# RUN: echo "SECTIONS{.foo :{ %T/filename-spec1.o(.foo) %T/filename-spec2.o(.foo) }}" > %t6.script # RUN: ld.lld -o %t6 --script %t6.script \ -# RUN: filename-spec1.o filename-spec2.o -# RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTSECOND %s +# RUN: %T/filename-spec1.o %T/filename-spec2.o +# RUN: llvm-objdump -s %t6 | FileCheck --check-prefix=FIRSTY %s # RUN: mkdir -p %t.testdir1 %t.testdir2 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.testdir1/filename-spec1.o @@ -59,33 +47,25 @@ # RUN: llvm-ar rsc %t.testdir2/lib2.a %t.testdir2/filename-spec2.o # Verify matching of archive library names. -# RUN: echo "SECTIONS { .foo : { \ -# RUN: *lib2*(.foo) \ -# RUN: *lib1*(.foo) } }" > %t7.script +# RUN: echo "SECTIONS{.foo :{ *lib2*(.foo) *lib1*(.foo) }}" > %t7.script # RUN: ld.lld -o %t7 --script %t7.script --whole-archive \ # RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a # RUN: llvm-objdump -s %t7 | FileCheck --check-prefix=SECONDFIRST %s # Verify matching directories. -# RUN: echo "SECTIONS { .foo : { \ -# RUN: *testdir2*(.foo) \ -# RUN: *testdir1*(.foo) } }" > %t8.script +# RUN: echo "SECTIONS{.foo :{ *testdir2*(.foo) *testdir1*(.foo) }}" > %t8.script # RUN: ld.lld -o %t8 --script %t8.script --whole-archive \ # RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a # RUN: llvm-objdump -s %t8 | FileCheck --check-prefix=SECONDFIRST %s # Verify matching of archive library names in KEEP. -# RUN: echo "SECTIONS { .foo : { \ -# RUN: KEEP(*lib2*(.foo)) \ -# RUN: KEEP(*lib1*(.foo)) } }" > %t9.script +# RUN: echo "SECTIONS{.foo :{ KEEP(*lib2*(.foo)) KEEP(*lib1*(.foo)) }}" > %t9.script # RUN: ld.lld -o %t9 --script %t9.script --whole-archive \ # RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a # RUN: llvm-objdump -s %t9 | FileCheck --check-prefix=SECONDFIRST %s # Verify matching directories in KEEP. -# RUN: echo "SECTIONS { .foo : { \ -# RUN: KEEP(*testdir2*(.foo)) \ -# RUN: KEEP(*testdir1*(.foo)) } }" > %t10.script +# RUN: echo "SECTIONS{.foo :{ KEEP(*testdir2*(.foo)) KEEP(*testdir1*(.foo)) }}" > %t10.script # RUN: ld.lld -o %t10 --script %t10.script --whole-archive \ # RUN: %t.testdir1/lib1.a %t.testdir2/lib2.a # RUN: llvm-objdump -s %t10 | FileCheck --check-prefix=SECONDFIRST %s diff --git a/test/ELF/linkerscript/fill.s b/test/ELF/linkerscript/fill.s deleted file mode 100644 index 604506084a74..000000000000 --- a/test/ELF/linkerscript/fill.s +++ /dev/null @@ -1,31 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { \ -# RUN: .out : { \ -# RUN: FILL(0x11111111) \ -# RUN: . += 2; \ -# RUN: *(.aaa) \ -# RUN: . += 4; \ -# RUN: *(.bbb) \ -# RUN: . += 4; \ -# RUN: FILL(0x22222222); \ -# RUN: . += 4; \ -# RUN: } \ -# RUN: }; " > %t.script -# RUN: ld.lld -o %t --script %t.script %t.o -# RUN: llvm-objdump -s %t | FileCheck %s - -# CHECK: Contents of section .out: -# CHECK-NEXT: 2222aa22 222222bb 22222222 22222222 - -.text -.globl _start -_start: - -.section .aaa, "a" -.align 1 -.byte 0xAA - -.section .bbb, "a" -.align 1 -.byte 0xBB diff --git a/test/ELF/linkerscript/fill.test b/test/ELF/linkerscript/fill.test new file mode 100644 index 000000000000..5bf295ec9c14 --- /dev/null +++ b/test/ELF/linkerscript/fill.test @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/fill.s -o %t.o +# RUN: ld.lld -o %t --script %s %t.o +# RUN: llvm-objdump -s %t | FileCheck %s + +SECTIONS { + .out : { + FILL(0x11111111) + . += 2; + *(.aaa) + . += 4; + *(.bbb) + . += 4; + FILL(0x22222222); + . += 4; + } +} + +# CHECK: Contents of section .out: +# CHECK-NEXT: 2222aa22 222222bb 22222222 22222222 diff --git a/test/ELF/linkerscript/header-addr.s b/test/ELF/linkerscript/header-addr.test index 70e6f674bafb..7994c0fc9653 100644 --- a/test/ELF/linkerscript/header-addr.s +++ b/test/ELF/linkerscript/header-addr.test @@ -1,13 +1,15 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "PHDRS {all PT_LOAD PHDRS;} \ -# RUN: SECTIONS { \ -# RUN: . = 0x2000 + SIZEOF_HEADERS; \ -# RUN: .text : {*(.text)} :all \ -# RUN: }" > %t.script -# RUN: ld.lld --hash-style=sysv -o %t.so --script %t.script %t.o -shared +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o +# RUN: ld.lld --hash-style=sysv -o %t.so --script %s %t.o -shared # RUN: llvm-readobj -program-headers %t.so | FileCheck %s +PHDRS { all PT_LOAD PHDRS; } + +SECTIONS { + . = 0x2000 + SIZEOF_HEADERS; + .text : {*(.text)} :all +} + # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD @@ -25,7 +27,7 @@ # CHECK-NEXT: } # CHECK-NEXT: ] -# RUN: ld.lld --hash-style=sysv -o %t2.so --script %t.script %t.o -shared -z max-page-size=0x2000 +# RUN: ld.lld --hash-style=sysv -o %t2.so --script %s %t.o -shared -z max-page-size=0x2000 # RUN: llvm-readobj -program-headers %t2.so \ # RUN: | FileCheck --check-prefix=MAXPAGE %s diff --git a/test/ELF/linkerscript/header-phdr.s b/test/ELF/linkerscript/header-phdr.s deleted file mode 100644 index 8c9097d8dfa5..000000000000 --- a/test/ELF/linkerscript/header-phdr.s +++ /dev/null @@ -1,13 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "PHDRS { foobar PT_LOAD FILEHDR PHDRS; } \ -# RUN: SECTIONS { . = 0x1000; .abc : { *(.zed) } : foobar }" > %t.script -# RUN: ld.lld --script %t.script %t.o -o %t -# RUN: llvm-readelf -l -S -W %t | FileCheck %s - -.section .zed, "a" -.zero 4 - - -# CHECK: [ 1] .abc PROGBITS 0000000000001000 001000 000004 00 A 0 0 1 -# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001004 0x001004 R E 0x1000 diff --git a/test/ELF/linkerscript/header-phdr.test b/test/ELF/linkerscript/header-phdr.test new file mode 100644 index 000000000000..72be15b88a94 --- /dev/null +++ b/test/ELF/linkerscript/header-phdr.test @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: echo '.section .zed, "a"; .zero 4' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld --script %s %t.o -o %t +# RUN: llvm-readelf -l -S -W %t | FileCheck %s + +# CHECK: [ 1] .abc PROGBITS 0000000000001000 001000 000004 00 A 0 0 1 +# CHECK: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x001004 0x001004 R E 0x1000 + +PHDRS { foobar PT_LOAD FILEHDR PHDRS; } + +SECTIONS { + . = 0x1000; + .abc : { *(.zed) } : foobar +} diff --git a/test/ELF/linkerscript/header-phdr2.s b/test/ELF/linkerscript/header-phdr2.s new file mode 100644 index 000000000000..fbcd03ff6056 --- /dev/null +++ b/test/ELF/linkerscript/header-phdr2.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "PHDRS { foobar PT_LOAD FILEHDR PHDRS; }" > %t.script +# RUN: echo "SECTIONS { .text : { *(.text) } : foobar }" >> %t.script +# RUN: not ld.lld --script %t.script %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: could not allocate headers + + .global _start +_start: + retq diff --git a/test/ELF/linkerscript/huge-temporary-file.s b/test/ELF/linkerscript/huge-temporary-file.s index d58709cf8f8d..e30153c28857 100644 --- a/test/ELF/linkerscript/huge-temporary-file.s +++ b/test/ELF/linkerscript/huge-temporary-file.s @@ -3,7 +3,7 @@ # RUN: echo "SECTIONS { .text 0x2000 : {. = 0x10 ; *(.text) } }" > %t.script # RUN: not ld.lld %t --script %t.script -o %t1 -## This inputs previously created a 4gb temporarily fine under 32 bit +## This inputs previously created a 4gb temporarily file under 32 bit ## configuration. Issue was fixed. There is no clean way to check that from here. ## This testcase added for documentation purposes. diff --git a/test/ELF/linkerscript/i386-sections-max-va-overflow.s b/test/ELF/linkerscript/i386-sections-max-va-overflow.s new file mode 100644 index 000000000000..d424112a1ce4 --- /dev/null +++ b/test/ELF/linkerscript/i386-sections-max-va-overflow.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t.o + +# RUN: echo "SECTIONS { . = 0xfffffff1;" > %t.script +# RUN: echo " .bar : { *(.bar*) } }" >> %t.script +# RUN: not ld.lld -o /dev/null --script %t.script %t.o 2>&1 | FileCheck %s -check-prefix=ERR + +## .bar section has data in [0xfffffff1, 0xfffffff1 + 0x10] == [0xffffff1, 0x1]. +## Check we can catch this overflow. +# ERR: error: section .bar at 0xFFFFFFF1 of size 0x10 exceeds available address space + +.section .bar,"ax",@progbits +.zero 0x10 diff --git a/test/ELF/linkerscript/implicit-program-header.s b/test/ELF/linkerscript/implicit-program-header.s deleted file mode 100644 index 95cdf142fe42..000000000000 --- a/test/ELF/linkerscript/implicit-program-header.s +++ /dev/null @@ -1,13 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: ld.lld --hash-style=sysv -o %t1 --script %S/Inputs/implicit-program-header.script \ -# RUN: %t.o -shared -# RUN: llvm-readobj -elf-output-style=GNU -l %t1 | FileCheck %s - -# CHECK: Segment Sections... -# CHECK-NEXT: 00 .text .dynsym .hash .dynstr .dynamic -# CHECK-NEXT: 01 .foo - -.quad 0 -.section .foo,"ax" -.quad 0 diff --git a/test/ELF/linkerscript/implicit-program-header.test b/test/ELF/linkerscript/implicit-program-header.test new file mode 100644 index 000000000000..8a3a4c6684af --- /dev/null +++ b/test/ELF/linkerscript/implicit-program-header.test @@ -0,0 +1,22 @@ +# REQUIRES: x86 + +# RUN: echo '.section .text,"ax"; .quad 0' > %t.s +# RUN: echo '.section .foo,"ax"; .quad 0' >> %t.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %t.s -o %t.o +# RUN: ld.lld --hash-style=sysv -o %t1 --script %s %t.o -shared +# RUN: llvm-readelf -l %t1 | FileCheck %s + +# CHECK: Segment Sections... +# CHECK-NEXT: 00 .dynsym .hash .dynstr .bar .foo .text .dynamic +# CHECK-NEXT: 01 .bar .foo + +PHDRS { + ph_write PT_LOAD FLAGS(2); + ph_exec PT_LOAD FLAGS(1); +} + +SECTIONS { + .bar : { *(.bar) } : ph_exec + .foo : { *(.foo) } + .text : { *(.text) } : ph_write +} diff --git a/test/ELF/linkerscript/info-section-type.s b/test/ELF/linkerscript/info-section-type.s new file mode 100644 index 000000000000..b718e828ab7d --- /dev/null +++ b/test/ELF/linkerscript/info-section-type.s @@ -0,0 +1,33 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +## In this test we check that output section types such as +## COPY, INFO and OVERLAY marks output section as non-allocatable. + +# RUN: echo "SECTIONS { .bar : { *(.foo) } };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=DEFAULT +# DEFAULT: Name: .bar +# DEFAULT: Type: SHT_PROGBITS +# DEFAULT-NEXT: Flags [ +# DEFAULT-NEXT: SHF_ALLOC +# DEFAULT-NEXT: ] + +# RUN: echo "SECTIONS { .bar (COPY) : { *(.foo) } };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC +# NONALLOC: Name: .bar +# NONALLOC: Type: SHT_PROGBITS +# NONALLOC-NEXT: Flags [ +# NONALLOC-NEXT: ] + +# RUN: echo "SECTIONS { .bar (INFO) : { *(.foo) } };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC + +# RUN: echo "SECTIONS { .bar (OVERLAY) : { *(.foo) } };" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: llvm-readobj -sections %t | FileCheck %s --check-prefix=NONALLOC + +.section .foo,"a",@progbits +.zero 1 diff --git a/test/ELF/linkerscript/insert-after.test b/test/ELF/linkerscript/insert-after.test new file mode 100644 index 000000000000..4260cd77f553 --- /dev/null +++ b/test/ELF/linkerscript/insert-after.test @@ -0,0 +1,29 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/insert-after.s -o %t1.o + +## Main linker script contains .text and .data sections. Here +## we check that can use INSERT AFTER to insert sections .foo.data +## and .foo.text at the right places. + +SECTIONS { + .foo.data : { *(.foo.data) } +} INSERT AFTER .data; + +SECTIONS { + .foo.text : { *(.foo.text) } +} INSERT AFTER .text; + +# RUN: ld.lld %t1.o -o %t1 --script %p/Inputs/insert-after.script --script %s +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .text 00000008 0000000000000000 TEXT +# CHECK-NEXT: 2 .foo.text 00000008 0000000000000008 TEXT +# CHECK-NEXT: 3 .data 00000008 0000000000000010 DATA +# CHECK-NEXT: 4 .foo.data 00000008 0000000000000018 DATA + +# RUN: not ld.lld %t1.o -o %t1 --script %s 2>&1 \ +# RUN: | FileCheck %s --check-prefix=ERR +# ERR-DAG: error: unable to INSERT AFTER/BEFORE .text: section not defined +# ERR-DAG: error: unable to INSERT AFTER/BEFORE .data: section not defined diff --git a/test/ELF/linkerscript/insert-before.test b/test/ELF/linkerscript/insert-before.test new file mode 100644 index 000000000000..52317bef6ac0 --- /dev/null +++ b/test/ELF/linkerscript/insert-before.test @@ -0,0 +1,29 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/insert-after.s -o %t1.o + +## Main linker script contains .text and .data sections. Here +## we check that can use INSERT BEFORE to insert sections .foo.data +## and .foo.text at the right places. + +SECTIONS { + .foo.data : { *(.foo.data) } +} INSERT BEFORE .data; + +SECTIONS { + .foo.text : { *(.foo.text) } +} INSERT BEFORE .text; + +# RUN: ld.lld %t1.o -o %t1 --script %p/Inputs/insert-after.script --script %s +# RUN: llvm-objdump -section-headers %t1 | FileCheck %s +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .foo.text 00000008 0000000000000000 TEXT +# CHECK-NEXT: 2 .text 00000008 0000000000000008 TEXT +# CHECK-NEXT: 3 .foo.data 00000008 0000000000000010 DATA +# CHECK-NEXT: 4 .data 00000008 0000000000000018 DATA + +# RUN: not ld.lld %t1.o -o %t1 --script %s 2>&1 \ +# RUN: | FileCheck %s --check-prefix=ERR +# ERR-DAG: error: unable to INSERT AFTER/BEFORE .text: section not defined +# ERR-DAG: error: unable to INSERT AFTER/BEFORE .data: section not defined diff --git a/test/ELF/linkerscript/insert-broken.test b/test/ELF/linkerscript/insert-broken.test new file mode 100644 index 000000000000..9a295623a2ca --- /dev/null +++ b/test/ELF/linkerscript/insert-broken.test @@ -0,0 +1,6 @@ +SECTIONS { + .foo : { *(.bar) } +} INSERT .data; + +# RUN: not ld.lld -o %t1 --script %s 2>&1 | FileCheck %s +# CHECK: {{.*}}:3: expected AFTER/BEFORE, but got '.data' diff --git a/test/ELF/linkerscript/lazy-symbols.s b/test/ELF/linkerscript/lazy-symbols.test index 22dffeef979b..579df9323865 100644 --- a/test/ELF/linkerscript/lazy-symbols.s +++ b/test/ELF/linkerscript/lazy-symbols.test @@ -1,11 +1,12 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %S/Inputs/lazy-symbols.s -o %t1 # RUN: llvm-ar rcs %tar %t1 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2 -# RUN: echo "foo = 1;" > %t.script -# RUN: ld.lld %t2 %tar --script %t.script -o %tout +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t2 +# RUN: ld.lld %t2 %tar --script %s -o %tout # RUN: llvm-readobj -symbols %tout | FileCheck %s +foo = 1; + # This test is to ensure a linker script can define a symbol which have the same # name as a lazy symbol. diff --git a/test/ELF/linkerscript/linker-script-in-search-path.s b/test/ELF/linkerscript/linker-script-in-search-path.s index be83b55b8995..8f1802299de5 100644 --- a/test/ELF/linkerscript/linker-script-in-search-path.s +++ b/test/ELF/linkerscript/linker-script-in-search-path.s @@ -4,16 +4,16 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: mkdir -p %T/searchpath -# RUN: echo "OUTPUT(\"%t.out\")" > %T/searchpath/foo.script -# RUN: ld.lld -T%T/searchpath/foo.script %t.o +# RUN: echo 'OUTPUT("%t.out")' > %T/searchpath/%basename_t.script +# RUN: ld.lld -T%T/searchpath/%basename_t.script %t.o # RUN: llvm-readobj %t.out | FileCheck %s # CHECK: Format: ELF64-x86-64 # If the linker script specified with -T is missing we should emit an error -# RUN: not ld.lld -Tfoo.script %t.o 2>&1 | FileCheck %s -check-prefix ERROR -# ERROR: error: cannot find linker script foo.script +# RUN: not ld.lld -T%basename_t.script %t.o 2>&1 | FileCheck %s -check-prefix ERROR +# ERROR: error: cannot find linker script {{.*}}.script # But if it exists in the search path we should fall back to that instead: # RUN: rm %t.out -# RUN: ld.lld -L %T/searchpath -Tfoo.script %t.o +# RUN: ld.lld -L %T/searchpath -T%basename_t.script %t.o # RUN: llvm-readobj %t.out | FileCheck %s diff --git a/test/ELF/linkerscript/linkerscript.s b/test/ELF/linkerscript/linkerscript.s index 6a239ea57c8d..39d2d4620a4f 100644 --- a/test/ELF/linkerscript/linkerscript.s +++ b/test/ELF/linkerscript/linkerscript.s @@ -17,32 +17,32 @@ # RUN: llvm-readobj %t.out > /dev/null # RUN: echo "SEARCH_DIR(/lib/foo/blah)" > %t.script -# RUN: ld.lld %t.script %t +# RUN: ld.lld %t.script %t -o %t.out # RUN: llvm-readobj %t.out > /dev/null # RUN: echo ";SEARCH_DIR(x);SEARCH_DIR(y);" > %t.script -# RUN: ld.lld %t.script %t +# RUN: ld.lld %t.script %t -o %t.out # RUN: llvm-readobj %t.out > /dev/null # RUN: echo ";" > %t.script -# RUN: ld.lld %t.script %t +# RUN: ld.lld %t.script %t -o %t.out # RUN: llvm-readobj %t.out > /dev/null # RUN: echo "INCLUDE \"%t.script2\" OUTPUT(\"%t.out\")" > %t.script1 # RUN: echo "GROUP(\"%t\")" > %t.script2 -# RUN: ld.lld %t.script1 +# RUN: ld.lld %t.script1 -o %t.out # RUN: llvm-readobj %t2 > /dev/null # RUN: echo "INCLUDE \"foo.script\"" > %t.script # RUN: echo "OUTPUT(\"%t.out\")" > %T/foo.script -# RUN: not ld.lld %t.script > %t.log 2>&1 +# RUN: not ld.lld %t.script -o %t.out > %t.log 2>&1 # RUN: FileCheck -check-prefix=INCLUDE_ERR %s < %t.log # INCLUDE_ERR: error: {{.+}}.script:1: cannot find linker script foo.script # INCLUDE_ERR-NEXT: INCLUDE "foo.script" # RUN: ld.lld -L %T %t.script %t # RUN: echo "FOO(BAR)" > %t.script -# RUN: not ld.lld -o foo %t.script > %t.log 2>&1 +# RUN: not ld.lld -o %t.out %t.script > %t.log 2>&1 # RUN: FileCheck -check-prefix=ERR1 %s < %t.log # ERR1: unknown directive: FOO diff --git a/test/ELF/linkerscript/lma-overflow.test b/test/ELF/linkerscript/lma-overflow.test new file mode 100644 index 000000000000..e572c05af344 --- /dev/null +++ b/test/ELF/linkerscript/lma-overflow.test @@ -0,0 +1,16 @@ +# REQUIRES: x86 + +# RUN: echo '.section .foo,"a"; .quad 1' | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: not ld.lld -o %t %t.o --script %s 2>&1 | FileCheck %s +# CHECK: error: section '.foo' will not fit in region 'flash': overflowed by 264 bytes + +MEMORY { + ram (rwx) : org = 0x1000, len = 0x300 + flash (rwx) : org = 0x1000, len = 0x100 +} +SECTIONS { + .foo : { + *(.foo) + . += 0x200; + } > ram AT>flash +} diff --git a/test/ELF/linkerscript/locationcountererr.s b/test/ELF/linkerscript/locationcountererr.s deleted file mode 100644 index 113e102d4bc2..000000000000 --- a/test/ELF/linkerscript/locationcountererr.s +++ /dev/null @@ -1,11 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -# RUN: echo "SECTIONS {" > %t.script -# RUN: echo ".text 0x2000 : {. = 0x10 ; *(.text) } }" >> %t.script -# RUN: not ld.lld %t --script %t.script -o %t1 2>&1 | FileCheck %s -# CHECK: {{.*}}.script:2: unable to move location counter backward for: .text - -.globl _start -_start: -nop diff --git a/test/ELF/linkerscript/locationcountererr.test b/test/ELF/linkerscript/locationcountererr.test new file mode 100644 index 000000000000..6a1b21319c5b --- /dev/null +++ b/test/ELF/linkerscript/locationcountererr.test @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t +# RUN: not ld.lld %t --script %s -o %t1 2>&1 | FileCheck %s +# CHECK: {{.*}}.test:8: unable to move location counter backward for: .text + +SECTIONS { + .text 0x2000 : { + . = 0x10; + *(.text) + } +} diff --git a/test/ELF/linkerscript/locationcountererr2.s b/test/ELF/linkerscript/locationcountererr2.s index 8968f6740ee4..9efe86a7283b 100644 --- a/test/ELF/linkerscript/locationcountererr2.s +++ b/test/ELF/linkerscript/locationcountererr2.s @@ -1,11 +1,11 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS {" > %t.script -# RUN: echo ". = 0x20; . = 0x10; .text : {} }" >> %t.script +# RUN: echo ". = 0x150; . = 0x10; .text : {} }" >> %t.script # RUN: ld.lld %t.o --script %t.script -o %t -shared # RUN: llvm-objdump -section-headers %t | FileCheck %s -# CHECK: Idx Name Size Address -# CHECK: 1 .text 00000000 0000000000000010 +# CHECK: Name Size Address +# CHECK: .text 00000000 0000000000000010 # RUN: echo "SECTIONS { . = 0x20; . = ASSERT(0x1, "foo"); }" > %t2.script # RUN: ld.lld %t.o --script %t2.script -o %t -shared diff --git a/test/ELF/linkerscript/map-file.test b/test/ELF/linkerscript/map-file.test new file mode 100644 index 000000000000..540b8d494887 --- /dev/null +++ b/test/ELF/linkerscript/map-file.test @@ -0,0 +1,60 @@ +# REQUIRES: x86 + +# RUN: echo '.quad sym3; .quad sym4; .section .foo.1, "a"; .quad 1' > %t.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o + +# RUN: ld.lld -o %t %t.o -Map=%t.map --script %s +# RUN: FileCheck -strict-whitespace %s < %t.map + +SECTIONS { + . = 0x1000; + .foo : { + BYTE(0x11) + SHORT(0x1122) + LONG(0x11223344) + QUAD(0x1122334455667788) + PROVIDE_HIDDEN(sym4 = .); + . += 0x1000; + *(.foo.1) + PROVIDE(unused1 = 0xff); + HIDDEN(sym6 = .); + . += 0x123 * + (1 + 1); + foo = .; + bar = 0x42 - 0x26; + } + sym1 = .; + . += 0x500; + sym2 = .; + PROVIDE(unused2 = 0xff); + PROVIDE(sym3 = 42); +} + +# CHECK: VMA LMA Size Align Out In Symbol +# CHECK-NEXT: 0 0 1000 1 . = 0x1000 +# CHECK-NEXT: 1000 1000 125d 1 .foo +# CHECK-NEXT: 1000 1000 1 1 BYTE ( 0x11 ) +# CHECK-NEXT: 1001 1001 2 1 SHORT ( 0x1122 ) +# CHECK-NEXT: 1003 1003 4 1 LONG ( 0x11223344 ) +# CHECK-NEXT: 1007 1007 8 1 QUAD ( 0x1122334455667788 ) +# CHECK-NEXT: 100f 100f 0 1 PROVIDE_HIDDEN ( sym4 = . ) +# CHECK-NEXT: 100f 100f 1000 1 . += 0x1000 +# CHECK-NEXT: 200f 200f 8 1 {{.*}}{{/|\\}}map-file.test.tmp.o:(.foo.1) +# CHECK-NEXT: 2017 2017 0 1 HIDDEN ( sym6 = . ) +# CHECK-NEXT: 2017 2017 246 1 . += 0x123 * ( 1 + 1 ) +# CHECK-NEXT: 225d 225d 0 1 foo = . +# CHECK-NEXT: 225d 225d 0 1 bar = 0x42 - 0x26 +# CHECK-NEXT: 225d 0 0 1 sym1 = . +# CHECK-NEXT: 225d 0 500 1 . += 0x500 +# CHECK-NEXT: 275d 0 0 1 sym2 = . +# CHECK-NEXT: 275d 0 0 1 PROVIDE ( sym3 = 42 ) +# CHECK-NEXT: 2760 2760 10 4 .text +# CHECK-NEXT: 2760 2760 10 4 {{.*}}{{/|\\}}map-file.test.tmp.o:(.text) +# CHECK-NEXT: 0 0 8 1 .comment +# CHECK-NEXT: 0 0 8 1 <internal>:(.comment) +# CHECK-NEXT: 0 0 c0 8 .symtab +# CHECK-NEXT: 0 0 c0 8 <internal>:(.symtab) +# CHECK-NEXT: 0 0 2f 1 .shstrtab +# CHECK-NEXT: 0 0 2f 1 <internal>:(.shstrtab) +# CHECK-NEXT: 0 0 22 1 .strtab +# CHECK-NEXT: 0 0 22 1 <internal>:(.strtab) diff --git a/test/ELF/linkerscript/map-file2.test b/test/ELF/linkerscript/map-file2.test new file mode 100644 index 000000000000..d9ed339e228d --- /dev/null +++ b/test/ELF/linkerscript/map-file2.test @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/map-file2.s -o %t.o +# RUN: ld.lld -o %t %t.o -Map=%t.map --script %s +# RUN: FileCheck -strict-whitespace %s < %t.map + +SECTIONS { + . = 0x1000; + .aaa : { *(.aaa.*) } + .bbb : AT(0x2000) { *(.bbb.*) } + .ccc : AT(0x3000) { *(.ccc.*) } + .ddd : { + BYTE(0x11) + . += 0x100; + *(.ddd.*) + } + .text : { *(.text.*) } +} + +# CHECK: VMA LMA Size Align Out In Symbol +# CHECK-NEXT: 0 0 1000 1 . = 0x1000 +# CHECK-NEXT: 1000 1000 8 1 .aaa +# CHECK-NEXT: 1000 1000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.aaa) +# CHECK-NEXT: 1008 2000 8 1 .bbb +# CHECK-NEXT: 1008 2000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.bbb) +# CHECK-NEXT: 1010 3000 8 1 .ccc +# CHECK-NEXT: 1010 3000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ccc) +# CHECK-NEXT: 1018 3008 109 1 .ddd +# CHECK-NEXT: 1018 3008 1 1 BYTE ( 0x11 ) +# CHECK-NEXT: 1019 3009 100 1 . += 0x100 +# CHECK-NEXT: 1119 3109 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ddd) +# CHECK-NEXT: 1128 3118 34 8 .eh_frame +# CHECK-NEXT: 1128 3118 30 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.eh_frame+0x0) +# CHECK-NEXT: 115c 314c 1 4 .text +# CHECK-NEXT: 115c 314c 1 4 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.text) +# CHECK-NEXT: 115c 314c 0 1 f(int) +# CHECK-NEXT: 115c 314c 0 1 _start +# CHECK-NEXT: 0 0 8 1 .comment +# CHECK-NEXT: 0 0 8 1 <internal>:(.comment) +# CHECK-NEXT: 0 0 48 8 .symtab +# CHECK-NEXT: 0 0 48 8 <internal>:(.symtab) +# CHECK-NEXT: 0 0 48 1 .shstrtab +# CHECK-NEXT: 0 0 48 1 <internal>:(.shstrtab) +# CHECK-NEXT: 0 0 e 1 .strtab +# CHECK-NEXT: 0 0 e 1 <internal>:(.strtab) diff --git a/test/ELF/linkerscript/memory-at.s b/test/ELF/linkerscript/memory-at.test index 9e56dbdbd657..0f06a6620a79 100644 --- a/test/ELF/linkerscript/memory-at.s +++ b/test/ELF/linkerscript/memory-at.test @@ -1,16 +1,21 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "MEMORY { \ -# RUN: FLASH (rx) : ORIGIN = 0x1000, LENGTH = 0x100 \ -# RUN: RAM (rwx) : ORIGIN = 0x2000, LENGTH = 0x100 } \ -# RUN: SECTIONS { \ -# RUN: .text : { *(.text*) } > FLASH \ -# RUN: __etext = .; \ -# RUN: .data : AT (__etext) { *(.data*) } > RAM \ -# RUN: }" > %t.script -# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: echo '.section .text,"ax"; .quad 0' > %t.s +# RUN: echo '.section .data,"aw"; .quad 0' >> %t.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t +# RUN: ld.lld %t --script %s -o %t2 # RUN: llvm-readobj -program-headers %t2 | FileCheck %s +MEMORY { + FLASH (rx) : ORIGIN = 0x1000, LENGTH = 0x100 + RAM (rwx) : ORIGIN = 0x2000, LENGTH = 0x100 +} + +SECTIONS { + .text : { *(.text*) } > FLASH + __etext = .; + .data : AT (__etext) { *(.data*) } > RAM +} + # CHECK: ProgramHeaders [ # CHECK-NEXT: ProgramHeader { # CHECK-NEXT: Type: PT_LOAD @@ -38,9 +43,3 @@ # CHECK-NEXT: ] # CHECK-NEXT: Alignment: # CHECK-NEXT: } - -.section .text, "ax" -.quad 0 - -.section .data, "aw" -.quad 0 diff --git a/test/ELF/linkerscript/memory-data-commands.test b/test/ELF/linkerscript/memory-data-commands.test new file mode 100644 index 000000000000..2762ec9e985f --- /dev/null +++ b/test/ELF/linkerscript/memory-data-commands.test @@ -0,0 +1,22 @@ +# REQUIRES: x86 + +# RUN: echo ".section .foo,\"a\"" > %t.s +# RUN: echo ".quad 1" >> %t.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o + +# RUN: not ld.lld -o %t %t.o --script %s 2>&1 | FileCheck %s + +# Check we are able to catch 'ram' overflow caused by BYTE command. +# CHECK: error: section '.foo' will not fit in region 'ram': overflowed by 1 bytes + +MEMORY { + text (rwx): org = 0x0, len = 0x1000 + ram (rwx): org = 0x1000, len = 8 +} +SECTIONS { + .text : { *(.text) } > text + .foo : { + *(.foo) + BYTE(0x1) + } > ram +} diff --git a/test/ELF/linkerscript/memory-loc-counter.test b/test/ELF/linkerscript/memory-loc-counter.test new file mode 100644 index 000000000000..3ca9a2cf6caa --- /dev/null +++ b/test/ELF/linkerscript/memory-loc-counter.test @@ -0,0 +1,37 @@ +# REQUIRES: x86 + +# RUN: echo ".section .foo,\"a\"" > %t.s +# RUN: echo ".quad 1" >> %t.s +# RUN: echo ".section .bar,\"a\"" >> %t.s +# RUN: echo ".quad 1" >> %t.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o + +# RUN: ld.lld -o %t %t.o --script %s +# RUN: llvm-readelf -sections -program-headers %t | FileCheck %s + +## Check that we can produce output without errors, +## and .foo section has proper size. +# CHECK: Section Headers: +# CHECK-NEXT: [Nr] Name Type Address Off Size +# CHECK-NEXT: [ 0] NULL 0000000000000000 000000 000000 +# CHECK-NEXT: [ 1] .foo PROGBITS 0000000000001000 001000 000108 +# CHECK-NEXT: [ 2] .bar PROGBITS 0000000000001108 001108 000008 + +## Check that load address is correct. +# CHECK: Program Headers: +# CHECK-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000002000 0x000110 0x000110 + +MEMORY { + ram (rwx) : org = 0x1000, len = 0x200 + flash (rwx) : org = 0x2000, len = 0x200 +} +SECTIONS { + .foo : { + *(.foo) + . += 0x100; + } > ram AT>flash + .bar : { + *(.bar) + } > ram AT>flash +} diff --git a/test/ELF/linkerscript/memory-region-alignment.test b/test/ELF/linkerscript/memory-region-alignment.test new file mode 100644 index 000000000000..ba9d4e3bab3f --- /dev/null +++ b/test/ELF/linkerscript/memory-region-alignment.test @@ -0,0 +1,58 @@ +# REQUIRES: x86 +# RUN: echo '.section .foo,"a"; .quad 0; .section .zed,"M",@progbits,1; .byte 0' > %t.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t.s -o %t.o + +MEMORY { + ram (rwx): org = 0x1, len = 96K +} + +SECTIONS { + .foo : ALIGN(8) { + *(.foo) + } > ram + + .zed : { + *(.zed) + } > ram +} + +# RUN: ld.lld %t.o -o %t --script %s +# RUN: llvm-readobj -sections %t | FileCheck %s + +# CHECK: Name: .foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x8 +# CHECK-NEXT: Offset: 0x1008 +# CHECK-NEXT: Size: 8 + +# CHECK: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10 +# CHECK-NEXT: Offset: 0x1010 +# CHECK-NEXT: Size: 0 + +# CHECK: Name: .zed +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x10 +# CHECK-NEXT: Offset: 0x1010 +# CHECK-NEXT: Size: 1 + +# CHECK: Name: .comment +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: SHF_STRINGS +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x0 +# CHECK-NEXT: Offset: 0x1011 +# CHECK-NEXT: Size: 8 diff --git a/test/ELF/linkerscript/memory.s b/test/ELF/linkerscript/memory.s index 172768394d30..0c171425b20a 100644 --- a/test/ELF/linkerscript/memory.s +++ b/test/ELF/linkerscript/memory.s @@ -11,7 +11,7 @@ # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=RAM %s -# RAM: 1 .text 00000001 0000000000008000 TEXT DATA +# RAM: 1 .text 00000001 0000000000008000 TEXT # RAM-NEXT: 2 .data 00001000 0000000000008001 DATA ## Check RAM and ROM memory regions. @@ -27,7 +27,7 @@ # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=RAMROM %s -# RAMROM: 1 .text 00000001 0000000080000000 TEXT DATA +# RAMROM: 1 .text 00000001 0000000080000000 TEXT # RAMROM-NEXT: 2 .data 00001000 0000000000000000 DATA ## Check memory region placement by attributes. @@ -43,7 +43,7 @@ # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=ATTRS %s -# ATTRS: 1 .text 00000001 0000000080000000 TEXT DATA +# ATTRS: 1 .text 00000001 0000000080000000 TEXT # ATTRS: 2 .data 00001000 0000000000000000 DATA ## Check bad `ORIGIN`. diff --git a/test/ELF/linkerscript/memory2.s b/test/ELF/linkerscript/memory2.s index 2e7381fb8914..7f86ecec29b7 100644 --- a/test/ELF/linkerscript/memory2.s +++ b/test/ELF/linkerscript/memory2.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: echo "MEMORY { ram (rwx) : ORIGIN = 0, LENGTH = 2K } \ # RUN: SECTIONS { .text : { *(.text*) } > ram }" > %t.script -# RUN: ld.lld -o %t2 --script %t.script %t +# RUN: ld.lld -o /dev/null --script %t.script %t .text .global _start diff --git a/test/ELF/linkerscript/memory4.test b/test/ELF/linkerscript/memory4.test new file mode 100644 index 000000000000..e73d36085562 --- /dev/null +++ b/test/ELF/linkerscript/memory4.test @@ -0,0 +1,19 @@ +# REQUIRES: x86 +# RUN: echo ".section .text,\"ax\"; nop; .section .data,\"aw\"; nop;" \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o +# RUN: ld.lld -o %t.so --script %s %t.o +# RUN: llvm-objdump -section-headers %t.so | FileCheck %s + +# CHECK: 1 .text 00000001 0000000000042000 +# CHECK-NEXT: 2 .data 00000001 0000000000042400 + +## Test that address expressions changes the position in a memory region. + +MEMORY { + ram (wxa) : ORIGIN = 0x42000, LENGTH = 0x100000 +} +SECTIONS { + .text : { *(.text*) } + data_addr = ALIGN(1024); + .data data_addr : { *(.data*) } +} diff --git a/test/ELF/linkerscript/memory5.test b/test/ELF/linkerscript/memory5.test new file mode 100644 index 000000000000..150ddf0e833c --- /dev/null +++ b/test/ELF/linkerscript/memory5.test @@ -0,0 +1,19 @@ +# REQUIRES: x86 +# RUN: echo ".section .text,\"ax\"; nop; .section .data,\"aw\"; nop;" \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t.o +# RUN: ld.lld -o %t.so --script %s %t.o +# RUN: llvm-objdump -section-headers %t.so | FileCheck %s + +# CHECK: 1 .text 00000001 0000000000042000 +# CHECK-NEXT: 2 .data 00000001 0000000000044001 + +## Test that assign to Dot changes the position in a memory region. + +MEMORY { + ram (wxa) : ORIGIN = 0x42000, LENGTH = 0x100000 +} +SECTIONS { + .text : { *(.text*) } + . += 0x2000; + .data : { *(.data*) } +} diff --git a/test/ELF/linkerscript/merge-header-load.s b/test/ELF/linkerscript/merge-header-load.s new file mode 100644 index 000000000000..5fb866abef85 --- /dev/null +++ b/test/ELF/linkerscript/merge-header-load.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: . = 0xffffffff80000200; \ +# RUN: .text : AT (0x4200) { *(.text) } \ +# RUN: }" > %t.script +# RUN: ld.lld %t.o --script %t.script -o %t +# RUN: llvm-readelf -program-headers %t | FileCheck %s + +# Test that we put the header in the first PT_LOAD. We used to create a PT_LOAD +# just for it and it would have a different virtual to physical address delta. + +# CHECK: Program Headers: +# CHECK: Type Offset VirtAddr PhysAddr +# CHECK-NEXT: PHDR 0x000040 0xffffffff80000040 0x0000000000004040 +# CHECK-NEXT: LOAD 0x000000 0xffffffff80000000 0x0000000000004000 +# CHECK-NOT: LOAD + +.global _start +_start: +nop diff --git a/test/ELF/linkerscript/merge-sections-syms.s b/test/ELF/linkerscript/merge-sections-syms.s index 713d334a1a5a..421749b6f1b9 100644 --- a/test/ELF/linkerscript/merge-sections-syms.s +++ b/test/ELF/linkerscript/merge-sections-syms.s @@ -20,7 +20,7 @@ # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: A -# CHECK-NEXT: Value: 0x195 +# CHECK-NEXT: Value: 0x226 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: # CHECK-NEXT: Type: @@ -29,7 +29,7 @@ # CHECK-NEXT: } # CHECK-NEXT: Symbol { # CHECK-NEXT: Name: B -# CHECK-NEXT: Value: 0x196 +# CHECK-NEXT: Value: 0x227 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: # CHECK-NEXT: Type: diff --git a/test/ELF/linkerscript/merge-sections.s b/test/ELF/linkerscript/merge-sections.s index 2709bdaee444..8fb9e87d616a 100644 --- a/test/ELF/linkerscript/merge-sections.s +++ b/test/ELF/linkerscript/merge-sections.s @@ -28,8 +28,7 @@ # CHECK-NEXT: Value: 0x[[ADDR1]] # CHECK: Name: end -# 0x19E = begin + sizeof(.foo) = 0x190 + 0xE -# CHECK-NEXT: Value: 0x19E +# CHECK-NEXT: Value: 0x236 # Check that we don't crash with --gc-sections # RUN: ld.lld --gc-sections -o %t2 --script %t.script %t -shared diff --git a/test/ELF/linkerscript/no-pt-load.s b/test/ELF/linkerscript/no-pt-load.s deleted file mode 100644 index c70402501391..000000000000 --- a/test/ELF/linkerscript/no-pt-load.s +++ /dev/null @@ -1,5 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "PHDRS {foo PT_DYNAMIC ;} " \ -# RUN: "SECTIONS { .text : { *(.text) } : foo }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t.o diff --git a/test/ELF/linkerscript/no-pt-load.test b/test/ELF/linkerscript/no-pt-load.test new file mode 100644 index 000000000000..16f7f4409984 --- /dev/null +++ b/test/ELF/linkerscript/no-pt-load.test @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o +# RUN: ld.lld -o %t1 --script %s %t.o + +## Check we do not crash. + +PHDRS { foo PT_DYNAMIC; } + +SECTIONS { + .text : { *(.text) } : foo +} diff --git a/test/ELF/linkerscript/no-space.s b/test/ELF/linkerscript/no-space.s index 21a38e42b2a3..7232495a3fd4 100644 --- a/test/ELF/linkerscript/no-space.s +++ b/test/ELF/linkerscript/no-space.s @@ -1,13 +1,13 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS {foo 0 : {*(foo*)} }" > %t.script +# RUN: echo "SECTIONS {foo 0 : {*(foo*)} .dynsym : {*(.dynsym)} .dynstr : {*(.dynstr)} }" > %t.script # RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared -# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s +# RUN: llvm-readelf -l %t | FileCheck %s -# RUN: echo "SECTIONS {foo : {*(foo*)} }" > %t.script +# RUN: echo "SECTIONS {foo : {*(foo*)} .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } }" > %t.script # RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared -# RUN: llvm-readobj -elf-output-style=GNU -l %t | FileCheck %s +# RUN: llvm-readelf -l %t | FileCheck %s # There is not enough address space available for the header, so just start the PT_LOAD # after it. Don't create a PT_PHDR as the header is not allocated. @@ -18,7 +18,7 @@ # CHECK: Section to Segment mapping: # CHECK-NEXT: Segment Sections... -# CHECK-NEXT: 00 foo .text .dynsym .hash .dynstr +# CHECK-NEXT: 00 foo .dynsym .dynstr .hash .section foo, "a" .quad 0 diff --git a/test/ELF/linkerscript/nobits-offset.s b/test/ELF/linkerscript/nobits-offset.s new file mode 100644 index 000000000000..c4141487630b --- /dev/null +++ b/test/ELF/linkerscript/nobits-offset.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .sec1 (NOLOAD) : { . += 1; } \ +# RUN: .text : { *(.text) } \ +# RUN: };" > %t.script +# RUN: ld.lld %t.o -T %t.script -o %t +# RUN: llvm-readelf --sections %t | FileCheck %s + +# We used to misalign section offsets if the first section in a +# PT_LOAD was SHT_NOBITS. + +# CHECK: [ 2] .text PROGBITS 0000000000000010 001010 000010 00 AX 0 0 16 + +.global _start +_start: + nop +.p2align 4 diff --git a/test/ELF/linkerscript/noload.s b/test/ELF/linkerscript/noload.s index 28be55df1f12..bd49160d80bd 100644 --- a/test/ELF/linkerscript/noload.s +++ b/test/ELF/linkerscript/noload.s @@ -2,12 +2,13 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: echo "SECTIONS { \ # RUN: .data_noload_a (NOLOAD) : { *(.data_noload_a) } \ -# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } };" > %t.script +# RUN: .data_noload_b (0x10000) (NOLOAD) : { *(.data_noload_b) } \ +# RUN: .text (0x20000) : { *(.text) } };" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o -# RUN: llvm-readobj --symbols -sections %t | FileCheck %s +# RUN: llvm-readobj -sections -program-headers %t | FileCheck %s # CHECK: Section { -# CHECK: Index: 2 +# CHECK: Index: 1 # CHECK-NEXT: Name: .data_noload_a # CHECK-NEXT: Type: SHT_NOBITS # CHECK-NEXT: Flags [ @@ -15,7 +16,7 @@ # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x0 -# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Offset: 0xE8 # CHECK-NEXT: Size: 4096 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 @@ -23,7 +24,7 @@ # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } # CHECK-NEXT: Section { -# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Index: 2 # CHECK-NEXT: Name: .data_noload_b # CHECK-NEXT: Type: SHT_NOBITS # CHECK-NEXT: Flags [ @@ -31,13 +32,29 @@ # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] # CHECK-NEXT: Address: 0x10000 -# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: Offset: 0xE8 # CHECK-NEXT: Size: 4096 # CHECK-NEXT: Link: 0 # CHECK-NEXT: Info: 0 # CHECK-NEXT: AddressAlignment: 1 # CHECK-NEXT: EntrySize: 0 # CHECK-NEXT: } +# CHECK: ProgramHeader { +# CHECK-NEXT: Type: PT_LOAD (0x1) +# CHECK-NEXT: Offset: 0x1000 +# CHECK-NEXT: VirtualAddress: 0x20000 +# CHECK-NEXT: PhysicalAddress: 0x20000 +# CHECK-NEXT: FileSize: 1 +# CHECK-NEXT: MemSize: 1 +# CHECK-NEXT: Flags [ (0x5) +# CHECK-NEXT: PF_R (0x4) +# CHECK-NEXT: PF_X (0x1) +# CHECK-NEXT: ] +# CHECK-NEXT: Alignment: 4096 +# CHECK-NEXT: } + +.section .text,"ax",@progbits + nop .section .data_noload_a,"aw",@progbits .zero 4096 diff --git a/test/ELF/linkerscript/non-absolute.s b/test/ELF/linkerscript/non-absolute.s index a0e9e7dc6782..b4b25a7bbf84 100644 --- a/test/ELF/linkerscript/non-absolute.s +++ b/test/ELF/linkerscript/non-absolute.s @@ -5,9 +5,11 @@ # RUN: llvm-objdump -d %t | FileCheck %s --check-prefix=DUMP # RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SYMBOL +# B = A + 0x1 = -0x10 + 0x1 = -0xf -> 0xFFFFFFFFFFFFFFF1 +# B - (0x94+6) = -0xf - (0x94+6) = -169 # DUMP: Disassembly of section .text: # DUMP-NEXT: foo: -# DUMP-NEXT: 0: {{.*}} -21(%rip), %eax +# DUMP-NEXT: 94: {{.*}} -169(%rip), %eax # SYMBOL: Symbol { # SYMBOL: Name: B @@ -18,7 +20,7 @@ # SYMBOL-NEXT: Other [ # SYMBOL-NEXT: STV_HIDDEN # SYMBOL-NEXT: ] -# SYMBOL-NEXT: Section: .text +# SYMBOL-NEXT: Section: .dynsym # SYMBOL-NEXT: } .text diff --git a/test/ELF/linkerscript/non-absolute2.s b/test/ELF/linkerscript/non-absolute2.s deleted file mode 100644 index 97c34d31a912..000000000000 --- a/test/ELF/linkerscript/non-absolute2.s +++ /dev/null @@ -1,12 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o -# RUN: echo "SECTIONS { A = . + 0x1; . += 0x1000; }" > %t.script -# RUN: ld.lld -shared %t1.o --script %t.script -o %t -# RUN: llvm-objdump -section-headers -t %t | FileCheck %s - -# CHECK: Sections: -# CHECK-NEXT: Idx Name Size Address -# CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .text 00000000 0000000000001000 - -# CHECK: 0000000000000001 .text 00000000 A diff --git a/test/ELF/linkerscript/non-absolute2.test b/test/ELF/linkerscript/non-absolute2.test new file mode 100644 index 000000000000..b60666412b8a --- /dev/null +++ b/test/ELF/linkerscript/non-absolute2.test @@ -0,0 +1,17 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t1.o +# RUN: ld.lld -shared %t1.o --script %s -o %t +# RUN: llvm-objdump -section-headers -t %t | FileCheck %s + +SECTIONS { + A = . + 0x1; + . += 0x1000; +} + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .dynsym 00000030 0000000000001000 +# CHECK: 5 .text 00000000 000000000000106c + +# CHECK: 0000000000000001 .dynsym 00000000 A diff --git a/test/ELF/linkerscript/non-alloc-segment.s b/test/ELF/linkerscript/non-alloc-segment.s index 229f028a16b2..d9984b3867d4 100644 --- a/test/ELF/linkerscript/non-alloc-segment.s +++ b/test/ELF/linkerscript/non-alloc-segment.s @@ -16,7 +16,7 @@ # RUN: .foo : {*(.foo)} :foo \ # RUN: }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o -# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s +# RUN: llvm-readelf -s -l %t | FileCheck %s # RUN: llvm-readobj -l %t | FileCheck --check-prefix=PHDR %s # CHECK: Program Headers: diff --git a/test/ELF/linkerscript/non-alloc.s b/test/ELF/linkerscript/non-alloc.s index 3257cb965565..87f9afff8091 100644 --- a/test/ELF/linkerscript/non-alloc.s +++ b/test/ELF/linkerscript/non-alloc.s @@ -1,9 +1,9 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS { .foo 0 : {*(foo)} }" > %t.script -# RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t -shared -# RUN: llvm-readobj -elf-output-style=GNU -s -l %t1 | FileCheck %s +# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared +# RUN: llvm-readelf -s -l %t | FileCheck %s # Test that we create all necessary PT_LOAD. We use to stop at the first # non-alloc, causing us to not create PT_LOAD for linker generated sections. @@ -15,7 +15,7 @@ # CHECK: Section to Segment mapping: # CHECK-NEXT: Segment Sections... -# CHECK-NEXT: 00 .text .dynsym .hash .dynstr +# CHECK-NEXT: 00 .dynsym .hash .dynstr .text # CHECK-NEXT: 01 .dynamic nop diff --git a/test/ELF/linkerscript/numbers.s b/test/ELF/linkerscript/numbers.s index d4fd13fd8197..98d7e3361343 100644 --- a/test/ELF/linkerscript/numbers.s +++ b/test/ELF/linkerscript/numbers.s @@ -29,12 +29,12 @@ ## Mailformed number errors. # RUN: echo "SECTIONS { . = 0x11h; }" > %t2.script -# RUN: not ld.lld %t --script %t2.script -o %t3 2>&1 | \ +# RUN: not ld.lld %t --script %t2.script -o /dev/null 2>&1 | \ # RUN: FileCheck --check-prefix=ERR1 %s # ERR1: malformed number: 0x11h # RUN: echo "SECTIONS { . = 0x11k; }" > %t3.script -# RUN: not ld.lld %t --script %t3.script -o %t4 2>&1 | \ +# RUN: not ld.lld %t --script %t3.script -o /dev/null 2>&1 | \ # RUN: FileCheck --check-prefix=ERR2 %s # ERR2: malformed number: 0x11k @@ -43,13 +43,28 @@ # RUN: FileCheck --check-prefix=ERR3 %s # ERR3: malformed number: 0x11m +# RUN: echo "SECTIONS { . = 1zh; }" > %t5.script +# RUN: not ld.lld %t --script %t5.script -o %t5 2>&1 | \ +# RUN: FileCheck --check-prefix=ERR4 %s +# ERR4: malformed number: 1zh + +# RUN: echo "SECTIONS { . = 1zk; }" > %t6.script +# RUN: not ld.lld %t --script %t6.script -o %t6 2>&1 | \ +# RUN: FileCheck --check-prefix=ERR5 %s +# ERR5: malformed number: 1zk + +# RUN: echo "SECTIONS { . = 1zm; }" > %t7.script +# RUN: not ld.lld %t --script %t7.script -o /dev/null 2>&1 | \ +# RUN: FileCheck --check-prefix=ERR6 %s +# ERR6: malformed number: 1zm + ## Make sure that numbers can be followed by a ":" with and without a space, ## e.g. "0x100 :" or "0x100:" # RUN: echo "SECTIONS { \ # RUN: .hex1 0x400 : { *(.hex.1) } \ # RUN: .hex2 0x500:{ *(.hex.2) } \ -# RUN: }" > %t5.script -# RUN: ld.lld %t --script %t5.script -o %t6 +# RUN: }" > %t8.script +# RUN: ld.lld %t --script %t8.script -o %t6 # RUN: llvm-objdump -section-headers %t6 | FileCheck -check-prefix=SECADDR %s # SECADDR: Sections: # SECADDR-NEXT: Idx Name Size Address diff --git a/test/ELF/linkerscript/openbsd-bootdata.s b/test/ELF/linkerscript/openbsd-bootdata.s deleted file mode 100644 index 3e90574bb3a3..000000000000 --- a/test/ELF/linkerscript/openbsd-bootdata.s +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o -# RUN: echo "PHDRS { boot PT_OPENBSD_BOOTDATA; }" > %t.script -# RUN: ld.lld --script %t.script %t.o -o %t -# RUN: llvm-readobj --program-headers -s %t | FileCheck %s - -# CHECK: ProgramHeader { -# CHECK: Type: PT_OPENBSD_BOOTDATA (0x65A41BE6) diff --git a/test/ELF/linkerscript/openbsd-bootdata.test b/test/ELF/linkerscript/openbsd-bootdata.test new file mode 100644 index 000000000000..6846c7f22f86 --- /dev/null +++ b/test/ELF/linkerscript/openbsd-bootdata.test @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux /dev/null -o %t.o +# RUN: ld.lld --script %s %t.o -o %t +# RUN: llvm-readobj --program-headers -s %t | FileCheck %s + +PHDRS { boot PT_OPENBSD_BOOTDATA; } + +# CHECK: ProgramHeader { +# CHECK: Type: PT_OPENBSD_BOOTDATA (0x65A41BE6) diff --git a/test/ELF/linkerscript/openbsd-randomize.s b/test/ELF/linkerscript/openbsd-randomize.s index bf885f423b02..575a6b25be78 100644 --- a/test/ELF/linkerscript/openbsd-randomize.s +++ b/test/ELF/linkerscript/openbsd-randomize.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o # RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; rand PT_OPENBSD_RANDOMIZE; } \ # RUN: SECTIONS { . = SIZEOF_HEADERS; \ diff --git a/test/ELF/linkerscript/openbsd-wxneeded.s b/test/ELF/linkerscript/openbsd-wxneeded.test index d371da9d8645..1868c0e08802 100644 --- a/test/ELF/linkerscript/openbsd-wxneeded.s +++ b/test/ELF/linkerscript/openbsd-wxneeded.test @@ -1,8 +1,10 @@ -# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o -# RUN: echo "PHDRS { text PT_LOAD FILEHDR PHDRS; wxneeded PT_OPENBSD_WXNEEDED; }" > %t.script -# RUN: ld.lld -z wxneeded --script %t.script %t.o -o %t +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux /dev/null -o %t.o +# RUN: ld.lld -z wxneeded --script %s %t.o -o %t # RUN: llvm-readobj --program-headers %t | FileCheck %s +PHDRS { text PT_LOAD FILEHDR PHDRS; wxneeded PT_OPENBSD_WXNEEDED; } + # CHECK: ProgramHeader { # CHECK: Type: PT_OPENBSD_WXNEEDED (0x65A3DBE7) # CHECK-NEXT: Offset: 0x0 diff --git a/test/ELF/linkerscript/operators.s b/test/ELF/linkerscript/operators.test index 494fc08c0f99..2be24dfc2fe3 100644 --- a/test/ELF/linkerscript/operators.s +++ b/test/ELF/linkerscript/operators.test @@ -1,42 +1,57 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: echo "SECTIONS { \ -# RUN: _start = .; \ -# RUN: plus = 1 + 2 + 3; \ -# RUN: minus = 5 - 1; \ -# RUN: div = 6 / 2; \ -# RUN: mul = 1 + 2 * 3; \ -# RUN: nospace = 1+2*6/3; \ -# RUN: braces = 1 + (2 + 3) * 4; \ -# RUN: and = 0xbb & 0xee; \ -# RUN: ternary1 = 1 ? 1 : 2; \ -# RUN: ternary2 = 0 ? 1 : 2; \ -# RUN: less = 1 < 0 ? 1 : 2; \ -# RUN: lesseq = 1 <= 1 ? 1 : 2; \ -# RUN: greater = 0 > 1 ? 1 : 2; \ -# RUN: greatereq = 1 >= 1 ? 1 : 2; \ -# RUN: eq = 1 == 1 ? 1 : 2; \ -# RUN: neq = 1 != 1 ? 1 : 2; \ -# RUN: plusassign = 1; \ -# RUN: plusassign += 2; \ -# RUN: unary = -1 + 3; \ -# RUN: lshift = 1 << 5; \ -# RUN: rshift = 0xff >> 3; \ -# RUN: maxpagesize = CONSTANT (MAXPAGESIZE); \ -# RUN: commonpagesize = CONSTANT (COMMONPAGESIZE); \ -# RUN: . = 0xfff0; \ -# RUN: datasegmentalign = DATA_SEGMENT_ALIGN (0xffff, 0); \ -# RUN: datasegmentalign2 = DATA_SEGMENT_ALIGN (0, 0); \ -# RUN: _end = .; \ -# RUN: minus_rel = _end - 0x10; \ -# RUN: minus_abs = _end - _start; \ -# RUN: }" > %t.script -# RUN: ld.lld %t --script %t.script -o %t2 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t +# RUN: ld.lld %t --script %s -o %t2 # RUN: llvm-objdump -t %t2 | FileCheck %s +SECTIONS { + _start = .; + plus = 1 + 2 + 3; + minus = 5 - 1; + div = 6 / 2; + mod = 20 % 7; + mul = 1 + 2 * 3; + nospace = 1+2*6/3; + braces = 1 + (2 + 3) * 4; + and = 0xbb & 0xee; + ternary1 = 1 ? 1 : 2; + ternary2 = 0 ? 1 : 2; + less = 1 < 0 ? 1 : 2; + lesseq = 1 <= 1 ? 1 : 2; + greater = 0 > 1 ? 1 : 2; + greatereq = 1 >= 1 ? 1 : 2; + eq = 1 == 1 ? 1 : 2; + neq = 1 != 1 ? 1 : 2; + plusassign = 1; + plusassign += 2; + unary = -1 + 3; + lshift = 1 << 5; + rshift = 0xff >> 3; + precedence1 = 1 | 0xff & 1 << 1 + 1 * 2; + precedence2 = (1 | (0xff & (1 << (1 + (1 * 2))))); + maxpagesize = CONSTANT (MAXPAGESIZE); + commonpagesize = CONSTANT (COMMONPAGESIZE); + . = 0xfff0; + datasegmentalign = DATA_SEGMENT_ALIGN (0xffff, 0); + datasegmentalign2 = DATA_SEGMENT_ALIGN (0, 0); + _end = .; + minus_rel = _end - 0x10; + minus_abs = _end - _start; + max = MAX(11, 22); + min = MIN(11, 22); + logicaland1 = 0 && 0; + logicaland2 = 0 && 1; + logicaland3 = 1 && 0; + logicaland4 = 1 && 1; + logicalor1 = 0 || 0; + logicalor2 = 0 || 1; + logicalor3 = 1 || 0; + logicalor4 = 1 || 1; +} + # CHECK: 00000000000006 *ABS* 00000000 plus # CHECK: 00000000000004 *ABS* 00000000 minus # CHECK: 00000000000003 *ABS* 00000000 div +# CHECK: 00000000000006 *ABS* 00000000 mod # CHECK: 00000000000007 *ABS* 00000000 mul # CHECK: 00000000000005 *ABS* 00000000 nospace # CHECK: 00000000000015 *ABS* 00000000 braces @@ -53,12 +68,24 @@ # CHECK: 00000000000002 *ABS* 00000000 unary # CHECK: 00000000000020 *ABS* 00000000 lshift # CHECK: 0000000000001f *ABS* 00000000 rshift +# CHECK: 00000000000009 *ABS* 00000000 precedence1 +# CHECK: 00000000000009 *ABS* 00000000 precedence2 # CHECK: 00000000001000 *ABS* 00000000 maxpagesize # CHECK: 00000000001000 *ABS* 00000000 commonpagesize # CHECK: 0000000000ffff *ABS* 00000000 datasegmentalign # CHECK: 0000000000fff0 *ABS* 00000000 datasegmentalign2 # CHECK: 0000000000ffe0 .text 00000000 minus_rel # CHECK: 0000000000fff0 *ABS* 00000000 minus_abs +# CHECK: 00000000000016 *ABS* 00000000 max +# CHECK: 0000000000000b *ABS* 00000000 min +# CHECK: 00000000000000 *ABS* 00000000 logicaland1 +# CHECK: 00000000000000 *ABS* 00000000 logicaland2 +# CHECK: 00000000000000 *ABS* 00000000 logicaland3 +# CHECK: 00000000000001 *ABS* 00000000 logicaland4 +# CHECK: 00000000000000 *ABS* 00000000 logicalor1 +# CHECK: 00000000000001 *ABS* 00000000 logicalor2 +# CHECK: 00000000000001 *ABS* 00000000 logicalor3 +# CHECK: 00000000000001 *ABS* 00000000 logicalor4 ## Mailformed number error. # RUN: echo "SECTIONS { . = 0x12Q41; }" > %t.script @@ -88,14 +115,16 @@ # RUN: echo "SECTIONS { . = 1 / 0; }" > %t.script # RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \ # RUN: FileCheck --check-prefix=DIVZERO %s -# DIVZERO: division by zero +# DIVZERO: {{.*}}.script:1: division by zero + +## Mod by zero error. +# RUN: echo "SECTIONS { . = 1 % 0; }" > %t.script +# RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \ +# RUN: FileCheck --check-prefix=MODZERO %s +# MODZERO: {{.*}}.script:1: modulo by zero ## Broken ternary operator expression. # RUN: echo "SECTIONS { . = 1 ? 2; }" > %t.script # RUN: not ld.lld %t --script %t.script -o %t2 2>&1 | \ # RUN: FileCheck --check-prefix=TERNERR %s # TERNERR: : expected, but got ; - -.globl _start -_start: -nop diff --git a/test/ELF/linkerscript/orphan-first-cmd.s b/test/ELF/linkerscript/orphan-first-cmd.s deleted file mode 100644 index 263cb30d6868..000000000000 --- a/test/ELF/linkerscript/orphan-first-cmd.s +++ /dev/null @@ -1,20 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { \ -# RUN: foo = 123; \ -# RUN: . = 0x1000; \ -# RUN: . = 0x2000; \ -# RUN: .bar : { *(.bar) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t -T %t.script %t.o -shared -# RUN: llvm-readobj -s %t | FileCheck %s - -# CHECK: Name: .text -# CHECK-NEXT: Type: SHT_PROGBITS -# CHECK-NEXT: Flags [ -# CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: SHF_EXECINSTR -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x1000 - -.section .bar, "aw" diff --git a/test/ELF/linkerscript/orphan-first-cmd.test b/test/ELF/linkerscript/orphan-first-cmd.test new file mode 100644 index 000000000000..84b183f96efb --- /dev/null +++ b/test/ELF/linkerscript/orphan-first-cmd.test @@ -0,0 +1,20 @@ +# REQUIRES: x86 +# RUN: echo '.section .bar, "aw"' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld -o %t -T %s %t.o -shared +# RUN: llvm-readobj -s %t | FileCheck %s + +SECTIONS { + foo = 123; + . = 0x1000; + . = 0x2000; + .bar : { *(.bar) } +} + +# CHECK: Name: .text +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_EXECINSTR +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x1070 diff --git a/test/ELF/linkerscript/orphan-phdrs.s b/test/ELF/linkerscript/orphan-phdrs.s index 648911162e97..f9d1467b532a 100644 --- a/test/ELF/linkerscript/orphan-phdrs.s +++ b/test/ELF/linkerscript/orphan-phdrs.s @@ -10,7 +10,7 @@ # RUN: .rw : { *(.rw) } \ # RUN: }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o -# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s +# RUN: llvm-readelf -s -l %t | FileCheck %s ## Check that the orphan section is placed correctly and belongs to ## the correct segment. @@ -18,6 +18,7 @@ # CHECK: Section Headers # CHECK: .text # CHECK-NEXT: .orphan +# CHECK-NEXT: .empty # CHECK-NEXT: .rw # CHECK: Segment Sections diff --git a/test/ELF/linkerscript/orphan.s b/test/ELF/linkerscript/orphan.s index f51085383a9e..4dbaf37c687e 100644 --- a/test/ELF/linkerscript/orphan.s +++ b/test/ELF/linkerscript/orphan.s @@ -13,7 +13,7 @@ ## .bss is SHT_NOBITS section and should be last RW section, so some space ## in ELF file could be saved. # CHECK: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .text 00000000 0000000000000000 TEXT DATA +# CHECK-NEXT: 1 .text 00000000 0000000000000000 TEXT # CHECK-NEXT: 2 .rw1 00000008 0000000000000000 DATA # CHECK-NEXT: 3 .rw2 00000008 0000000000000008 DATA # CHECK-NEXT: 4 .rw3 00000008 0000000000000010 DATA diff --git a/test/ELF/linkerscript/out-of-order.s b/test/ELF/linkerscript/out-of-order.s index c43df43e5002..da8c103bb47f 100644 --- a/test/ELF/linkerscript/out-of-order.s +++ b/test/ELF/linkerscript/out-of-order.s @@ -1,19 +1,37 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-linux %s -o %t.o -# RUN: echo "SECTIONS { .data 0x4000 : { *(.data) } .text 0x2000 : { *(.text) } }" > %t.script +# RUN: echo "SECTIONS { .data 0x4000 : {*(.data)} .dynsym 0x2000 : {*(.dynsym)} .dynstr : {*(.dynstr)} }" > %t.script # RUN: ld.lld --hash-style=sysv -o %t.so --script %t.script %t.o -shared # RUN: llvm-objdump -section-headers %t.so | FileCheck %s +# Note: how the layout is done: +# we need to layout 2 segments, each contains sections: +# seg1: .data .dynamic +# seg2: .dynsym .dynstr .text .hash +# for each segment, we start from the first section, regardless +# whether it is an orphan or not (sections that are not listed in the +# linkerscript are orphans): +# for seg1, we assign address: .data(0x4000), .dynamic(0x4008) +# for seg2, we assign address: .dynsym(0x2000), .dynstr(0x2018) ... +# .dynsym is not an orphan, so we take address from script, we assign +# .dynstr current address cursor, which is the end # of .dynsym and so +# on for later sections. + +# Also note, it is absolutely *illegal* to have section addresses of +# the same segment in none-increasing order, authors of linker scripts +# must take responsibility to make sure this does not happen. + # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .data 00000008 0000000000004000 DATA +# CHECK-NEXT: 1 .data 00000008 0000000000004000 # CHECK-NEXT: 2 .dynamic 00000060 0000000000004008 -# CHECK-NEXT: 3 .text 00000008 0000000000002000 TEXT DATA -# CHECK-NEXT: 4 .dynsym 00000018 0000000000002008 -# CHECK-NEXT: 5 .hash 00000010 0000000000002020 -# CHECK-NEXT: 6 .dynstr 00000001 0000000000002030 +# CHECK-NEXT: 3 .dynsym 00000018 0000000000002000 +# CHECK-NEXT: 4 .dynstr 00000001 0000000000002018 +# CHECK-NEXT: 5 .hash 00000010 000000000000201c +# CHECK-NEXT: 6 .text 00000008 000000000000202c .quad 0 .data .quad 0 + diff --git a/test/ELF/linkerscript/output-too-large.s b/test/ELF/linkerscript/output-too-large.s index c892a88a947e..ca85465036fe 100644 --- a/test/ELF/linkerscript/output-too-large.s +++ b/test/ELF/linkerscript/output-too-large.s @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o # RUN: echo "SECTIONS { .text : { . = 0xffffffff; *(.text*); } }" > %t.script -# RUN: not ld.lld --script %t.script %t.o -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld --no-check-sections --script %t.script %t.o -o /dev/null 2>&1 | FileCheck %s # CHECK: error: output file too large .global _start diff --git a/test/ELF/linkerscript/outputarch.s b/test/ELF/linkerscript/outputarch.s deleted file mode 100644 index dd3bf93611b4..000000000000 --- a/test/ELF/linkerscript/outputarch.s +++ /dev/null @@ -1,4 +0,0 @@ -# REQUIRES: x86 -# RUN: echo "OUTPUT_ARCH(All data written here is ignored)" > %t.script -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd %s -o %t1 -# RUN: ld.lld -shared -o %t2 %t1 %t.script diff --git a/test/ELF/linkerscript/outputarch.test b/test/ELF/linkerscript/outputarch.test new file mode 100644 index 000000000000..4819a983cfce --- /dev/null +++ b/test/ELF/linkerscript/outputarch.test @@ -0,0 +1,5 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-freebsd /dev/null -o %t1 +# RUN: ld.lld -shared -o %t2 %t1 %s + +OUTPUT_ARCH(All data written here is ignored) diff --git a/test/ELF/linkerscript/overlapping-sections.s b/test/ELF/linkerscript/overlapping-sections.s new file mode 100644 index 000000000000..818301fd2b0e --- /dev/null +++ b/test/ELF/linkerscript/overlapping-sections.s @@ -0,0 +1,113 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "SECTIONS { \ +# RUN: .sec1 0x8000 : AT(0x8000) { sec1_start = .; *(.first_sec) sec1_end = .;} \ +# RUN: .sec2 0x8800 : AT(0x8080) { sec2_start = .; *(.second_sec) sec2_end = .;} \ +# RUN: }" > %t-lma.script +# RUN: not ld.lld -o %t.so --script %t-lma.script %t.o -shared 2>&1 | FileCheck %s -check-prefix LMA-OVERLAP-ERR +# LMA-OVERLAP-ERR: error: section .sec1 load address range overlaps with .sec2 +# LMA-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF] +# LMA-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8080, 0x817F] + +# Check that we create the expected binary with --noinhibit-exec or --no-check-sections: +# RUN: ld.lld -o %t.so --script %t-lma.script %t.o -shared --noinhibit-exec +# RUN: ld.lld -o %t.so --script %t-lma.script %t.o -shared --no-check-sections -fatal-warnings +# RUN: ld.lld -o %t.so --script %t-lma.script %t.o -shared --check-sections --no-check-sections -fatal-warnings + +# Verify that the .sec2 was indeed placed in a PT_LOAD where the PhysAddr +# overlaps with where .sec1 is loaded: +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-LMA +# BAD-LMA-LABEL: Section Headers: +# BAD-LMA: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1 +# BAD-LMA: .sec2 PROGBITS 0000000000008800 002800 000100 00 WA 0 0 1 +# BAD-LMA-LABEL: Program Headers: +# BAD-LMA-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# BAD-LMA-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000 +# BAD-LMA-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000 +# BAD-LMA-NEXT: LOAD 0x002800 0x0000000000008800 0x0000000000008080 0x000170 0x000170 RW 0x1000 +# BAD-LMA-LABEL: Section to Segment mapping: +# BAD-LMA: 01 .sec1 +# BAD-LMA: 02 .sec2 .dynamic + +# Now try a script where the virtual memory addresses overlap but ensure that the +# load addresses don't: +# RUN: echo "SECTIONS { \ +# RUN: .sec1 0x8000 : AT(0x8000) { sec1_start = .; *(.first_sec) sec1_end = .;} \ +# RUN: .sec2 0x8020 : AT(0x8800) { sec2_start = .; *(.second_sec) sec2_end = .;} \ +# RUN: }" > %t-vaddr.script +# RUN: not ld.lld -o %t.so --script %t-vaddr.script %t.o -shared 2>&1 | FileCheck %s -check-prefix VADDR-OVERLAP-ERR +# VADDR-OVERLAP-ERR: error: section .sec1 virtual address range overlaps with .sec2 +# VADDR-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF] +# VADDR-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8020, 0x811F] + +# Check that the expected binary was created with --noinhibit-exec: +# RUN: ld.lld -o %t.so --script %t-vaddr.script %t.o -shared --noinhibit-exec +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-VADDR +# BAD-VADDR-LABEL: Section Headers: +# BAD-VADDR: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1 +# BAD-VADDR: .sec2 PROGBITS 0000000000008020 003020 000100 00 WA 0 0 1 +# BAD-VADDR-LABEL: Program Headers: +# BAD-VADDR-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# BAD-VADDR-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000 +# BAD-VADDR-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x000100 0x000100 RW 0x1000 +# BAD-VADDR-NEXT: LOAD 0x003020 0x0000000000008020 0x0000000000008800 0x000170 0x000170 RW 0x1000 +# BAD-VADDR-LABEL: Section to Segment mapping: +# BAD-VADDR: 01 .sec1 +# BAD-VADDR: 02 .sec2 .dynamic + +# Finally check the case where both LMA and vaddr overlap + +# RUN: echo "SECTIONS { \ +# RUN: .sec1 0x8000 : { sec1_start = .; *(.first_sec) sec1_end = .;} \ +# RUN: .sec2 0x8040 : { sec2_start = .; *(.second_sec) sec2_end = .;} \ +# RUN: }" > %t-both-overlap.script + +# RUN: not ld.lld -o %t.so --script %t-both-overlap.script %t.o -shared 2>&1 | FileCheck %s -check-prefix BOTH-OVERLAP-ERR + +# BOTH-OVERLAP-ERR: error: section .sec1 file range overlaps with .sec2 +# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x2000, 0x20FF] +# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x2040, 0x213F] +# BOTH-OVERLAP-ERR: error: section .sec1 virtual address range overlaps with .sec2 +# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF] +# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8040, 0x813F] +# BOTH-OVERLAP-ERR: error: section .sec1 load address range overlaps with .sec2 +# BOTH-OVERLAP-ERR-NEXT: >>> .sec1 range is [0x8000, 0x80FF] +# BOTH-OVERLAP-ERR-NEXT: >>> .sec2 range is [0x8040, 0x813F] + +# RUN: ld.lld -o %t.so --script %t-both-overlap.script %t.o -shared --noinhibit-exec +# Note: In case everything overlaps we create a binary with overlapping file +# offsets. ld.bfd seems to place .sec1 to file offset 18000 and .sec2 +# at 18100 so that only virtual addr and LMA overlap +# However, in order to create such a broken binary the user has to ignore a +# fatal error by passing --noinhibit-exec, so this behaviour is fine. + +# RUN: llvm-objdump -s %t.so | FileCheck %s -check-prefix BROKEN-OUTPUT-FILE +# BROKEN-OUTPUT-FILE-LABEL: Contents of section .sec1: +# BROKEN-OUTPUT-FILE-NEXT: 8000 01010101 01010101 01010101 01010101 +# BROKEN-OUTPUT-FILE-NEXT: 8010 01010101 01010101 01010101 01010101 +# BROKEN-OUTPUT-FILE-NEXT: 8020 01010101 01010101 01010101 01010101 +# BROKEN-OUTPUT-FILE-NEXT: 8030 01010101 01010101 01010101 01010101 +# Starting here the contents of .sec2 overwrites .sec1: +# BROKEN-OUTPUT-FILE-NEXT: 8040 02020202 02020202 02020202 02020202 + +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t.so | FileCheck %s -check-prefix BAD-BOTH +# BAD-BOTH-LABEL: Section Headers: +# BAD-BOTH: .sec1 PROGBITS 0000000000008000 002000 000100 00 WA 0 0 1 +# BAD-BOTH: .sec2 PROGBITS 0000000000008040 002040 000100 00 WA 0 0 1 +# BAD-BOTH-LABEL: Program Headers: +# BAD-BOTH-NEXT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# BAD-BOTH-NEXT: LOAD 0x001000 0x0000000000000000 0x0000000000000000 0x000100 0x000100 R E 0x1000 +# BAD-BOTH-NEXT: LOAD 0x002000 0x0000000000008000 0x0000000000008000 0x0001b0 0x0001b0 RW 0x1000 +# BAD-BOTH-LABEL: Section to Segment mapping: +# BAD-BOTH: 01 .sec1 .sec2 .dynamic + +.section .first_sec,"aw",@progbits +.rept 0x100 +.byte 1 +.endr + +.section .second_sec,"aw",@progbits +.rept 0x100 +.byte 2 +.endr diff --git a/test/ELF/linkerscript/overlay-reject.test b/test/ELF/linkerscript/overlay-reject.test new file mode 100644 index 000000000000..fcb82b6df4b5 --- /dev/null +++ b/test/ELF/linkerscript/overlay-reject.test @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld %t.o --script %s -o %t 2>&1 | FileCheck %s + +# CHECK: {{.*}}.test:{{.*}}: { expected, but got 0x3000 +# CHECK-NEXT: >>> .out.aaa 0x3000 : { *(.aaa) } +# CHECK-NEXT: >>> ^ + +SECTIONS { + OVERLAY 0x1000 : AT ( 0x2000 ) { + .out.aaa 0x3000 : { *(.aaa) } + } +} diff --git a/test/ELF/linkerscript/overlay-reject2.test b/test/ELF/linkerscript/overlay-reject2.test new file mode 100644 index 000000000000..490533c5fa5e --- /dev/null +++ b/test/ELF/linkerscript/overlay-reject2.test @@ -0,0 +1,17 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t.o +# RUN: not ld.lld %t.o --script %s -o %t 2>&1 | FileCheck %s + +# CHECK: {{.*}}.test:{{.*}}: { expected, but got AX +# CHECK-NEXT: >>> .out.aaa { *(.aaa) } > AX AT>FLASH +# CHECK-NEXT: >>> ^ + +MEMORY { + AX (ax) : ORIGIN = 0x3000, LENGTH = 0x4000 +} + +SECTIONS { + OVERLAY 0x1000 : AT ( 0x2000 ) { + .out.aaa { *(.aaa) } > AX AT>FLASH + } +} diff --git a/test/ELF/linkerscript/overlay.test b/test/ELF/linkerscript/overlay.test new file mode 100644 index 000000000000..a28ab610ec09 --- /dev/null +++ b/test/ELF/linkerscript/overlay.test @@ -0,0 +1,30 @@ +# REQUIRES: x86 +# RUN: echo 'nop; .section .small, "a"; .long 0; .section .big, "a"; .quad 1;' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld %t.o --script %s -o %t + +SECTIONS { + OVERLAY 0x1000 : AT ( 0x4000 ) { + .out.big { *(.big) } + .out.small { *(.small) } + } +} + +## Here we check that can handle OVERLAY which will produce sections +## .out.big and .out.small with the same starting VAs, but different LMAs. +## Section .big is larger than .small, we check that placing of section +## .text does not cause overlapping error and that +## .text's VA is 0x1000 + max(sizeof(.out.big), sizeof(.out.small)). + +# RUN: llvm-readobj -sections -program-headers -elf-output-style=GNU %t | FileCheck %s + +# CHECK: Section Headers: +# CHECK: Name Type Address Off Size +# CHECK: .out.big PROGBITS 0000000000001000 001000 000008 +# CHECK: .out.small PROGBITS 0000000000001000 002000 000004 +# CHECK: .text PROGBITS 0000000000001008 002008 000001 + +# CHECK: Program Headers: +# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align +# CHECK-NEXT: LOAD 0x001000 0x0000000000001000 0x0000000000004000 0x000008 0x000008 R E 0x1000 +# CHECK-NEXT: LOAD 0x002000 0x0000000000001000 0x0000000000004008 0x000009 0x000009 R E 0x1000 diff --git a/test/ELF/linkerscript/page-size-align.s b/test/ELF/linkerscript/page-size-align.s deleted file mode 100644 index 771bb13a8e6d..000000000000 --- a/test/ELF/linkerscript/page-size-align.s +++ /dev/null @@ -1,22 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o - -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: .text : { *(.text) } \ -# RUN: . = ALIGN(CONSTANT(MAXPAGESIZE)); \ -# RUN: . = . + 0x3000; \ -# RUN: .dynamic : { *(.dynamic) } \ -# RUN: }" > %t.script - -# RUN: ld.lld -T %t.script -z max-page-size=0x4000 %t.o -o %t.so -shared -# RUN: llvm-readobj -s %t.so | FileCheck %s - -# CHECK: Name: .dynamic -# CHECK-NEXT: Type: SHT_DYNAMIC -# CHECK-NEXT: Flags [ -# CHECK-NEXT: SHF_ALLOC -# CHECK-NEXT: SHF_WRITE -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x7000 -# CHECK-NEXT: Offset: 0x3000 diff --git a/test/ELF/linkerscript/page-size-align.test b/test/ELF/linkerscript/page-size-align.test new file mode 100644 index 000000000000..f69413157426 --- /dev/null +++ b/test/ELF/linkerscript/page-size-align.test @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o +# RUN: ld.lld -T %s -z max-page-size=0x4000 %t.o -o %t.so -shared +# RUN: llvm-readobj -s %t.so | FileCheck %s + +SECTIONS { + . = SIZEOF_HEADERS; + .text : { *(.text) } + . = ALIGN(CONSTANT(MAXPAGESIZE)); + . = . + 0x3000; + .dynamic : { *(.dynamic) } +} + +# CHECK: Name: .dynamic +# CHECK-NEXT: Type: SHT_DYNAMIC +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_WRITE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x7000 +# CHECK-NEXT: Offset: 0x3000 diff --git a/test/ELF/linkerscript/parse-section-in-addr.test b/test/ELF/linkerscript/parse-section-in-addr.test new file mode 100644 index 000000000000..6f42a6fe2788 --- /dev/null +++ b/test/ELF/linkerscript/parse-section-in-addr.test @@ -0,0 +1,10 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o +# RUN: ld.lld -o %t.so --script %s %t.o -shared +# RUN: llvm-readelf -S %t.so | FileCheck %s + +SECTIONS { + .foo-bar : AT(ADDR(.foo-bar)) { *(.text) } +} + +# CHECK: .foo-bar diff --git a/test/ELF/linkerscript/provide-empty-section.s b/test/ELF/linkerscript/provide-empty-section.s new file mode 100644 index 000000000000..56cb6aca1e3b --- /dev/null +++ b/test/ELF/linkerscript/provide-empty-section.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %tundefined.o +# RUN: echo "foo=42" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %tdefined.o +# RUN: echo "call foo" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %treference.o + +# RUN: echo "SECTIONS { .bar : { PROVIDE(foo = .); } }" > %t.script + +# Case 1: Provided symbol is undefined and not referenced - empty section should be removed. +# RUN: ld.lld %tundefined.o -T %t.script -o %t1.elf +# RUN: llvm-readobj -sections %t1.elf | FileCheck %s --check-prefix=NOSECTION + +# Case 2: Provided symbol is undefined and referenced - empty section should not be removed. +# RUN: ld.lld %tundefined.o %treference.o -T %t.script -o %t2.elf +# RUN: llvm-readobj -sections %t2.elf | FileCheck %s --check-prefix=SECTION + +# Case 3: Provided symbol is defined and not referenced - empty section should be removed. +# RUN: ld.lld %tdefined.o -T %t.script -o %t3.elf +# RUN: llvm-readobj -sections %t3.elf | FileCheck %s --check-prefix=NOSECTION + +# Case 4: Provided symbol is defined and referenced - empty section should not be removed. +# RUN: ld.lld %tdefined.o %treference.o -T %t.script -o %t4.elf +# RUN: llvm-readobj -sections %t4.elf | FileCheck %s --check-prefix=SECTION + +.global _start +_start: + ret + +# SECTION: .bar +# NOSECTION-NOT: .bar diff --git a/test/ELF/linkerscript/provide-shared2.s b/test/ELF/linkerscript/provide-shared2.s new file mode 100644 index 000000000000..8a3200b6f545 --- /dev/null +++ b/test/ELF/linkerscript/provide-shared2.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/provide-shared2.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: echo "SECTIONS { . = . + SIZEOF_HEADERS; PROVIDE(foo = 42); }" > %t.script +# RUN: ld.lld -o %t --script %t.script %t.o %t2.so +# RUN: llvm-readelf --dyn-symbols %t | FileCheck %s + +# CHECK: 1 1: 000000000000002a 0 NOTYPE GLOBAL DEFAULT ABS foo@ + +.global _start +_start: + nop diff --git a/test/ELF/linkerscript/pt-interp.test b/test/ELF/linkerscript/pt-interp.test new file mode 100644 index 000000000000..0441817aea6d --- /dev/null +++ b/test/ELF/linkerscript/pt-interp.test @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux /dev/null -o %t.o +# RUN: ld.lld -o %t.so -shared %t.o + +## Check we create PT_INTERP program header when it is specified in PHDRS. +# RUN: echo "PHDRS { interp PT_INTERP; }" > %t1.script +# RUN: ld.lld -o %t1 --script %t1.script %t.o %t.so --dynamic-linker foo +# RUN: llvm-readobj -program-headers %t1 | FileCheck %s +# CHECK: PT_INTERP + +## Check we do not create it if it is not specified, +## but only if PHDRS is not empty by itself. +# RUN: echo "PHDRS { ph_text PT_LOAD; }" > %t2.script +# RUN: ld.lld -o %t1 --script %t2.script %t.o %t.so --dynamic-linker foo +# RUN: llvm-readobj -program-headers %t1 | FileCheck %s --check-prefix=NOINTERP +# NOINTERP-NOT: PT_INTERP + +## Otherwise, if PHDRS is empty, we create PT_INTERP header. +# RUN: echo "PHDRS {}" > %t3.script +# RUN: ld.lld -o %t1 --script %t3.script %t.o %t.so --dynamic-linker foo +# RUN: llvm-readobj -program-headers %t1 | FileCheck %s diff --git a/test/ELF/linkerscript/pt_gnu_eh_frame.s b/test/ELF/linkerscript/pt_gnu_eh_frame.s index 81b4c6307d4c..7f9ebaa8d8d1 100644 --- a/test/ELF/linkerscript/pt_gnu_eh_frame.s +++ b/test/ELF/linkerscript/pt_gnu_eh_frame.s @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: echo "SECTIONS { /DISCARD/ : { *(.eh_frame*) *(.eh_frame_hdr*) } }" > %t.script -# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t +# RUN: ld.lld -o /dev/null --eh-frame-hdr --script %t.script %t .global _start _start: diff --git a/test/ELF/linkerscript/region-alias.s b/test/ELF/linkerscript/region-alias.s index 8a88f6f5ad9f..af4a0f377ddd 100644 --- a/test/ELF/linkerscript/region-alias.s +++ b/test/ELF/linkerscript/region-alias.s @@ -15,7 +15,7 @@ # RUN: echo "REGION_ALIAS (\"ALIAS_DATA\", RAM);" >> %t.script.inc # RUN: ld.lld %t --script %t.script -o %t2 # RUN: llvm-objdump -section-headers %t2 | FileCheck %s -# CHECK: .text 00000001 0000000000001000 TEXT DATA +# CHECK: .text 00000001 0000000000001000 TEXT # CHECK: .data 00000008 0000000000002000 DATA ## All to ROM. @@ -23,7 +23,7 @@ # RUN: echo "REGION_ALIAS (\"ALIAS_DATA\", ROM);" >> %t.script.inc # RUN: ld.lld %t --script %t.script -o %t2 # RUN: llvm-objdump -section-headers %t2 | FileCheck %s --check-prefix=RAM -# RAM: .text 00000001 0000000000001000 TEXT DATA +# RAM: .text 00000001 0000000000001000 TEXT # RAM: .data 00000008 0000000000001001 DATA ## Redefinition of region. diff --git a/test/ELF/linkerscript/rosegment.s b/test/ELF/linkerscript/rosegment.test index 3201b8bda9fb..41479e609d24 100644 --- a/test/ELF/linkerscript/rosegment.s +++ b/test/ELF/linkerscript/rosegment.test @@ -1,12 +1,14 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t # Test that with linker scripts we don't create a RO PT_LOAD. -# RUN: echo "SECTIONS {}" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -shared +# RUN: ld.lld -o %t1 --script %s %t -shared # RUN: llvm-readobj -l %t1 | FileCheck %s +SECTIONS { +} + # CHECK-NOT: Type: PT_LOAD # CHECK: Type: PT_LOAD diff --git a/test/ELF/linkerscript/section-metadata.s b/test/ELF/linkerscript/section-metadata.s index f447240ac3a9..44547b8ab002 100644 --- a/test/ELF/linkerscript/section-metadata.s +++ b/test/ELF/linkerscript/section-metadata.s @@ -10,15 +10,15 @@ # RUN: llvm-objdump -s %t | FileCheck --check-prefix=INV %s -# CHECK: Contents of section .text: -# CHECK-NEXT: 02000000 00000000 01000000 00000000 # CHECK: Contents of section .rodata: # CHECK-NEXT: 02000000 00000000 01000000 00000000 +# CHECK: Contents of section .text: +# CHECK-NEXT: 02000000 00000000 01000000 00000000 -# INV: Contents of section .text: -# INV-NEXT: 01000000 00000000 02000000 00000000 # INV: Contents of section .rodata: # INV-NEXT: 01000000 00000000 02000000 00000000 +# INV: Contents of section .text: +# INV-NEXT: 01000000 00000000 02000000 00000000 .global _start _start: diff --git a/test/ELF/linkerscript/section-metadata2.s b/test/ELF/linkerscript/section-metadata2.s new file mode 100644 index 000000000000..4a538b6190e7 --- /dev/null +++ b/test/ELF/linkerscript/section-metadata2.s @@ -0,0 +1,37 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { .text : { *(.text.*) } }" > %t.script + +# RUN: echo "_bar" > %t.ord +# RUN: echo "_foo" >> %t.ord +# RUN: ld.lld --symbol-ordering-file %t.ord -o %t --script %t.script %t.o +# RUN: llvm-objdump -s %t | FileCheck %s + +# CHECK: Contents of section .rodata: +# CHECK-NEXT: 02000000 00000000 01000000 00000000 +# CHECK: Contents of section .text: +# CHECK-NEXT: 02000000 00000000 01000000 00000000 + +# RUN: echo "_foo" > %t.ord +# RUN: echo "_bar" >> %t.ord +# RUN: ld.lld --symbol-ordering-file %t.ord -o %t --script %t.script %t.o +# RUN: llvm-objdump -s %t | FileCheck %s --check-prefix=INV + +# INV: Contents of section .rodata: +# INV-NEXT: 01000000 00000000 02000000 00000000 +# INV: Contents of section .text: +# INV-NEXT: 01000000 00000000 02000000 00000000 + +.section .text.foo,"a",@progbits +_foo: +.quad 1 + +.section .text.bar,"a",@progbits +_bar: +.quad 2 + +.section .rodata.foo,"ao",@progbits,.text.foo +.quad 1 + +.section .rodata.bar,"ao",@progbits,.text.bar +.quad 2 diff --git a/test/ELF/linkerscript/sections-keep.s b/test/ELF/linkerscript/sections-keep.s index feb0baca9c3d..2c778e3e936b 100644 --- a/test/ELF/linkerscript/sections-keep.s +++ b/test/ELF/linkerscript/sections-keep.s @@ -1,14 +1,14 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/keep.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/keep.s -o %t1.o ## First check that section "keep" is garbage collected without using KEEP # RUN: echo "SECTIONS { \ # RUN: .text : { *(.text) } \ # RUN: .keep : { *(.keep) } \ # RUN: .temp : { *(.temp) }}" > %t.script -# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | \ +# RUN: ld.lld --gc-sections -o %t --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t | \ # RUN: FileCheck -check-prefix=SECGC %s # SECGC: Sections: # SECGC-NEXT: Idx Name Size @@ -21,8 +21,8 @@ # RUN: .text : { *(.text) } \ # RUN: .keep : { KEEP(*(.keep)) } \ # RUN: .temp : { *(.temp) }}" > %t.script -# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | \ +# RUN: ld.lld --gc-sections -o %t --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t | \ # RUN: FileCheck -check-prefix=SECNOGC %s # SECNOGC: Sections: # SECNOGC-NEXT: Idx Name Size @@ -38,14 +38,14 @@ # RUN: . = SIZEOF_HEADERS; \ # RUN: .keep : { KEEP(*(.keep)) } \ # RUN: .nokeep : { *(.keep) }}" > %t.script -# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED1 %s +# RUN: ld.lld --gc-sections -o %t --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t | FileCheck -check-prefix=MIXED1 %s # MIXED1: Sections: # MIXED1-NEXT: Idx Name Size # MIXED1-NEXT: 0 00000000 # MIXED1-NEXT: 1 .keep 00000004 -# MIXED1-NEXT: 2 .text 00000007 00000000000000ec TEXT DATA -# MIXED1-NEXT: 3 .temp 00000004 00000000000000f3 DATA +# MIXED1-NEXT: 2 .temp 00000004 00000000000000ec +# MIXED1-NEXT: 3 .text 00000007 00000000000000f0 # MIXED1-NEXT: 4 .comment 00000008 0000000000000000 # MIXED1-NEXT: 5 .symtab 00000060 0000000000000000 # MIXED1-NEXT: 6 .shstrtab 00000036 0000000000000000 @@ -59,14 +59,14 @@ # RUN: . = SIZEOF_HEADERS; \ # RUN: .nokeep : { *(.keep) } \ # RUN: .keep : { KEEP(*(.keep)) }}" > %t.script -# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t -# RUN: llvm-objdump -section-headers %t1 | FileCheck -check-prefix=MIXED2 %s +# RUN: ld.lld --gc-sections -o %t --script %t.script %t.o +# RUN: llvm-objdump -section-headers %t | FileCheck -check-prefix=MIXED2 %s # MIXED2: Sections: # MIXED2-NEXT: Idx Name Size # MIXED2-NEXT: 0 00000000 -# MIXED2-NEXT: 1 .nokeep 00000004 00000000000000e8 DATA -# MIXED2-NEXT: 2 .text 00000007 00000000000000ec TEXT DATA -# MIXED2-NEXT: 3 .temp 00000004 00000000000000f3 DATA +# MIXED2-NEXT: 1 .nokeep 00000004 00000000000000e8 +# MIXED2-NEXT: 2 .temp 00000004 00000000000000ec +# MIXED2-NEXT: 3 .text 00000007 00000000000000f0 # MIXED2-NEXT: 4 .comment 00000008 0000000000000000 # MIXED2-NEXT: 5 .symtab 00000060 0000000000000000 # MIXED2-NEXT: 6 .shstrtab 00000038 0000000000000000 @@ -75,10 +75,10 @@ # Check file pattern for kept sections. # RUN: echo "SECTIONS { \ # RUN: . = SIZEOF_HEADERS; \ -# RUN: .keep : { KEEP(*2.o(.keep)) } \ +# RUN: .keep : { KEEP(*1.o(.keep)) } \ # RUN: }" > %t.script -# RUN: ld.lld --gc-sections -o %t1 --script %t.script %t2.o %t -# RUN: llvm-objdump -s %t1 | FileCheck -check-prefix=FILEMATCH %s +# RUN: ld.lld --gc-sections -o %t --script %t.script %t1.o %t.o +# RUN: llvm-objdump -s %t | FileCheck -check-prefix=FILEMATCH %s # FILEMATCH: Contents of section .keep: # FILEMATCH-NEXT: 00e8 41414141 AAAA diff --git a/test/ELF/linkerscript/sections-max-va-overflow.s b/test/ELF/linkerscript/sections-max-va-overflow.s new file mode 100644 index 000000000000..ce771b4784c4 --- /dev/null +++ b/test/ELF/linkerscript/sections-max-va-overflow.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "SECTIONS { . = 0xfffffffffffffff1;" > %t.script +# RUN: echo " .bar : { *(.bar*) } }" >> %t.script +# RUN: not ld.lld -o /dev/null --script %t.script %t.o 2>&1 | FileCheck %s -check-prefix=ERR + +## .bar section has data in [0xfffffffffffffff1, 0xfffffffffffffff1 + 0x10] == +## [0xfffffffffffffff1, 0x1]. Check we can catch this overflow. +# ERR: error: section .bar at 0xFFFFFFFFFFFFFFF1 of size 0x10 exceeds available address space + +.section .bar,"ax",@progbits +.zero 0x10 diff --git a/test/ELF/linkerscript/sections-sort.s b/test/ELF/linkerscript/sections-sort.s index 99bbbead925c..e665c9aaa74a 100644 --- a/test/ELF/linkerscript/sections-sort.s +++ b/test/ELF/linkerscript/sections-sort.s @@ -13,13 +13,13 @@ nop .section foo, "a" .byte 0 -# CHECK: Id +# CHECK: Idx # CHECK-NEXT: 0 # CHECK-NEXT: 1 .text -# CHECK-NEXT: 2 foo -# CHECK-NEXT: 3 .dynsym -# CHECK-NEXT: 4 .hash -# CHECK-NEXT: 5 .dynstr +# CHECK-NEXT: 2 .dynsym +# CHECK-NEXT: 3 .hash +# CHECK-NEXT: 4 .dynstr +# CHECK-NEXT: 5 foo # CHECK-NEXT: 6 .dynamic # CHECK-NEXT: 7 .comment # CHECK-NEXT: 8 .symtab diff --git a/test/ELF/linkerscript/sections-va-overflow.test b/test/ELF/linkerscript/sections-va-overflow.test new file mode 100644 index 000000000000..7ede6ecc3de8 --- /dev/null +++ b/test/ELF/linkerscript/sections-va-overflow.test @@ -0,0 +1,22 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/sections-va-overflow.s -o %t.o +# RUN: not ld.lld -o /dev/null --script %s %t.o 2>&1 | FileCheck %s -check-prefix=ERR + +PHDRS { + ph_headers PT_PHDR PHDRS; + ph_text PT_LOAD FILEHDR PHDRS FLAGS (0x1 | 0x4); +} + +SECTIONS { + . = 0xffffffff20000000; + .text : { *(.text*) } : ph_text + .test 0x1000 : { BYTE(0) } + .bss : { *(.bss*) } +} + +## Section .test has VA 0x1000 and placed in the same segment as section .text +## with VA 0xffffffff20000000. That might be technically correct, but most probably +## is a result of a broken script file and causes file offset calculation overflow. +## It seems we do not have to support it, so we don't and we report an error in this case. +# ERR: error: unable to place section .text at file offset [0xFFFFFFFF20000000, 0xFFFFFFFE40000000]; check your linker script for overflows +# ERR-NOT: unable to place section .bss diff --git a/test/ELF/linkerscript/sections.s b/test/ELF/linkerscript/sections.s index dd4b12f42b89..b1e8fb5e9a12 100644 --- a/test/ELF/linkerscript/sections.s +++ b/test/ELF/linkerscript/sections.s @@ -16,7 +16,7 @@ # RUN: FileCheck -check-prefix=SEC-DEFAULT %s # Idx Name Size -# SEC-DEFAULT: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA +# SEC-DEFAULT: 1 .text 0000000e {{[0-9a-f]*}} TEXT # SEC-DEFAULT: 2 .data 00000020 {{[0-9a-f]*}} DATA # SEC-DEFAULT: 3 other 00000003 {{[0-9a-f]*}} DATA # SEC-DEFAULT: 4 .bss 00000002 {{[0-9a-f]*}} BSS @@ -47,7 +47,7 @@ # SEC-ORDER: 5 .strtab 00000008 {{[0-9a-f]*}} # SEC-ORDER: 6 .comment 00000008 {{[0-9a-f]*}} # SEC-ORDER: 7 .data 00000020 {{[0-9a-f]*}} DATA -# SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT DATA +# SEC-ORDER: 8 .text 0000000e {{[0-9a-f]*}} TEXT # .text and .data have swapped names but proper sizes and types. # RUN: echo "SECTIONS { \ @@ -58,7 +58,7 @@ # RUN: FileCheck -check-prefix=SEC-SWAP-NAMES %s # Idx Name Size -# SEC-SWAP-NAMES: 1 .data 0000000e {{[0-9a-f]*}} TEXT DATA +# SEC-SWAP-NAMES: 1 .data 0000000e {{[0-9a-f]*}} TEXT # SEC-SWAP-NAMES: 2 .text 00000020 {{[0-9a-f]*}} DATA # SEC-SWAP-NAMES: 3 other 00000003 {{[0-9a-f]*}} DATA # SEC-SWAP-NAMES: 4 .bss 00000002 {{[0-9a-f]*}} BSS @@ -80,7 +80,7 @@ # RUN: FileCheck -check-prefix=SEC-MULTI %s # Idx Name Size -# SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT DATA +# SEC-MULTI: 1 .text 0000000e {{[0-9a-f]*}} TEXT # SEC-MULTI-NEXT: .data 00000020 {{[0-9a-f]*}} DATA # SEC-MULTI-NEXT: .data 00000003 {{[0-9a-f]*}} DATA # SEC-MULTI-NEXT: .bss 00000002 {{[0-9a-f]*}} BSS diff --git a/test/ELF/linkerscript/segment-none.s b/test/ELF/linkerscript/segment-none.s index d54e835a0c22..06566525caf7 100644 --- a/test/ELF/linkerscript/segment-none.s +++ b/test/ELF/linkerscript/segment-none.s @@ -9,7 +9,7 @@ # RUN: .foo : {*(.foo)} :NONE \ # RUN: }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o -# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck %s +# RUN: llvm-readelf -s -l %t | FileCheck %s ## Test that section .foo is placed in segment NONE when assigned to segment ## NONE in the linker script and segment NONE is defined. @@ -19,7 +19,7 @@ # RUN: .foo : {*(.foo)} :NONE \ # RUN: }" > %t.script # RUN: ld.lld -o %t --script %t.script %t.o -# RUN: llvm-readobj -elf-output-style=GNU -s -l %t | FileCheck --check-prefix=DEFINED %s +# RUN: llvm-readelf -s -l %t | FileCheck --check-prefix=DEFINED %s # CHECK: Section to Segment mapping: # CHECK-NEXT: Segment Sections... diff --git a/test/ELF/linkerscript/segment-start.s b/test/ELF/linkerscript/segment-start.s index 69897d604b3b..cb47cb6cd471 100644 --- a/test/ELF/linkerscript/segment-start.s +++ b/test/ELF/linkerscript/segment-start.s @@ -22,6 +22,6 @@ .quad foobar4 // RUN: echo "SECTIONS { . = SEGMENT_START(\"foobar\", foo); }" > %t.script -// RUN: not ld.lld %t.o %t.script -shared -o %t2.so 2>&1 \ +// RUN: not ld.lld %t.o %t.script -shared -o /dev/null 2>&1 \ // RUN: | FileCheck --check-prefix=ERR %s // ERR: {{.*}}.script:1: symbol not found: foo diff --git a/test/ELF/linkerscript/sort-constructors.s b/test/ELF/linkerscript/sort-constructors.s deleted file mode 100644 index a0c23af6de79..000000000000 --- a/test/ELF/linkerscript/sort-constructors.s +++ /dev/null @@ -1,5 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o -# RUN: echo "SECTIONS { .aaa : { SORT(CONSTRUCTORS) } }" > %t1.script -# RUN: ld.lld -shared -o %t1 --script %t1.script %t1.o -# RUN: llvm-readobj %t1 > /dev/null diff --git a/test/ELF/linkerscript/sort-constructors.test b/test/ELF/linkerscript/sort-constructors.test new file mode 100644 index 000000000000..698208afd54e --- /dev/null +++ b/test/ELF/linkerscript/sort-constructors.test @@ -0,0 +1,8 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux /dev/null -o %t1.o +# RUN: ld.lld -shared -o %t1 --script %s %t1.o +# RUN: llvm-readobj %t1 > /dev/null + +SECTIONS { + .aaa : { SORT(CONSTRUCTORS) } +} diff --git a/test/ELF/linkerscript/sort-non-script.s b/test/ELF/linkerscript/sort-non-script.s index 4611b18d55ef..2477c835e134 100644 --- a/test/ELF/linkerscript/sort-non-script.s +++ b/test/ELF/linkerscript/sort-non-script.s @@ -1,14 +1,14 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "SECTIONS { foo : {*(foo)} }" > %t.script -# RUN: ld.lld --hash-style=sysv -o %t1 --script %t.script %t -shared -# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s +# RUN: ld.lld --hash-style=sysv -o %t --script %t.script %t.o -shared +# RUN: llvm-readelf -s %t | FileCheck %s -# CHECK: .text {{.*}} AX -# CHECK-NEXT: .dynsym {{.*}} A +# CHECK: .dynsym {{.*}} A # CHECK-NEXT: .hash {{.*}} A # CHECK-NEXT: .dynstr {{.*}} A +# CHECK-NEXT: .text {{.*}} AX # CHECK-NEXT: foo {{.*}} WA # CHECK-NEXT: .dynamic {{.*}} WA diff --git a/test/ELF/linkerscript/start-end.s b/test/ELF/linkerscript/start-end.s deleted file mode 100644 index b68606abc181..000000000000 --- a/test/ELF/linkerscript/start-end.s +++ /dev/null @@ -1,16 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: echo "SECTIONS { \ -# RUN: .init_array : { \ -# RUN: __init_array_start = .; \ -# RUN: *(.init_array) \ -# RUN: __init_array_end = .; } }" > %t.script -# RUN: ld.lld %t.o -script %t.script -o %t 2>&1 - -.globl _start -.text -_start: - nop - -.section .init_array, "aw" - .quad 0 diff --git a/test/ELF/linkerscript/start-end.test b/test/ELF/linkerscript/start-end.test new file mode 100644 index 000000000000..ab7504dac2d4 --- /dev/null +++ b/test/ELF/linkerscript/start-end.test @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: echo '.section .init_array, "aw"; .quad 0' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld %t.o -script %s -o %t 2>&1 + +SECTIONS { + .init_array : { + __init_array_start = .; + *(.init_array) + __init_array_end = .; + } +} diff --git a/test/ELF/linkerscript/subalign.s b/test/ELF/linkerscript/subalign.s index 1396798c82f6..99cb3f19a999 100644 --- a/test/ELF/linkerscript/subalign.s +++ b/test/ELF/linkerscript/subalign.s @@ -36,7 +36,7 @@ ## Test we fail gracefuly when alignment value is not a power of 2. # RUN: echo "SECTIONS { .aaa : SUBALIGN(3) { *(.aaa*) } }" > %t5.script -# RUN: not ld.lld %t1.o --script %t5.script -o %t5 2>&1 | FileCheck -check-prefix=ERR %s +# RUN: not ld.lld %t1.o --script %t5.script -o /dev/null 2>&1 | FileCheck -check-prefix=ERR %s # ERR: {{.*}}.script:1: alignment must be power of 2 .global _start diff --git a/test/ELF/linkerscript/symbol-assignexpr.s b/test/ELF/linkerscript/symbol-assignexpr.s index 9ab03a173f1c..3be7d05931fe 100644 --- a/test/ELF/linkerscript/symbol-assignexpr.s +++ b/test/ELF/linkerscript/symbol-assignexpr.s @@ -47,7 +47,7 @@ # CHECK-NEXT: 0000000000000001 *ABS* 00000000 symbol15 # RUN: echo "SECTIONS { symbol2 = symbol; }" > %t2.script -# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \ +# RUN: not ld.lld -o /dev/null --script %t2.script %t 2>&1 \ # RUN: | FileCheck -check-prefix=ERR %s # ERR: {{.*}}.script:1: symbol not found: symbol diff --git a/test/ELF/linkerscript/symbol-memoryexpr.s b/test/ELF/linkerscript/symbol-memoryexpr.s index 9c75274e1644..cdd821dc585a 100644 --- a/test/ELF/linkerscript/symbol-memoryexpr.s +++ b/test/ELF/linkerscript/symbol-memoryexpr.s @@ -23,7 +23,7 @@ # RUN: no_exist_origin = ORIGIN(ram); \ # RUN: no_exist_length = LENGTH(ram); \ # RUN: }" > %t2.script -# RUN: not ld.lld -o %t2 --script %t2.script %t 2>&1 \ +# RUN: not ld.lld -o /dev/null --script %t2.script %t 2>&1 \ # RUN: | FileCheck -check-prefix=ERR %s # ERR: {{.*}}.script:1: memory region not defined: ram diff --git a/test/ELF/linkerscript/symbol-only-flags.s b/test/ELF/linkerscript/symbol-only-flags.test index 300d8d88da97..cea2539cd6ba 100644 --- a/test/ELF/linkerscript/symbol-only-flags.s +++ b/test/ELF/linkerscript/symbol-only-flags.test @@ -1,11 +1,15 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; \ -# RUN: .tbss : { *(.tbss) } \ -# RUN: .foo : { bar = .; } }" > %t.script -# RUN: ld.lld -o %t --script %t.script %t.o +# RUN: echo '.section .tbss,"awT",@nobits; .quad 0' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t.o +# RUN: ld.lld -o %t --script %s %t.o # RUN: llvm-readobj -s %t | FileCheck %s +SECTIONS { + . = SIZEOF_HEADERS; + .tbss : { *(.tbss) } + .foo : { bar = .; } +} + ## Check .foo does not get SHF_TLS flag. # CHECK: Section { # CHECK: Index: @@ -15,6 +19,3 @@ # CHECK-NEXT: SHF_ALLOC # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] - -.section .tbss,"awT",@nobits -.quad 0 diff --git a/test/ELF/linkerscript/symbol-only.s b/test/ELF/linkerscript/symbol-only.s deleted file mode 100644 index 76d54f01cdc7..000000000000 --- a/test/ELF/linkerscript/symbol-only.s +++ /dev/null @@ -1,21 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: abc : { foo = .; } \ -# RUN: . = ALIGN(0x1000); \ -# RUN: bar : { *(bar) } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --script %t.script %t -shared -# RUN: llvm-objdump -section-headers -t %t1 | FileCheck %s -# CHECK: Sections: -# CHECK-NEXT: Idx Name Size Address -# CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK: abc 00000000 [[ADDR:[0-9a-f]*]] BSS -# CHECK-NEXT: bar 00000000 0000000000001000 DATA - -# CHECK: SYMBOL TABLE: -# CHECK: [[ADDR]] abc 00000000 foo - -.section bar, "a" diff --git a/test/ELF/linkerscript/symbol-only.test b/test/ELF/linkerscript/symbol-only.test new file mode 100644 index 000000000000..f2fefdc049b9 --- /dev/null +++ b/test/ELF/linkerscript/symbol-only.test @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: echo '.section bar, "a"' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t +# RUN: ld.lld -o %t1 --script %s %t -shared +# RUN: llvm-objdump -section-headers -t %t1 | FileCheck %s + +SECTIONS { + . = SIZEOF_HEADERS; + abc : { foo = .; } + . = ALIGN(0x1000); + bar : { *(bar) } +} + +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK: abc 00000000 [[ADDR:[0-9a-f]*]] +# CHECK: bar 00000000 0000000000001000 + +# CHECK: SYMBOL TABLE: +# CHECK: [[ADDR]] abc 00000000 foo diff --git a/test/ELF/linkerscript/symbol-ordering-file.s b/test/ELF/linkerscript/symbol-ordering-file.s index be686c420887..dd5e0a152ae9 100644 --- a/test/ELF/linkerscript/symbol-ordering-file.s +++ b/test/ELF/linkerscript/symbol-ordering-file.s @@ -14,6 +14,16 @@ # AFTER: Contents of section .foo: # AFTER-NEXT: 2211 +# RUN: echo "SECTIONS { .text : { *(.text) } }" > %t2.script +# RUN: ld.lld --symbol-ordering-file %t.ord %t.o --script %t2.script -o %t3.out +# RUN: llvm-objdump -s %t3.out| FileCheck %s --check-prefix=AFTER + +# RUN: echo "SECTIONS { .foo : { BYTE(0x33); *(.foo); BYTE(0x44) } }" > %t3.script +# RUN: ld.lld --symbol-ordering-file %t.ord %t.o --script %t3.script -o %t4.out +# RUN: llvm-objdump -s %t4.out| FileCheck %s --check-prefix=COMMANDS +# COMMANDS: Contents of section .foo: +# COMMANDS-NEXT: 33221144 + .section .foo,"ax",@progbits,unique,1 _foo1: .byte 0x11 diff --git a/test/ELF/linkerscript/symbol-ordering-file2.s b/test/ELF/linkerscript/symbol-ordering-file2.s new file mode 100644 index 000000000000..31746ae0a333 --- /dev/null +++ b/test/ELF/linkerscript/symbol-ordering-file2.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o + +## Check we do not crash when trying to order linker script symbol. + +# RUN: echo "bar" > %t.ord +# RUN: echo "SECTIONS { bar = 1; }" > %t.script +# RUN: ld.lld --symbol-ordering-file %t.ord %t.o --script %t.script \ +# RUN: -o %t.out 2>&1 | FileCheck %s +# CHECK: warning: <internal>: unable to order absolute symbol: bar + +## Check we do not crash when trying to order --defsym symbol. + +# RUN: echo "bar" > %t.ord +# RUN: ld.lld --symbol-ordering-file %t.ord %t.o -defsym=bar=1 \ +# RUN: -o %t.out 2>&1 | FileCheck %s diff --git a/test/ELF/linkerscript/symbols-non-alloc.s b/test/ELF/linkerscript/symbols-non-alloc.s deleted file mode 100644 index e51a39ee5d29..000000000000 --- a/test/ELF/linkerscript/symbols-non-alloc.s +++ /dev/null @@ -1,19 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t - -# RUN: echo "SECTIONS { . = SIZEOF_HEADERS; \ -# RUN: .text : { *(.text) } \ -# RUN: .nonalloc : { *(.nonalloc) } \ -# RUN: Sym = .; \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t2 --script %t.script %t -# RUN: llvm-objdump -section-headers -t %t2 | FileCheck %s - -# CHECK: Sections: -# CHECK: .nonalloc 00000008 0000000000000000 - -# CHECK: SYMBOL TABLE: -# CHECK: 0000000000000008 .nonalloc 00000000 Sym - -.section .nonalloc,"" - .quad 0 diff --git a/test/ELF/linkerscript/symbols-non-alloc.test b/test/ELF/linkerscript/symbols-non-alloc.test new file mode 100644 index 000000000000..6d7580affc26 --- /dev/null +++ b/test/ELF/linkerscript/symbols-non-alloc.test @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: echo '.section .nonalloc,""; .quad 0' \ +# RUN: | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t +# RUN: ld.lld -o %t2 --script %s %t +# RUN: llvm-objdump -section-headers -t %t2 | FileCheck %s + +# CHECK: Sections: +# CHECK: .nonalloc 00000008 0000000000000000 + +# CHECK: SYMBOL TABLE: +# CHECK: 0000000000000008 .nonalloc 00000000 Sym + +SECTIONS { + . = SIZEOF_HEADERS; + .text : { *(.text) } + .nonalloc : { *(.nonalloc) } + Sym = .; +} diff --git a/test/ELF/linkerscript/symbols-synthetic.s b/test/ELF/linkerscript/symbols-synthetic.s deleted file mode 100644 index 95cdae9a929e..000000000000 --- a/test/ELF/linkerscript/symbols-synthetic.s +++ /dev/null @@ -1,98 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# Simple symbol assignment within input section list. The '.' symbol -# is not location counter but offset from the beginning of output -# section .foo -# RUN: echo "SECTIONS { \ -# RUN: . = SIZEOF_HEADERS; \ -# RUN: .foo : { \ -# RUN: begin_foo = .; \ -# RUN: PROVIDE(_begin_sec = .); \ -# RUN: *(.foo) \ -# RUN: end_foo = .; \ -# RUN: PROVIDE_HIDDEN(_end_sec = .); \ -# RUN: PROVIDE(_end_sec_abs = ABSOLUTE(.)); \ -# RUN: size_foo_1 = SIZEOF(.foo); \ -# RUN: size_foo_1_abs = ABSOLUTE(SIZEOF(.foo)); \ -# RUN: . = ALIGN(0x1000); \ -# RUN: begin_bar = .; \ -# RUN: *(.bar) \ -# RUN: end_bar = .; \ -# RUN: size_foo_2 = SIZEOF(.foo); } \ -# RUN: size_foo_3 = SIZEOF(.foo); \ -# RUN: .eh_frame_hdr : { \ -# RUN: __eh_frame_hdr_start = .; \ -# RUN: __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10)); \ -# RUN: *(.eh_frame_hdr) \ -# RUN: __eh_frame_hdr_end = .; \ -# RUN: __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10)); } \ -# RUN: .eh_frame : { } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t -# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=SIMPLE %s - -# Check that the following script is processed without errors -# RUN: echo "SECTIONS { \ -# RUN: .eh_frame_hdr : { \ -# RUN: PROVIDE_HIDDEN(_begin_sec = .); \ -# RUN: *(.eh_frame_hdr) \ -# RUN: *(.eh_frame_hdr) \ -# RUN: PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); \ -# RUN: PROVIDE_HIDDEN(_end_sec = .); } \ -# RUN: }" > %t.script -# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t - -# Check that we can specify synthetic symbols without defining SECTIONS. -# RUN: echo "PROVIDE_HIDDEN(_begin_sec = _start); \ -# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text));" > %t.script -# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t -# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=NO-SEC %s - -# Check that we can do the same as above inside SECTIONS block. -# RUN: echo "SECTIONS { \ -# RUN: . = 0x201000; \ -# RUN: .text : { *(.text) } \ -# RUN: PROVIDE_HIDDEN(_begin_sec = ADDR(.text)); \ -# RUN: PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text)); }" > %t.script -# RUN: ld.lld -o %t1 --eh-frame-hdr --script %t.script %t -# RUN: llvm-objdump -t %t1 | FileCheck --check-prefix=IN-SEC %s - -# SIMPLE: 0000000000000128 .foo 00000000 .hidden _end_sec -# SIMPLE-NEXT: 0000000000000120 .foo 00000000 _begin_sec -# SIMPLE-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs -# SIMPLE-NEXT: 0000000000001048 .text 00000000 _start -# SIMPLE-NEXT: 0000000000000120 .foo 00000000 begin_foo -# SIMPLE-NEXT: 0000000000000128 .foo 00000000 end_foo -# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1 -# SIMPLE-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1_abs -# SIMPLE-NEXT: 0000000000001000 .foo 00000000 begin_bar -# SIMPLE-NEXT: 0000000000001004 .foo 00000000 end_bar -# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_2 -# SIMPLE-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3 -# SIMPLE-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start -# SIMPLE-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2 -# SIMPLE-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end -# SIMPLE-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2 - -# NO-SEC: 0000000000201000 .text 00000000 .hidden _begin_sec -# NO-SEC-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec - -# IN-SEC: 0000000000201000 .text 00000000 .hidden _begin_sec -# IN-SEC-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec - -.global _start -_start: - nop - -.section .foo,"a" - .quad 0 - -.section .bar,"a" - .long 0 - -.section .dah,"ax",@progbits - .cfi_startproc - nop - .cfi_endproc - -.global _begin_sec, _end_sec, _end_sec_abs diff --git a/test/ELF/linkerscript/synthetic-relsec-layout.s b/test/ELF/linkerscript/synthetic-relsec-layout.s new file mode 100644 index 000000000000..efaa946cbaa9 --- /dev/null +++ b/test/ELF/linkerscript/synthetic-relsec-layout.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "SECTIONS { .foo : { *(.rela.dyn) } }" > %t.script +# RUN: ld.lld -T %t.script %t.o -o %t.so -shared +# RUN: llvm-readobj -r %t.so | FileCheck %s + +# Check we are able to do custom layout for synthetic sections. +# (here we check we can place synthetic .rela.dyn into .foo). + +# CHECK: Relocations [ +# CHECK: Section ({{.*}}) .foo { +# CHECK: R_X86_64_64 .foo 0x0 +# CHECK: } + +.data +.quad .foo diff --git a/test/ELF/linkerscript/synthetic-symbols1.test b/test/ELF/linkerscript/synthetic-symbols1.test new file mode 100644 index 000000000000..908a05f49588 --- /dev/null +++ b/test/ELF/linkerscript/synthetic-symbols1.test @@ -0,0 +1,56 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t +# RUN: ld.lld -o %t.exe --eh-frame-hdr --script %s %t +# RUN: llvm-objdump -t %t.exe | FileCheck %s + +# Simple symbol assignment within input section list. The '.' symbol +# is not location counter but offset from the beginning of output +# section .foo + +SECTIONS { + . = SIZEOF_HEADERS; + .foo : { + begin_foo = .; + PROVIDE(_begin_sec = .); + *(.foo) + end_foo = .; + PROVIDE_HIDDEN(_end_sec = .); + PROVIDE(_end_sec_abs = ABSOLUTE(.)); + size_foo_1 = SIZEOF(.foo); + size_foo_1_abs = ABSOLUTE(SIZEOF(.foo)); + . = ALIGN(0x1000); + begin_bar = .; + *(.bar) + end_bar = .; + size_foo_2 = SIZEOF(.foo); + } + + size_foo_3 = SIZEOF(.foo); + + .eh_frame_hdr : { + __eh_frame_hdr_start = .; + __eh_frame_hdr_start2 = ABSOLUTE(ALIGN(0x10)); + *(.eh_frame_hdr) + __eh_frame_hdr_end = .; + __eh_frame_hdr_end2 = ABSOLUTE(ALIGN(0x10)); + } + + .eh_frame : {} +} + +# CHECK: 0000000000000128 .foo 00000000 .hidden _end_sec +# CHECK-NEXT: 0000000000000120 .foo 00000000 _begin_sec +# CHECK-NEXT: 0000000000000128 *ABS* 00000000 _end_sec_abs +# CHECK-NEXT: 000000000000104c .text 00000000 _start +# CHECK-NEXT: 0000000000000120 .foo 00000000 begin_foo +# CHECK-NEXT: 0000000000000128 .foo 00000000 end_foo +# CHECK-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1 +# CHECK-NEXT: 0000000000000008 *ABS* 00000000 size_foo_1_abs +# CHECK-NEXT: 0000000000001000 .foo 00000000 begin_bar +# CHECK-NEXT: 0000000000001004 .foo 00000000 end_bar +# CHECK-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_2 +# CHECK-NEXT: 0000000000000ee4 *ABS* 00000000 size_foo_3 +# CHECK-NEXT: 0000000000001004 .eh_frame_hdr 00000000 __eh_frame_hdr_start +# CHECK-NEXT: 0000000000001010 *ABS* 00000000 __eh_frame_hdr_start2 +# CHECK-NEXT: 0000000000001018 .eh_frame_hdr 00000000 __eh_frame_hdr_end +# CHECK-NEXT: 0000000000001020 *ABS* 00000000 __eh_frame_hdr_end2 diff --git a/test/ELF/linkerscript/synthetic-symbols2.test b/test/ELF/linkerscript/synthetic-symbols2.test new file mode 100644 index 000000000000..5304c1e28f01 --- /dev/null +++ b/test/ELF/linkerscript/synthetic-symbols2.test @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t +# RUN: ld.lld -o %t.exe --eh-frame-hdr --script %s %t + +SECTIONS { + .eh_frame_hdr : { + PROVIDE_HIDDEN(_begin_sec = .); + *(.eh_frame_hdr) + *(.eh_frame_hdr) + PROVIDE_HIDDEN(_end_sec_abs = ABSOLUTE(.)); + PROVIDE_HIDDEN(_end_sec = .); + } +} diff --git a/test/ELF/linkerscript/synthetic-symbols3.test b/test/ELF/linkerscript/synthetic-symbols3.test new file mode 100644 index 000000000000..a24ecccedf0b --- /dev/null +++ b/test/ELF/linkerscript/synthetic-symbols3.test @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t +# RUN: ld.lld -o %t.exe --eh-frame-hdr --script %s %t +# RUN: llvm-objdump -t %t.exe | FileCheck %s + +# Check that we can specify synthetic symbols without defining SECTIONS. +PROVIDE_HIDDEN(_begin_sec = _start); +PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text)); + +# CHECK: 0000000000201000 .text 00000000 .hidden _begin_sec +# CHECK-NEXT: 0000000000201001 .text 00000000 .hidden _end_sec diff --git a/test/ELF/linkerscript/synthetic-symbols4.test b/test/ELF/linkerscript/synthetic-symbols4.test new file mode 100644 index 000000000000..fde06e3f3a44 --- /dev/null +++ b/test/ELF/linkerscript/synthetic-symbols4.test @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/synthetic-symbols.s -o %t.o +# RUN: ld.lld -o %t --eh-frame-hdr --script %s %t.o +# RUN: llvm-objdump -t %t | FileCheck %s + +SECTIONS { + . = 0x201000; + .text : { *(.text) } + PROVIDE_HIDDEN(_begin_sec = ADDR(.text)); + PROVIDE_HIDDEN(_end_sec = ADDR(.text) + SIZEOF(.text)); +} + +# CHECK: 0000000000201054 .text 00000000 .hidden _begin_sec +# CHECK-NEXT: 0000000000201055 .text 00000000 .hidden _end_sec diff --git a/test/ELF/linkerscript/unused-synthetic.s b/test/ELF/linkerscript/unused-synthetic.s index b7cedbc8e09c..6ddbf505ccbb 100644 --- a/test/ELF/linkerscript/unused-synthetic.s +++ b/test/ELF/linkerscript/unused-synthetic.s @@ -1,17 +1,17 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: echo "SECTIONS { \ -# RUN: .got : { *(.got) } \ +# RUN: .got : { *(.got) *(.got) } \ # RUN: .plt : { *(.plt) } \ # RUN: .text : { *(.text) } \ # RUN: }" > %t.script # RUN: ld.lld -shared -o %t.so --script %t.script %t.o -# RUN: llvm-objdump -section-headers %t.so | FileCheck %s +# RUN: llvm-readelf -s %t.so | FileCheck %s # CHECK-NOT: .got # CHECK-NOT: .plt +# CHECK: .dynsym # CHECK: .text -# CHECK-NEXT: .dynsym # Test that the size of a removed unused synthetic input section is not added # to the output section size. Adding a symbol assignment prevents removal of diff --git a/test/ELF/linkerscript/unused-synthetic2.test b/test/ELF/linkerscript/unused-synthetic2.test new file mode 100644 index 000000000000..755d1af00be0 --- /dev/null +++ b/test/ELF/linkerscript/unused-synthetic2.test @@ -0,0 +1,12 @@ +# REQUIRES: arm +# RUN: llvm-mc -filetype=obj -triple=armv7-unknown-linux-gnueabi /dev/null -o %t.o + +## We incorrectly removed unused synthetic sections and crashed before. +## Check we do not crash and do not produce .trap output section. +# RUN: ld.lld -shared -o %t.so --script %s %t.o +# RUN: llvm-objdump -section-headers %t.so | FileCheck %s +# CHECK-NOT: .trap + +SECTIONS { + .trap : { *(.ARM.exidx) *(.dummy) } +} diff --git a/test/ELF/linkerscript/va.s b/test/ELF/linkerscript/va.s index 854ebcef0146..c305f0689e11 100644 --- a/test/ELF/linkerscript/va.s +++ b/test/ELF/linkerscript/va.s @@ -5,11 +5,11 @@ # RUN: ld.lld -o %t1 --script %t.script %t # RUN: llvm-objdump -section-headers %t1 | FileCheck %s # CHECK: Sections: -# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: Idx Name Size Address # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .text 00000001 0000000000000000 TEXT DATA -# CHECK-NEXT: 2 .foo 00000004 0000000000000001 DATA -# CHECK-NEXT: 3 .boo 00000004 0000000000000005 DATA +# CHECK-NEXT: 1 .foo 00000004 0000000000000000 +# CHECK-NEXT: 2 .boo 00000004 0000000000000004 +# CHECK-NEXT: 3 .text 00000001 0000000000000008 .global _start _start: diff --git a/test/ELF/linkerscript/version-script.s b/test/ELF/linkerscript/version-script.s new file mode 100644 index 000000000000..df666e1b39ea --- /dev/null +++ b/test/ELF/linkerscript/version-script.s @@ -0,0 +1,57 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +# RUN: echo "bar = foo; VERSION { V { global: foo; bar; local: *; }; }" > %t.script +# RUN: ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s + +# RUN: echo "SECTIONS { .text : { bar = foo; *(.text) } }" > %t.script +# RUN: echo "VERSION { V { global: foo; bar; local: *; }; }" >> %t.script +# RUN: ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s + +## Check that we are able to version symbols defined in script. +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: @ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: und@ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: foo@@V +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: bar@@V +# CHECK-NEXT: } +# CHECK-NEXT: ] + +# RUN: echo "bar = und; VERSION { V { global: foo; bar; local: *; }; }" > %t.script +# RUN: not ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so \ +# RUN: 2>&1 | FileCheck --check-prefix=ERR %s +# ERR: symbol not found: und + +# RUN: echo "und = 0x1; VERSION { V { global: und; local: *; }; }" > %t.script +# RUN: ld.lld -T %t.script -shared --no-undefined-version %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s --check-prefix=UNDEF +# UNDEF: Symbols [ +# UNDEF-NEXT: Symbol { +# UNDEF-NEXT: Version: 0 +# UNDEF-NEXT: Name: @ +# UNDEF-NEXT: } +# UNDEF-NEXT: Symbol { +# UNDEF-NEXT: Version: 2 +# UNDEF-NEXT: Name: und@@V +# UNDEF-NEXT: } +# UNDEF-NEXT: ] + +.global und + +.text +.globl foo +.type foo,@function +foo: diff --git a/test/ELF/llvm33-rela-outside-group.s b/test/ELF/llvm33-rela-outside-group.s index 8e7e7c4e6a4d..1c87817e0c75 100644 --- a/test/ELF/llvm33-rela-outside-group.s +++ b/test/ELF/llvm33-rela-outside-group.s @@ -1,7 +1,7 @@ // Input file generated with: // llvm33/llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %S/Inputs/llvm33-rela-outside-group.o // -// RUN: ld.lld -shared %S/Inputs/llvm33-rela-outside-group.o %S/Inputs/llvm33-rela-outside-group.o +// RUN: ld.lld -shared %S/Inputs/llvm33-rela-outside-group.o %S/Inputs/llvm33-rela-outside-group.o -o /dev/null .global bar .weak _Z3fooIiEvv diff --git a/test/ELF/local-dynamic.s b/test/ELF/local-dynamic.s index 797a1071311c..c122074fd7d9 100644 --- a/test/ELF/local-dynamic.s +++ b/test/ELF/local-dynamic.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // Check that local symbols are not inserted into dynamic table. // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %t -shared -o %t1.so // RUN: llvm-readobj -t -dyn-symbols %t1.so | FileCheck %s -// REQUIRES: x86 // CHECK: Symbols [ // CHECK-NEXT: Symbol { diff --git a/test/ELF/local-got-pie.s b/test/ELF/local-got-pie.s index b1b213af6659..c89fc1cb4ed4 100644 --- a/test/ELF/local-got-pie.s +++ b/test/ELF/local-got-pie.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: ld.lld --hash-style=sysv %t.o -o %t -pie // RUN: llvm-readobj -s -r -d %t | FileCheck %s diff --git a/test/ELF/local-got-shared.s b/test/ELF/local-got-shared.s index c858424cfd96..284135db13e0 100644 --- a/test/ELF/local-got-shared.s +++ b/test/ELF/local-got-shared.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: ld.lld --hash-style=sysv %t.o -o %t -shared // RUN: llvm-readobj -s -r -d %t | FileCheck %s diff --git a/test/ELF/local-got.s b/test/ELF/local-got.s index 17517f6a70ea..2c1bd58d7682 100644 --- a/test/ELF/local-got.s +++ b/test/ELF/local-got.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so diff --git a/test/ELF/local-symbols-order.s b/test/ELF/local-symbols-order.s new file mode 100644 index 000000000000..dfd964f2de27 --- /dev/null +++ b/test/ELF/local-symbols-order.s @@ -0,0 +1,37 @@ +# REQUIRES: x86 + +# RUN: echo '.data; .file "file2"; foo2:; .global bar2; .hidden bar2; bar2:' > %t2.s +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %t2.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o + +# RUN: ld.lld -o %t %t1.o %t2.o --emit-relocs +# RUN: llvm-readobj -symbols -sections -elf-output-style=GNU %t | FileCheck %s + +## Check we sort local symbols to match the following order: +## file1, local1, section1, hidden1, file2, local2, section2, hidden2 ... + +# CHECK: Section Headers: +# CHECK: [Nr] Name +# CHECK: [ [[ST:.*]]] .text +# CHECK: [ [[SD:.*]]] .data +# CHECK: [ [[SC:.*]]] .comment + +# CHECK: Num: Value Size Type Bind Vis Ndx Name +# CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND +# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS file1 +# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE LOCAL DEFAULT 1 foo1 +# CHECK-NEXT: 3: 0000000000201000 0 SECTION LOCAL DEFAULT [[ST]] +# CHECK-NEXT: 4: 0000000000201000 0 NOTYPE LOCAL HIDDEN 1 bar1 +# CHECK-NEXT: 5: 0000000000000000 0 FILE LOCAL DEFAULT ABS file2 +# CHECK-NEXT: 6: 0000000000201000 0 NOTYPE LOCAL DEFAULT 2 foo2 +# CHECK-NEXT: 7: 0000000000201000 0 SECTION LOCAL DEFAULT [[SD]] +# CHECK-NEXT: 8: 0000000000201000 0 NOTYPE LOCAL HIDDEN 2 bar2 +# CHECK-NEXT: 9: 0000000000000000 0 SECTION LOCAL DEFAULT [[SC]] + +foo1: + +.global bar1 +.hidden bar1 +bar1: + +.file "file1" diff --git a/test/ELF/local.s b/test/ELF/local.s index 983d7ff7ba63..cb9adc864852 100644 --- a/test/ELF/local.s +++ b/test/ELF/local.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // Check that symbol table is correctly populated with local symbols. // RUN: llvm-mc -save-temp-labels -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %t -o %t1 // RUN: llvm-readobj -t -s %t1 | FileCheck %s -// REQUIRES: x86 // Check that Info is equal to the number of local symbols. // CHECK: Section { diff --git a/test/ELF/lto-plugin-ignore.s b/test/ELF/lto-plugin-ignore.s index 2f45a43b2428..65230f1567e7 100644 --- a/test/ELF/lto-plugin-ignore.s +++ b/test/ELF/lto-plugin-ignore.s @@ -3,9 +3,8 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: ld.lld %t -plugin-opt=/foo/bar -plugin-opt=-fresolution=zed \ # RUN: -plugin-opt=-pass-through=-lgcc -plugin-opt=-function-sections \ -# RUN: -plugin-opt=-data-sections -o /dev/null +# RUN: -plugin-opt=-data-sections -plugin-opt=thinlto -o /dev/null -# RUN: not ld.lld %t -plugin-opt=-data-sectionssss \ -# RUN: -plugin-opt=-function-sectionsss 2>&1 | FileCheck %s -# CHECK: unknown option: -data-sectionsss -# CHECK: unknown option: -function-sectionsss +# RUN: not ld.lld %t -plugin-opt=-abc -plugin-opt=-xyz 2>&1 | FileCheck %s +# CHECK: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-abc' +# CHECK: error: --plugin-opt: ld.lld{{.*}}: Unknown command line argument '-xyz' diff --git a/test/ELF/lto/Inputs/absolute.s b/test/ELF/lto/Inputs/absolute.s new file mode 100644 index 000000000000..63fbc9f9234c --- /dev/null +++ b/test/ELF/lto/Inputs/absolute.s @@ -0,0 +1,2 @@ +.globl blah + blah = 0xdeadbeef diff --git a/test/ELF/lto/Inputs/archive-3.ll b/test/ELF/lto/Inputs/archive-3.ll index ad8fb1e33ef2..37442469aa7e 100644 --- a/test/ELF/lto/Inputs/archive-3.ll +++ b/test/ELF/lto/Inputs/archive-3.ll @@ -1,5 +1,6 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" + define void @foo() { ret void } diff --git a/test/ELF/lto/Inputs/asmundef.ll b/test/ELF/lto/Inputs/asmundef.ll new file mode 100644 index 000000000000..0992f79c9af8 --- /dev/null +++ b/test/ELF/lto/Inputs/asmundef.ll @@ -0,0 +1,4 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @patatino() diff --git a/test/ELF/lto/Inputs/common3.ll b/test/ELF/lto/Inputs/common3.ll index a4efc6591570..8f20a1e8ac2d 100644 --- a/test/ELF/lto/Inputs/common3.ll +++ b/test/ELF/lto/Inputs/common3.ll @@ -1,3 +1,4 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" + @a = common hidden global i64 0, align 4 diff --git a/test/ELF/lto/Inputs/i386-empty.ll b/test/ELF/lto/Inputs/i386-empty.ll new file mode 100644 index 000000000000..6029cb6d0900 --- /dev/null +++ b/test/ELF/lto/Inputs/i386-empty.ll @@ -0,0 +1,2 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "i686-linux-gnu" diff --git a/test/ELF/lto/Inputs/lazy-internal.ll b/test/ELF/lto/Inputs/lazy-internal.ll new file mode 100644 index 000000000000..918791c5d20f --- /dev/null +++ b/test/ELF/lto/Inputs/lazy-internal.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define hidden void @bar() { + ret void +} diff --git a/test/ELF/lto/Inputs/sample-profile.prof b/test/ELF/lto/Inputs/sample-profile.prof new file mode 100644 index 000000000000..0ccd747bd376 --- /dev/null +++ b/test/ELF/lto/Inputs/sample-profile.prof @@ -0,0 +1 @@ +f:0:0 diff --git a/test/ELF/lto/Inputs/thinlto_empty.ll b/test/ELF/lto/Inputs/thinlto_empty.ll new file mode 100644 index 000000000000..a3c99cdfe772 --- /dev/null +++ b/test/ELF/lto/Inputs/thinlto_empty.ll @@ -0,0 +1,2 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/Inputs/weakodr-visibility.ll b/test/ELF/lto/Inputs/weakodr-visibility.ll new file mode 100644 index 000000000000..1bd956059d24 --- /dev/null +++ b/test/ELF/lto/Inputs/weakodr-visibility.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define weak_odr protected i32 @foo(i8* %this) { + ret i32 42 +} diff --git a/test/ELF/lto/abs-resol.ll b/test/ELF/lto/abs-resol.ll new file mode 100644 index 000000000000..4b0fb47a9e21 --- /dev/null +++ b/test/ELF/lto/abs-resol.ll @@ -0,0 +1,17 @@ +; REQUIRES: x86 + +; RUN: llvm-as %s -o %t.o +; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/absolute.s -o %t2.o -filetype=obj +; RUN: ld.lld %t.o %t2.o -o %t3.out -pie + +; RUN: echo "blah = 0xdeadfeef;" > %t.script +; RUN: ld.lld %t.o -T%t.script -o %t4.out -pie + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@blah = external global i8, align 1 + +define i8* @_start() { + ret i8* @blah +} diff --git a/test/ELF/lto/archive-2.ll b/test/ELF/lto/archive-2.ll index 6712d60c11e3..28e349ebd317 100644 --- a/test/ELF/lto/archive-2.ll +++ b/test/ELF/lto/archive-2.ll @@ -3,9 +3,9 @@ ; RUN: rm -f %t.a ; RUN: llvm-ar rcs %t.a %t1.o ; RUN: llvm-as %s -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3 +; RUN: ld.lld %t2.o %t.a -o %t3 ; RUN: llvm-readobj -t %t3 | FileCheck %s -; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared +; RUN: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared ; RUN: llvm-readobj -t %t3 | FileCheck %s ; CHECK: Name: _start ( diff --git a/test/ELF/lto/archive-3.ll b/test/ELF/lto/archive-3.ll index 0322e412539a..fec1b6155238 100644 --- a/test/ELF/lto/archive-3.ll +++ b/test/ELF/lto/archive-3.ll @@ -2,12 +2,12 @@ ; RUN: llvm-as %S/Inputs/archive-3.ll -o %t1.o ; RUN: llvm-as %s -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t3 -save-temps +; RUN: ld.lld %t1.o %t2.o -o %t3 -save-temps ; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s ; RUN: rm -f %t.a ; RUN: llvm-ar rcs %t.a %t1.o -; RUN: ld.lld -m elf_x86_64 %t.a %t1.o %t2.o -o %t3 -save-temps +; RUN: ld.lld %t.a %t1.o %t2.o -o %t3 -save-temps ; RUN: llvm-dis %t3.0.2.internalize.bc -o - | FileCheck %s ; CHECK: define internal void @foo() { diff --git a/test/ELF/lto/archive-no-index.ll b/test/ELF/lto/archive-no-index.ll index 48cca0aa0794..5ac2628fefd8 100644 --- a/test/ELF/lto/archive-no-index.ll +++ b/test/ELF/lto/archive-no-index.ll @@ -11,8 +11,8 @@ ; RUN: llvm-ar crS %t1.a %t2.o ; RUN: llvm-ar crs %t2.a %t2.o -; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t1.a -; RUN: ld.lld -o %t -emain -m elf_x86_64 %t1.o %t2.a +; RUN: ld.lld -o %t -emain %t1.o %t1.a +; RUN: ld.lld -o %t -emain %t1.o %t2.a target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/archive.ll b/test/ELF/lto/archive.ll index b4d011fdb888..6c4ca5e9aaaa 100644 --- a/test/ELF/lto/archive.ll +++ b/test/ELF/lto/archive.ll @@ -3,9 +3,9 @@ ; RUN: rm -f %t.a ; RUN: llvm-ar rcs %t.a %t1.o ; RUN: llvm-as %s -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t2.o %t.a -o %t3 -shared +; RUN: ld.lld %t2.o %t.a -o %t3 -shared ; RUN: llvm-readobj -t %t3 | FileCheck %s -; RUN: ld.lld -m elf_x86_64 %t2.o --whole-archive %t.a -o %t3 -shared +; RUN: ld.lld %t2.o --whole-archive %t.a -o %t3 -shared ; RUN: llvm-readobj -t %t3 | FileCheck %s ; CHECK: Name: g ( diff --git a/test/ELF/lto/asmundef.ll b/test/ELF/lto/asmundef.ll index d03a5e387213..604af8f9380b 100644 --- a/test/ELF/lto/asmundef.ll +++ b/test/ELF/lto/asmundef.ll @@ -1,6 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t -save-temps +; RUN: llvm-as %S/Inputs/asmundef.ll -o %t2.o +; RUN: ld.lld %t.o %t2.o -o %t -save-temps ; RUN: llvm-dis %t.0.4.opt.bc -o - | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @@ -20,5 +21,5 @@ define void @_start() { ret void } -; CHECK: define void @foo +; CHECK: define dso_local void @foo diff --git a/test/ELF/lto/available-externally.ll b/test/ELF/lto/available-externally.ll index 315e710ec87c..516bec8c8a4e 100644 --- a/test/ELF/lto/available-externally.ll +++ b/test/ELF/lto/available-externally.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-as %p/Inputs/available-externally.ll -o %t2.o -; RUN: ld.lld %t1.o %t2.o -m elf_x86_64 -o %t.so -shared -save-temps +; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps ; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/bitcode-nodatalayout.ll b/test/ELF/lto/bitcode-nodatalayout.ll index 5c4883a42444..c99cbb8550f0 100644 --- a/test/ELF/lto/bitcode-nodatalayout.ll +++ b/test/ELF/lto/bitcode-nodatalayout.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: not ld.lld -m elf_x86_64 %t.o -o %t 2>&1 | FileCheck %s +; RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s ; CHECK: input module has no datalayout diff --git a/test/ELF/lto/cache.ll b/test/ELF/lto/cache.ll index 5ab74f5c5457..3f2bea9f2cdf 100644 --- a/test/ELF/lto/cache.ll +++ b/test/ELF/lto/cache.ll @@ -13,7 +13,7 @@ ; RUN: ls %t.cache | count 4 ; Create a file of size 64KB. -; RUN: %python -c "print(' ' * 65536)" > %t.cache/llvmcache-foo +; RUN: "%python" -c "print(' ' * 65536)" > %t.cache/llvmcache-foo ; This should leave the file in place. ; RUN: ld.lld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=128k:prune_interval=0s -o %t3 %t2.o %t.o diff --git a/test/ELF/lto/codemodel.ll b/test/ELF/lto/codemodel.ll index cc126202f299..995575a9a0ab 100644 --- a/test/ELF/lto/codemodel.ll +++ b/test/ELF/lto/codemodel.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %ts -mllvm -code-model=small -; RUN: ld.lld -m elf_x86_64 %t.o -o %tl -mllvm -code-model=large +; RUN: ld.lld %t.o -o %ts -mllvm -code-model=small +; RUN: ld.lld %t.o -o %tl -mllvm -code-model=large ; RUN: llvm-objdump -d %ts | FileCheck %s --check-prefix=CHECK-SMALL ; RUN: llvm-objdump -d %tl | FileCheck %s --check-prefix=CHECK-LARGE diff --git a/test/ELF/lto/combined-lto-object-name.ll b/test/ELF/lto/combined-lto-object-name.ll index 76564f90c665..e0b98740e0f0 100644 --- a/test/ELF/lto/combined-lto-object-name.ll +++ b/test/ELF/lto/combined-lto-object-name.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: not ld.lld -m elf_x86_64 %t.o -o %t2 2>&1 | FileCheck %s +; RUN: not ld.lld %t.o -o %t2 2>&1 | FileCheck %s target triple = "x86_64-unknown-linux-gnu" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/comdat.ll b/test/ELF/lto/comdat.ll index e1384d0abd23..1739351220cd 100644 --- a/test/ELF/lto/comdat.ll +++ b/test/ELF/lto/comdat.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared +; RUN: ld.lld %t.o %t.o -o %t.so -shared ; RUN: llvm-readobj -t %t.so | FileCheck %s ; CHECK: Name: foo diff --git a/test/ELF/lto/comdat2.ll b/test/ELF/lto/comdat2.ll index 283182155ae6..e7c6ea10b5e2 100644 --- a/test/ELF/lto/comdat2.ll +++ b/test/ELF/lto/comdat2.ll @@ -1,9 +1,9 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/comdat.s -o %t2.o -filetype=obj -; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared +; RUN: ld.lld %t.o %t2.o -o %t.so -shared ; RUN: llvm-readobj -t %t.so | FileCheck %s -; RUN: ld.lld -m elf_x86_64 %t2.o %t.o -o %t2.so -shared +; RUN: ld.lld %t2.o %t.o -o %t2.so -shared ; RUN: llvm-readobj -t %t2.so | FileCheck %s --check-prefix=OTHER diff --git a/test/ELF/lto/common2.ll b/test/ELF/lto/common2.ll index 2345a203b24c..1cb5c322ba05 100644 --- a/test/ELF/lto/common2.ll +++ b/test/ELF/lto/common2.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o -; RUN: ld.lld -m elf_x86_64 %t1.o -o %t -shared -save-temps +; RUN: ld.lld %t1.o -o %t -shared -save-temps ; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s ; RUN: llvm-readobj -t %t | FileCheck %s --check-prefix=SHARED diff --git a/test/ELF/lto/common3.ll b/test/ELF/lto/common3.ll index aea33f443f4c..de52615e24f4 100644 --- a/test/ELF/lto/common3.ll +++ b/test/ELF/lto/common3.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-as %S/Inputs/common3.ll -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t -shared -save-temps +; RUN: ld.lld %t1.o %t2.o -o %t -shared -save-temps ; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/cpu-string.ll b/test/ELF/lto/cpu-string.ll new file mode 100644 index 000000000000..ff80dbb9a7b3 --- /dev/null +++ b/test/ELF/lto/cpu-string.ll @@ -0,0 +1,25 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o + +; RUN: ld.lld %t.o -o %t.so -shared +; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.so | FileCheck %s +; CHECK: nop{{$}} + +; RUN: ld.lld -mllvm -mcpu=znver1 %t.o -o %t.znver1.so -shared +; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.znver1.so | FileCheck -check-prefix=ZNVER1 %s +; ZNVER1: nopw + +; Check we are able to use -plugin-opt=mcpu=<CPU> to set CPU string. +; RUN: ld.lld -plugin-opt=mcpu=znver1 %t.o -o %t.znver1.so -shared +; RUN: llvm-objdump -d -section=".text" -no-leading-addr -no-show-raw-insn %t.znver1.so | FileCheck -check-prefix=ZNVER1 %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @foo() #0 { +entry: + call void asm sideeffect ".p2align 4, 0x90", "~{dirflag},~{fpsr},~{flags}"() + ret void +} + +attributes #0 = { "no-frame-pointer-elim"="true" } diff --git a/test/ELF/lto/ctors.ll b/test/ELF/lto/ctors.ll index 7fce645f28f6..f64189711aa5 100644 --- a/test/ELF/lto/ctors.ll +++ b/test/ELF/lto/ctors.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared +; RUN: ld.lld %t.o -o %t.so -shared ; RUN: llvm-readobj -sections %t.so | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/data-ordering-lto.s b/test/ELF/lto/data-ordering-lto.s index 0364e587b908..bdacccc35400 100644 --- a/test/ELF/lto/data-ordering-lto.s +++ b/test/ELF/lto/data-ordering-lto.s @@ -8,17 +8,18 @@ # RUN: echo "pat " >> %t_order_lto.txt # RUN: ld.lld --symbol-ordering-file %t_order_lto.txt %t.o %t.bc -o %t2.out -# RUN: llvm-readobj -elf-output-style=GNU -t %t2.out| FileCheck %s +# RUN: llvm-readelf -t %t2.out| FileCheck %s # Check that the order is tin -> dipsy -> pat. -# CHECK: Symbol table '.symtab' contains 5 entries: +# CHECK: Symbol table '.symtab' contains 6 entries: # CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name # CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND -# CHECK-NEXT: 1: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start -# CHECK-NEXT: 2: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy -# CHECK-NEXT: 3: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat -# CHECK-NEXT: 4: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin +# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o +# CHECK-NEXT: 2: 0000000000201000 0 NOTYPE GLOBAL DEFAULT 1 _start +# CHECK-NEXT: 3: 0000000000202004 4 OBJECT GLOBAL DEFAULT 2 dipsy +# CHECK-NEXT: 4: 0000000000202008 4 OBJECT GLOBAL DEFAULT 2 pat +# CHECK-NEXT: 5: 0000000000202000 4 OBJECT GLOBAL DEFAULT 2 tin .globl _start _start: diff --git a/test/ELF/lto/debugger-tune.ll b/test/ELF/lto/debugger-tune.ll new file mode 100644 index 000000000000..b7457756bcb1 --- /dev/null +++ b/test/ELF/lto/debugger-tune.ll @@ -0,0 +1,35 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o + +; Here we verify that -debugger-tune=<value> option is +; handled by LLD. DWARF linkage name attributes are optional, +; they normally present, but are missing for SCE debugger tune. + +; RUN: ld.lld %t.o -o %t.exe +; RUN: llvm-dwarfdump %t.exe | FileCheck %s +; CHECK: DW_AT_linkage_name ("name_of_foo") + +; RUN: ld.lld -plugin-opt=-debugger-tune=sce %t.o -o %t.exe +; RUN: llvm-dwarfdump %t.exe | FileCheck --check-prefix=SCE %s +; SCE-NOT: name_of_foo + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foo = global i32 0, align 4, !dbg !0 + +!llvm.dbg.cu = !{!5} +!llvm.module.flags = !{!8, !9} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "global_foo", linkageName: "name_of_foo", scope: !2, + file: !3, line: 2, type: !4, isLocal: false, isDefinition: true) +!2 = !DINamespace(name: "test", scope: null) +!3 = !DIFile(filename: "test.cpp", directory: "/home/tests") +!4 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!5 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, producer: "clang", + isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !6, globals: !7) +!6 = !{} +!7 = !{!0} +!8 = !{i32 2, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll index 2ce8570f9b68..e5f0a4875f59 100644 --- a/test/ELF/lto/defsym.ll +++ b/test/ELF/lto/defsym.ll @@ -2,14 +2,18 @@ ; LTO ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %S/Inputs/defsym-bar.ll -o %t1.o -; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 -save-temps +; RUN: llvm-readelf -t %t.so.lto.o | FileCheck --check-prefix=OBJ %s ; RUN: llvm-objdump -d %t.so | FileCheck %s ; ThinLTO ; RUN: opt -module-summary %s -o %t.o ; RUN: opt -module-summary %S/Inputs/defsym-bar.ll -o %t1.o -; RUN: ld.lld %t.o %t1.o -shared -o %t.so -defsym=bar2=bar3 -; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=THIN +; RUN: ld.lld %t.o %t1.o -shared -o %t2.so -defsym=bar2=bar3 -save-temps +; RUN: llvm-readelf -t %t2.so1.lto.o | FileCheck --check-prefix=OBJ %s +; RUN: llvm-objdump -d %t2.so | FileCheck %s --check-prefix=THIN + +; OBJ: UND bar2 ; Call to bar2() should not be inlined and should be routed to bar3() ; Symbol bar3 should not be eliminated diff --git a/test/ELF/lto/discard-value-names.ll b/test/ELF/lto/discard-value-names.ll index f1e95fe75000..485014e94d9b 100644 --- a/test/ELF/lto/discard-value-names.ll +++ b/test/ELF/lto/discard-value-names.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 -shared -save-temps %t.o -o %t2.o +; RUN: ld.lld -shared -save-temps %t.o -o %t2.o ; RUN: llvm-dis < %t2.o.0.0.preopt.bc | FileCheck %s ; CHECK: @GlobalValueName diff --git a/test/ELF/lto/drop-debug-info.ll b/test/ELF/lto/drop-debug-info.ll index 27c0260080eb..f820faf5d0e9 100644 --- a/test/ELF/lto/drop-debug-info.ll +++ b/test/ELF/lto/drop-debug-info.ll @@ -3,7 +3,7 @@ ; drop-debug-info.bc was created from "void f(void) {}" with clang 3.5 and ; -gline-tables-only, so it contains old debug info. ; -; RUN: ld.lld -m elf_x86_64 -shared %p/Inputs/drop-debug-info.bc \ -; RUN: -disable-verify 2>&1 | FileCheck %s +; RUN: ld.lld -shared %p/Inputs/drop-debug-info.bc \ +; RUN: -disable-verify -o %t 2>&1 | FileCheck %s ; CHECK: ignoring debug info with an invalid version (1) in {{.*}}drop-debug-info.bc diff --git a/test/ELF/lto/drop-linkage.ll b/test/ELF/lto/drop-linkage.ll index 1ff179666f0e..f02fa02bc4fd 100644 --- a/test/ELF/lto/drop-linkage.ll +++ b/test/ELF/lto/drop-linkage.ll @@ -1,12 +1,12 @@ -target triple = "x86_64-unknown-linux-gnu" -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" - ; REQUIRES: x86 ; RUN: llc %s -o %t.o -filetype=obj ; RUN: llvm-as %p/Inputs/drop-linkage.ll -o %t2.o ; RUN: ld.lld %t.o %t2.o -o %t.so -save-temps -shared ; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s +target triple = "x86_64-unknown-linux-gnu" +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" + define void @foo() { ret void } diff --git a/test/ELF/lto/duplicated.ll b/test/ELF/lto/duplicated.ll index 156748117a23..fc60fbab23c9 100644 --- a/test/ELF/lto/duplicated.ll +++ b/test/ELF/lto/duplicated.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: not ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared 2>&1 | FileCheck %s +; RUN: not ld.lld %t.o %t.o -o %t.so -shared 2>&1 | FileCheck %s ; CHECK: duplicate symbol: f ; CHECK-NEXT: >>> defined in {{.*}}.o diff --git a/test/ELF/lto/dynamic-list.ll b/test/ELF/lto/dynamic-list.ll index 0e950b3c83fd..c5473d833380 100644 --- a/test/ELF/lto/dynamic-list.ll +++ b/test/ELF/lto/dynamic-list.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: echo "{ foo; };" > %t.list -; RUN: ld.lld -m elf_x86_64 -o %t --dynamic-list %t.list -pie %t.o +; RUN: ld.lld -o %t --dynamic-list %t.list -pie %t.o ; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s ; CHECK: Name: foo@ diff --git a/test/ELF/lto/dynsym.ll b/test/ELF/lto/dynsym.ll index b2b4157820b5..d056c0b555e3 100644 --- a/test/ELF/lto/dynsym.ll +++ b/test/ELF/lto/dynsym.ll @@ -1,12 +1,12 @@ ; REQUIRES: x86 ; RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux -o %t.o %p/Inputs/dynsym.s -; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared +; RUN: ld.lld %t.o -o %t.so -shared ; RUN: llvm-as %s -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t2.o %t.so -o %t +; RUN: ld.lld %t2.o %t.so -o %t ; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s ; Check that we don't crash when gc'ing sections and printing the result. -; RUN: ld.lld -m elf_x86_64 %t2.o %t.so --gc-sections --print-gc-sections \ +; RUN: ld.lld %t2.o %t.so --gc-sections --print-gc-sections \ ; RUN: -o %t ; RUN: llvm-readobj -dyn-symbols %t | FileCheck %s diff --git a/test/ELF/lto/inline-asm.ll b/test/ELF/lto/inline-asm.ll index b6af6a5a5cbb..e0732e6def54 100644 --- a/test/ELF/lto/inline-asm.ll +++ b/test/ELF/lto/inline-asm.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared +; RUN: ld.lld %t.o -o %t.so -shared target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/internalize-basic.ll b/test/ELF/lto/internalize-basic.ll index 43c1837528f5..5197654d5880 100644 --- a/test/ELF/lto/internalize-basic.ll +++ b/test/ELF/lto/internalize-basic.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps +; RUN: ld.lld %t.o -o %t2 -save-temps ; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s target triple = "x86_64-unknown-linux-gnu" @@ -15,7 +15,7 @@ define hidden void @foo() { } ; Check that _start is not internalized. -; CHECK: define void @_start() +; CHECK: define dso_local void @_start() ; Check that foo function is correctly internalized. ; CHECK: define internal void @foo() diff --git a/test/ELF/lto/internalize-exportdyn.ll b/test/ELF/lto/internalize-exportdyn.ll index 2034a2b3ab72..7c996e19f354 100644 --- a/test/ELF/lto/internalize-exportdyn.ll +++ b/test/ELF/lto/internalize-exportdyn.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %p/Inputs/internalize-exportdyn.ll -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t2 --export-dynamic -save-temps +; RUN: ld.lld %t.o %t2.o -o %t2 --export-dynamic -save-temps ; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s target triple = "x86_64-unknown-linux-gnu" @@ -38,10 +38,10 @@ define linkonce_odr void @baz() { @use_baz = global void ()* @baz ; Check what gets internalized. -; CHECK: define void @_start() -; CHECK: define void @foo() +; CHECK: define dso_local void @_start() +; CHECK: define dso_local void @foo() ; CHECK: define internal void @bar() ; CHECK: define internal void @zed() ; CHECK: define internal void @zed2() -; CHECK: define weak_odr void @bah() -; CHECK: define weak_odr void @baz() +; CHECK: define weak_odr dso_local void @bah() +; CHECK: define weak_odr dso_local void @baz() diff --git a/test/ELF/lto/internalize-llvmused.ll b/test/ELF/lto/internalize-llvmused.ll index 253dcb26d042..7e3d867da596 100644 --- a/test/ELF/lto/internalize-llvmused.ll +++ b/test/ELF/lto/internalize-llvmused.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -save-temps +; RUN: ld.lld %t.o -o %t2 -save-temps ; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/internalize-undef.ll b/test/ELF/lto/internalize-undef.ll index f76528bda3b0..c0860d8943bd 100644 --- a/test/ELF/lto/internalize-undef.ll +++ b/test/ELF/lto/internalize-undef.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %p/Inputs/internalize-undef.ll -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps +; RUN: ld.lld %t.o %t2.o -o %t -save-temps ; RUN: llvm-dis < %t.0.2.internalize.bc | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/internalize-version-script.ll b/test/ELF/lto/internalize-version-script.ll index c577e43b50e4..7e242e1a7eff 100644 --- a/test/ELF/lto/internalize-version-script.ll +++ b/test/ELF/lto/internalize-version-script.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: echo "{ global: foo; local: *; };" > %t.script -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps +; RUN: ld.lld %t.o -o %t2 -shared --version-script %t.script -save-temps ; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/irmover-error.ll b/test/ELF/lto/irmover-error.ll index 8b9836d23ca4..d1c962ff7250 100644 --- a/test/ELF/lto/irmover-error.ll +++ b/test/ELF/lto/irmover-error.ll @@ -1,6 +1,6 @@ ; RUN: llvm-as -o %t1.bc %s ; RUN: llvm-as -o %t2.bc %S/Inputs/irmover-error.ll -; RUN: not ld.lld -m elf_x86_64 %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s +; RUN: not ld.lld %t1.bc %t2.bc -o %t 2>&1 | FileCheck %s ; CHECK: linking module flags 'foo': IDs have conflicting values diff --git a/test/ELF/lto/keep-undefined.ll b/test/ELF/lto/keep-undefined.ll index cb0f4ce491f9..55d2a05b48f9 100644 --- a/test/ELF/lto/keep-undefined.ll +++ b/test/ELF/lto/keep-undefined.ll @@ -2,7 +2,7 @@ ; This test checks that symbols which are specified in "-u" switches ; are kept over LTO if we link an executable. ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %tout -u foo +; RUN: ld.lld %t.o -o %tout -u foo ; RUN: llvm-nm %tout | FileCheck %s ; CHECK: T foo diff --git a/test/ELF/lto/lazy-internal.ll b/test/ELF/lto/lazy-internal.ll new file mode 100644 index 000000000000..1bb2bac3d59e --- /dev/null +++ b/test/ELF/lto/lazy-internal.ll @@ -0,0 +1,19 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t1.o +; RUN: llvm-as %p/Inputs/lazy-internal.ll -o %t2.o +; RUN: rm -f %t2.a +; RUN: llvm-ar rc %t2.a %t2.o +; RUN: ld.lld %t2.a %t1.o -o %t.so -shared -save-temps +; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s + +; CHECK: define internal void @foo() +; CHECK: define internal void @bar() + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define hidden void @foo() { + call void @bar() + ret void +} +declare void @bar() diff --git a/test/ELF/lto/linkage.ll b/test/ELF/lto/linkage.ll index 5af9b321eeec..9b9390002c7a 100644 --- a/test/ELF/lto/linkage.ll +++ b/test/ELF/lto/linkage.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o -; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared +; RUN: ld.lld %t1.o %t1.o -o %t.so -shared ; RUN: llvm-nm %t.so | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/linker-script-symbols-assign.ll b/test/ELF/lto/linker-script-symbols-assign.ll index 2ffdc823a484..bd7a37402997 100644 --- a/test/ELF/lto/linker-script-symbols-assign.ll +++ b/test/ELF/lto/linker-script-symbols-assign.ll @@ -2,20 +2,11 @@ ; RUN: llvm-as %s -o %t.o ; RUN: echo "foo = 1;" > %t.script -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 --script %t.script -save-temps +; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps ; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s ; CHECK-NOT: bar -; CHECK: Symbol { -; CHECK: Name: foo -; CHECK-NEXT: Value: 0x0 -; CHECK-NEXT: Size: 4 -; CHECK-NEXT: Binding: Weak -; CHECK-NEXT: Type: Object -; CHECK-NEXT: Other: 0 -; CHECK-NEXT: Section: .bss.foo -; CHECK-NEXT: } -; CHECK-NEXT:] +; CHECK-NOT: foo ; RUN: llvm-readobj -symbols %t2 | FileCheck %s --check-prefix=VAL ; VAL: Symbol { @@ -29,7 +20,7 @@ ; VAL-NEXT: } ; RUN: echo "zed = 1;" > %t2.script -; RUN: ld.lld -m elf_x86_64 %t.o -o %t3 --script %t2.script +; RUN: ld.lld %t.o -o %t3 --script %t2.script ; RUN: llvm-readobj -symbols %t3 | FileCheck %s --check-prefix=ABS ; ABS: Symbol { ; ABS: Name: zed diff --git a/test/ELF/lto/linker-script-symbols-ipo.ll b/test/ELF/lto/linker-script-symbols-ipo.ll index 6ac1a83e1ec0..4cc95c6cacaf 100644 --- a/test/ELF/lto/linker-script-symbols-ipo.ll +++ b/test/ELF/lto/linker-script-symbols-ipo.ll @@ -4,7 +4,7 @@ ; RUN: echo "bar = foo;" > %t.script ;; Check that without linkerscript bar is inlined. -; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t3 -save-temps +; RUN: ld.lld %t1.o %t2.o -o %t3 -save-temps ; RUN: llvm-objdump -d %t3 | FileCheck %s --check-prefix=IPO ; IPO: Disassembly of section .text: ; IPO: _start: @@ -12,13 +12,13 @@ ; IPO-NEXT: 201005: {{.*}} retq ;; Check that LTO does not do IPO for symbols assigned by script. -; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t4 --script %t.script -save-temps +; RUN: ld.lld %t1.o %t2.o -o %t4 --script %t.script -save-temps ; RUN: llvm-objdump -d %t4 | FileCheck %s --check-prefix=NOIPO ; NOIPO: Disassembly of section .text: ; NOIPO: foo: -; NOIPO-NEXT: 201010: {{.*}} movl $2, %eax +; NOIPO-NEXT: {{.*}} movl $2, %eax ; NOIPO: _start: -; NOIPO-NEXT: 201020: {{.*}} jmp -21 <foo> +; NOIPO-NEXT: {{.*}} jmp -21 <foo> target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/linker-script-symbols.ll b/test/ELF/lto/linker-script-symbols.ll index c2a58b6e841d..28758c052067 100644 --- a/test/ELF/lto/linker-script-symbols.ll +++ b/test/ELF/lto/linker-script-symbols.ll @@ -2,7 +2,7 @@ ; RUN: llvm-as %s -o %t.o ; RUN: echo "foo = bar;" > %t.script -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 --script %t.script -save-temps +; RUN: ld.lld %t.o -o %t2 --script %t.script -save-temps ; RUN: llvm-readobj -symbols %t2.lto.o | FileCheck %s ; CHECK-NOT: zed diff --git a/test/ELF/lto/lto-start.ll b/test/ELF/lto/lto-start.ll index e93eecfbf033..cc1eb4bd5b01 100644 --- a/test/ELF/lto/lto-start.ll +++ b/test/ELF/lto/lto-start.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 +; RUN: ld.lld %t.o -o %t2 ; RUN: llvm-readobj -t %t2 | FileCheck %s ; CHECK: Format: ELF64-x86-64 diff --git a/test/ELF/lto/ltopasses-basic.ll b/test/ELF/lto/ltopasses-basic.ll index 0c4ad8b9f17c..6789bdc95fe1 100644 --- a/test/ELF/lto/ltopasses-basic.ll +++ b/test/ELF/lto/ltopasses-basic.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM +; RUN: ld.lld %t.o -o %t.so -save-temps -mllvm -debug-pass=Arguments -shared 2>&1 | FileCheck %s --check-prefix=MLLVM ; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/ltopasses-custom.ll b/test/ELF/lto/ltopasses-custom.ll index a48959a32991..a75000d5cfd3 100644 --- a/test/ELF/lto/ltopasses-custom.ll +++ b/test/ELF/lto/ltopasses-custom.ll @@ -1,8 +1,8 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps --lto-aa-pipeline=basic-aa \ +; RUN: ld.lld %t.o -o %t.so -save-temps --lto-aa-pipeline=basic-aa \ ; RUN: --lto-newpm-passes=ipsccp -shared -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared +; RUN: ld.lld %t.o -o %t2.so -save-temps --lto-newpm-passes=loweratomic -shared ; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s ; RUN: llvm-dis %t2.so.0.4.opt.bc -o - | FileCheck %s --check-prefix=ATOMIC diff --git a/test/ELF/lto/metadata.ll b/test/ELF/lto/metadata.ll index 2eaacaae2726..238b5bd43b70 100644 --- a/test/ELF/lto/metadata.ll +++ b/test/ELF/lto/metadata.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o -; RUN: ld.lld -m elf_x86_64 %t1.o %t1.o -o %t.so -shared +; RUN: ld.lld %t1.o %t1.o -o %t.so -shared target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/mix-platforms2.ll b/test/ELF/lto/mix-platforms2.ll new file mode 100644 index 000000000000..1bd989e86746 --- /dev/null +++ b/test/ELF/lto/mix-platforms2.ll @@ -0,0 +1,9 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %tx64.o +; RUN: llvm-as %S/Inputs/i386-empty.ll -o %ti386.o +; RUN: not ld.lld %ti386.o %tx64.o -o %t.out 2>&1 | FileCheck %s + +; CHECK: {{.*}}x64.o is incompatible with {{.*}}i386.o + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/module-asm.ll b/test/ELF/lto/module-asm.ll index 1389b9f5472e..eaf276214221 100644 --- a/test/ELF/lto/module-asm.ll +++ b/test/ELF/lto/module-asm.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t +; RUN: ld.lld %t.o -o %t ; RUN: llvm-nm %t | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/new-pass-manager.ll b/test/ELF/lto/new-pass-manager.ll new file mode 100644 index 000000000000..918b50500166 --- /dev/null +++ b/test/ELF/lto/new-pass-manager.ll @@ -0,0 +1,14 @@ +; REQUIRES: x86 +; RUN: opt -module-summary %s -o %t.o + +; Test new-pass-manager and debug-pass-manager option +; RUN: ld.lld --plugin-opt=new-pass-manager --plugin-opt=debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s +; RUN: ld.lld --plugin-opt=new-pass-manager --lto-debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s +; RUN: ld.lld --lto-new-pass-manager --plugin-opt=debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s +; RUN: ld.lld --lto-new-pass-manager --lto-debug-pass-manager -o %t2.o %t.o 2>&1 | FileCheck %s + +; CHECK: Starting llvm::Module pass manager run +; CHECK: Finished llvm::Module pass manager run + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/opt-level.ll b/test/ELF/lto/opt-level.ll index 57fa3041ac65..5c4ec43a21a5 100644 --- a/test/ELF/lto/opt-level.ll +++ b/test/ELF/lto/opt-level.ll @@ -1,30 +1,30 @@ ; REQUIRES: x86 ; RUN: llvm-as -o %t.o %s -; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --lto-O0 %t.o +; RUN: ld.lld -o %t0 -e main --lto-O0 %t.o ; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s -; RUN: ld.lld -o %t0 -m elf_x86_64 -e main --plugin-opt=O0 %t.o +; RUN: ld.lld -o %t0 -e main --plugin-opt=O0 %t.o ; RUN: llvm-nm %t0 | FileCheck --check-prefix=CHECK-O0 %s -; RUN: ld.lld -o %t2 -m elf_x86_64 -e main --lto-O2 %t.o +; RUN: ld.lld -o %t2 -e main --lto-O2 %t.o ; RUN: llvm-nm %t2 | FileCheck --check-prefix=CHECK-O2 %s -; RUN: ld.lld -o %t2a -m elf_x86_64 -e main %t.o +; RUN: ld.lld -o %t2a -e main %t.o ; RUN: llvm-nm %t2a | FileCheck --check-prefix=CHECK-O2 %s -; RUN: ld.lld -o %t2 -m elf_x86_64 -e main --plugin-opt=O2 %t.o +; RUN: ld.lld -o %t2 -e main %t.o --plugin-opt O2 ; RUN: llvm-nm %t2 | FileCheck --check-prefix=CHECK-O2 %s ; Reject invalid optimization levels. -; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O6 %t.o 2>&1 | \ +; RUN: not ld.lld -o %t3 -e main --lto-O6 %t.o 2>&1 | \ ; RUN: FileCheck --check-prefix=INVALID1 %s ; INVALID1: invalid optimization level for LTO: 6 -; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=O6 %t.o 2>&1 | \ +; RUN: not ld.lld -o %t3 -e main --plugin-opt=O6 %t.o 2>&1 | \ ; RUN: FileCheck --check-prefix=INVALID1 %s -; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=Ofoo %t.o 2>&1 | \ +; RUN: not ld.lld -o %t3 -e main --plugin-opt=Ofoo %t.o 2>&1 | \ ; RUN: FileCheck --check-prefix=INVALID2 %s -; INVALID2: --plugin-opt: number expected, but got 'foo' +; INVALID2: --plugin-opt=Ofoo: number expected, but got 'foo' -; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \ +; RUN: not ld.lld -o %t3 -e main --lto-O-1 %t.o 2>&1 | \ ; RUN: FileCheck --check-prefix=INVALIDNEGATIVE1 %s ; INVALIDNEGATIVE1: invalid optimization level for LTO: 4294967295 -; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --plugin-opt=O-1 %t.o 2>&1 | \ +; RUN: not ld.lld -o %t3 -e main --plugin-opt=O-1 %t.o 2>&1 | \ ; RUN: FileCheck --check-prefix=INVALIDNEGATIVE2 %s ; INVALIDNEGATIVE2: invalid optimization level for LTO: 4294967295 diff --git a/test/ELF/lto/parallel-internalize.ll b/test/ELF/lto/parallel-internalize.ll index da5bdc6892a8..f21b3ccd29e9 100644 --- a/test/ELF/lto/parallel-internalize.ll +++ b/test/ELF/lto/parallel-internalize.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as -o %t.bc %s ; RUN: rm -f %t.lto.o %t1.lto.o -; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc \ +; RUN: ld.lld --lto-partitions=2 -save-temps -o %t %t.bc \ ; RUN: -e foo --lto-O0 ; RUN: llvm-readobj -t -dyn-symbols %t | FileCheck %s ; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s @@ -18,6 +18,24 @@ ; CHECK-NEXT: Section: Undefined (0x0) ; CHECK-NEXT: } ; CHECK-NEXT: Symbol { +; CHECK-NEXT: Name: {{.*}}.o +; CHECK-NEXT: Value: 0x0 +; CHECK-NEXT: Size: 0 +; CHECK-NEXT: Binding: Local +; CHECK-NEXT: Type: File +; CHECK-NEXT: Other: 0 +; CHECK-NEXT: Section: Absolute +; CHECK-NEXT: } +; CHECK-NEXT: Symbol { +; CHECK-NEXT: Name: {{.*}}.o +; CHECK-NEXT: Value: 0x0 +; CHECK-NEXT: Size: 0 +; CHECK-NEXT: Binding: Local +; CHECK-NEXT: Type: File +; CHECK-NEXT: Other: 0 +; CHECK-NEXT: Section: Absolute +; CHECK-NEXT: } +; CHECK-NEXT: Symbol { ; CHECK-NEXT: Name: bar ; CHECK-NEXT: Value: 0x201010 ; CHECK-NEXT: Size: 8 diff --git a/test/ELF/lto/parallel.ll b/test/ELF/lto/parallel.ll index a1c15af380f0..4ba3fd69d527 100644 --- a/test/ELF/lto/parallel.ll +++ b/test/ELF/lto/parallel.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as -o %t.bc %s ; RUN: rm -f %t.lto.o %t1.lto.o -; RUN: ld.lld -m elf_x86_64 --lto-partitions=2 -save-temps -o %t %t.bc -shared +; RUN: ld.lld --lto-partitions=2 -save-temps -o %t %t.bc -shared ; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s ; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s diff --git a/test/ELF/lto/relax-relocs.ll b/test/ELF/lto/relax-relocs.ll index 8e8d9d165787..80e5dac77d83 100644 --- a/test/ELF/lto/relax-relocs.ll +++ b/test/ELF/lto/relax-relocs.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 -save-temps -shared %t.o -o %t.so +; RUN: ld.lld -save-temps -shared %t.o -o %t.so ; RUN: llvm-readobj -r %t.so.lto.o | FileCheck %s ; Test that we produce R_X86_64_REX_GOTPCRELX instead of R_X86_64_GOTPCREL diff --git a/test/ELF/lto/relocatable.ll b/test/ELF/lto/relocatable.ll index ef21f84a621a..2ec9144a37b0 100644 --- a/test/ELF/lto/relocatable.ll +++ b/test/ELF/lto/relocatable.ll @@ -14,6 +14,15 @@ ; CHECK-NEXT: Section: Undefined ; CHECK-NEXT: } ; CHECK-NEXT: Symbol { +; CHECK-NEXT: Name: {{.*}}.o +; CHECK-NEXT: Value: 0x0 +; CHECK-NEXT: Size: 0 +; CHECK-NEXT: Binding: Local +; CHECK-NEXT: Type: File +; CHECK-NEXT: Other: 0 +; CHECK-NEXT: Section: Absolute +; CHECK-NEXT: } +; CHECK-NEXT: Symbol { ; CHECK-NEXT: Name: ; CHECK-NEXT: Value: 0x0 ; CHECK-NEXT: Size: 0 diff --git a/test/ELF/lto/sample-profile.ll b/test/ELF/lto/sample-profile.ll new file mode 100644 index 000000000000..a8b110444425 --- /dev/null +++ b/test/ELF/lto/sample-profile.ll @@ -0,0 +1,25 @@ +; REQUIRES: x86 +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o + +; RUN: rm -f %t1.lto.o %t2.lto.o +; RUN: ld.lld --lto-sample-profile=%p/Inputs/sample-profile.prof %t1.o %t2.o -o %t3 +; RUN opt -S %t3.lto.o | FileCheck %s + +; RUN: rm -f %t1.lto.o %t2.lto.o +; RUN: ld.lld --plugin-opt=sample-profile=%p/Inputs/sample-profile.prof %t1.o %t2.o -o %t3 +; RUN opt -S %t3.lto.o | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK: ProfileSummary +declare void @g(...) +declare void @h(...) + +define void @f() { +entry: + call void (...) @g() + call void (...) @h() + ret void +} diff --git a/test/ELF/lto/save-temps.ll b/test/ELF/lto/save-temps.ll index c8e52ff4b4ec..b34134cc5d7f 100644 --- a/test/ELF/lto/save-temps.ll +++ b/test/ELF/lto/save-temps.ll @@ -3,7 +3,7 @@ ; 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 -; RUN: ld.lld -shared -m elf_x86_64 %t.o %t2.o -save-temps +; RUN: ld.lld -shared %t.o %t2.o -save-temps ; RUN: llvm-nm a.out | FileCheck %s ; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s ; RUN: llvm-nm a.out.lto.o | FileCheck %s diff --git a/test/ELF/lto/setting-dso-local.ll b/test/ELF/lto/setting-dso-local.ll new file mode 100644 index 000000000000..74ce4e7f16d3 --- /dev/null +++ b/test/ELF/lto/setting-dso-local.ll @@ -0,0 +1,15 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t1.o +; RUN: not ld.lld -o %t %t1.o 2>&1 | FileCheck %s + +; CHECK: undefined symbol: foobar + +; We used to crash setting foobar to non-dso_local + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@foobar = external hidden global i32 +define i32* @_start() { + ret i32* @foobar +} diff --git a/test/ELF/lto/start-lib.ll b/test/ELF/lto/start-lib.ll index ec73954a80ca..024d887a7d0a 100644 --- a/test/ELF/lto/start-lib.ll +++ b/test/ELF/lto/start-lib.ll @@ -4,17 +4,17 @@ ; RUN: llvm-as %p/Inputs/start-lib1.ll -o %t2.o ; RUN: llvm-as %p/Inputs/start-lib2.ll -o %t3.o ; -; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o %t2.o %t3.o +; RUN: ld.lld -shared -o %t3 %t1.o %t2.o %t3.o ; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST1 %s ; TEST1: Name: bar ; TEST1: Name: foo ; -; RUN: ld.lld -m elf_x86_64 -shared -o %t3 -u bar %t1.o --start-lib %t2.o %t3.o +; RUN: ld.lld -shared -o %t3 -u bar %t1.o --start-lib %t2.o %t3.o ; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST2 %s ; TEST2: Name: bar ; TEST2-NOT: Name: foo ; -; RUN: ld.lld -m elf_x86_64 -shared -o %t3 %t1.o --start-lib %t2.o %t3.o +; RUN: ld.lld -shared -o %t3 %t1.o --start-lib %t2.o %t3.o ; RUN: llvm-readobj --symbols %t3 | FileCheck --check-prefix=TEST3 %s ; TEST3-NOT: Name: bar ; TEST3-NOT: Name: foo diff --git a/test/ELF/lto/symbol-ordering-lto.s b/test/ELF/lto/symbol-ordering-lto.s index 4c29e54c476e..530b63c669a4 100644 --- a/test/ELF/lto/symbol-ordering-lto.s +++ b/test/ELF/lto/symbol-ordering-lto.s @@ -8,16 +8,17 @@ # RUN: echo "pat " >> %t_order_lto.txt # RUN: ld.lld --symbol-ordering-file %t_order_lto.txt %t.o %t.bc -o %t2.out -# RUN: llvm-readobj -elf-output-style=GNU -t %t2.out| FileCheck %s +# RUN: llvm-readelf -t %t2.out| FileCheck %s # Check that the order is tin -> _start -> pat. -# CHECK: Symbol table '.symtab' contains 4 entries: +# CHECK: Symbol table '.symtab' contains 5 entries: # CHECK-NEXT: Num: Value Size Type Bind Vis Ndx Name # CHECK-NEXT: 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND -# CHECK-NEXT: 1: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start -# CHECK-NEXT: 2: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat -# CHECK-NEXT: 3: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin +# CHECK-NEXT: 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS {{.*}}.o +# CHECK-NEXT: 2: 0000000000201008 0 NOTYPE GLOBAL DEFAULT 1 _start +# CHECK-NEXT: 3: 0000000000201020 6 FUNC GLOBAL DEFAULT 1 pat +# CHECK-NEXT: 4: 0000000000201000 6 FUNC GLOBAL DEFAULT 1 tin .globl _start _start: diff --git a/test/ELF/lto/thinlto-cant-write-index.ll b/test/ELF/lto/thinlto-cant-write-index.ll new file mode 100644 index 000000000000..94f2a45c2743 --- /dev/null +++ b/test/ELF/lto/thinlto-cant-write-index.ll @@ -0,0 +1,23 @@ +; REQUIRES: x86 + +; Basic ThinLTO tests. +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o + +; Ensure lld generates error if unable to write to index files +; RUN: rm -f %t2.o.thinlto.bc +; RUN: touch %t2.o.thinlto.bc +; RUN: chmod 400 %t2.o.thinlto.bc +; RUN: not ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t3 2>&1 | FileCheck %s +; CHECK: cannot open {{.*}}2.o.thinlto.bc: {{P|p}}ermission denied + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/ELF/lto/thinlto-debug-fission.ll b/test/ELF/lto/thinlto-debug-fission.ll new file mode 100644 index 000000000000..b779ad4a45f6 --- /dev/null +++ b/test/ELF/lto/thinlto-debug-fission.ll @@ -0,0 +1,21 @@ +; REQUIRES: x86 + +; RUN: opt %s -o %t1.o +; RUN: rm -rf %T/dwo + +; Test to ensure that --plugin-opt=dwo_dir=$DIR creates .dwo files under $DIR +; RUN: ld.lld --plugin-opt=dwo_dir=%T/dwo -shared %t1.o -o /dev/null +; RUN: llvm-readobj -h %T/dwo/0.dwo | FileCheck %s + +; CHECK: Format: ELF64-x86-64 + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/ELF/lto/thinlto-emit-imports.ll b/test/ELF/lto/thinlto-emit-imports.ll new file mode 100644 index 000000000000..cae7922682bc --- /dev/null +++ b/test/ELF/lto/thinlto-emit-imports.ll @@ -0,0 +1,55 @@ +; REQUIRES: x86 + +; Generate summary sections and test lld handling. +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o + +; Include a file with an empty module summary index, to ensure that the expected +; output files are created regardless, for a distributed build system. +; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o + +; Ensure lld generates imports files if requested for distributed backends. +; RUN: rm -f %t3.o.imports %t3.o.thinlto.bc +; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4 + +; The imports file for this module contains the bitcode file for +; Inputs/thinlto.ll +; RUN: cat %t1.o.imports | count 1 +; RUN: cat %t1.o.imports | FileCheck %s --check-prefix=IMPORTS1 +; IMPORTS1: thinlto-emit-imports.ll.tmp2.o + +; The imports file for Input/thinlto.ll is empty as it does not import anything. +; RUN: cat %t2.o.imports | count 0 + +; The imports file for Input/thinlto_empty.ll is empty but should exist. +; RUN: cat %t3.o.imports | count 0 + +; The index file should be created even for the input with an empty summary. +; RUN: ls %t3.o.thinlto.bc + +; Ensure lld generates error if unable to write to imports file. +; RUN: rm -f %t3.o.imports +; RUN: touch %t3.o.imports +; RUN: chmod 400 %t3.o.imports +; RUN: not ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4 2>&1 | FileCheck %s --check-prefix=ERR +; ERR: cannot open {{.*}}3.o.imports: {{P|p}}ermission denied + +; Ensure lld doesn't generate import files when thinlto-index-only is not enabled +; RUN: rm -f %t1.o.imports +; RUN: rm -f %t2.o.imports +; RUN: rm -f %t3.o.imports +; RUN: ld.lld --plugin-opt=thinlto-emit-imports-files -shared %t1.o %t2.o %t3.o -o %t4 +; RUN: not ls %t1.o.imports +; RUN: not ls %t2.o.imports +; RUN: not ls %t3.o.imports + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/ELF/lto/thinlto-index-file.ll b/test/ELF/lto/thinlto-index-file.ll new file mode 100644 index 000000000000..91f0b298ca35 --- /dev/null +++ b/test/ELF/lto/thinlto-index-file.ll @@ -0,0 +1,24 @@ +; REQUIRES: x86 + +; Basic ThinLTO tests. +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o +; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o + +; Ensure lld writes linked files to linked objects file +; RUN: ld.lld --plugin-opt=thinlto-index-only=%t.idx -shared %t1.o %t2.o %t3.o -o %t4 +; RUN: FileCheck %s < %t.idx +; CHECK: {{.*}}thinlto-index-file.ll.tmp1.o +; CHECK: {{.*}}thinlto-index-file.ll.tmp2.o +; CHECK: {{.*}}thinlto-index-file.ll.tmp3.o + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/ELF/lto/thinlto-index-only.ll b/test/ELF/lto/thinlto-index-only.ll new file mode 100644 index 000000000000..6263799ee2fd --- /dev/null +++ b/test/ELF/lto/thinlto-index-only.ll @@ -0,0 +1,89 @@ +; REQUIRES: x86 + +; First ensure that the ThinLTO handling in lld handles +; bitcode without summary sections gracefully and generates index file. +; RUN: llvm-as %s -o %t1.o +; RUN: llvm-as %p/Inputs/thinlto.ll -o %t2.o +; RUN: rm -f %t3 +; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t3 +; RUN: ls %t2.o.thinlto.bc +; RUN: not test -e %t3 +; RUN: ld.lld -shared %t1.o %t2.o -o %t3 +; RUN: llvm-nm %t3 | FileCheck %s --check-prefix=NM + +; Basic ThinLTO tests. +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o +; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o + +; Ensure lld generates an index and not a binary if requested. +; RUN: rm -f %t4 +; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t2.o -o %t4 +; RUN: llvm-bcanalyzer -dump %t1.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND1 +; RUN: llvm-bcanalyzer -dump %t2.o.thinlto.bc | FileCheck %s --check-prefix=BACKEND2 +; RUN: not test -e %t4 + +; Ensure lld generates an index even if the file is wrapped in --start-lib/--end-lib +; RUN: rm -f %t2.o.thinlto.bc %t4 +; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o %t3.o --start-lib %t2.o --end-lib -o %t4 +; RUN: ls %t2.o.thinlto.bc +; RUN: not test -e %t4 + +; Test that LLD generates an empty index even for lazy object file that is not added to link. +; Test LLD generates empty imports file either because of thinlto-emit-imports-files option. +; RUN: rm -f %t1.o.thinlto.bc +; RUN: rm -f %t1.o.imports +; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t2.o --start-lib %t1.o --end-lib \ +; RUN: --plugin-opt=thinlto-emit-imports-files -o %t3 +; RUN: ls %t1.o.thinlto.bc +; RUN: ls %t1.o.imports + +; Ensure lld generates an error if unable to write an empty index file +; for lazy object file that is not added to link. +; RUN: rm -f %t1.o.thinlto.bc +; RUN: touch %t1.o.thinlto.bc +; RUN: chmod 400 %t1.o.thinlto.bc +; RUN: not ld.lld --plugin-opt=thinlto-index-only -shared %t2.o --start-lib %t1.o --end-lib \ +; RUN: -o %t3 2>&1 | FileCheck %s +; CHECK: cannot open {{.*}}1.o.thinlto.bc: {{P|p}}ermission denied +; RUN: rm -f %t1.o.thinlto.bc + +; NM: T f + +; The backend index for this module contains summaries from itself and +; Inputs/thinlto.ll, as it imports from the latter. +; BACKEND1: <MODULE_STRTAB_BLOCK +; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.o' +; BACKEND1-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp{{.*}}.o' +; BACKEND1-NEXT: </MODULE_STRTAB_BLOCK +; BACKEND1: <GLOBALVAL_SUMMARY_BLOCK +; BACKEND1: <VERSION +; BACKEND1: <FLAGS +; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}} +; BACKEND1: <VALUE_GUID op0={{1|2}} op1={{-3706093650706652785|-5300342847281564238}} +; BACKEND1: <COMBINED +; BACKEND1: <COMBINED +; BACKEND1: </GLOBALVAL_SUMMARY_BLOCK + +; The backend index for Input/thinlto.ll contains summaries from itself only, +; as it does not import anything. +; BACKEND2: <MODULE_STRTAB_BLOCK +; BACKEND2-NEXT: <ENTRY {{.*}} record string = '{{.*}}thinlto-index-only.ll.tmp2.o' +; BACKEND2-NEXT: </MODULE_STRTAB_BLOCK +; BACKEND2-NEXT: <GLOBALVAL_SUMMARY_BLOCK +; BACKEND2-NEXT: <VERSION +; BACKEND2-NEXT: <FLAGS +; BACKEND2-NEXT: <VALUE_GUID op0=1 op1=-5300342847281564238 +; BACKEND2-NEXT: <COMBINED +; BACKEND2-NEXT: </GLOBALVAL_SUMMARY_BLOCK + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/ELF/lto/thinlto-no-index.ll b/test/ELF/lto/thinlto-no-index.ll new file mode 100644 index 000000000000..f80cf0e63812 --- /dev/null +++ b/test/ELF/lto/thinlto-no-index.ll @@ -0,0 +1,24 @@ +; REQUIRES: x86 + +; Basic ThinLTO tests. +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o +; RUN: opt -module-summary %p/Inputs/thinlto_empty.ll -o %t3.o + +; Ensure lld doesn't generates index files when thinlto-index-only is not enabled +; RUN: rm -f %t1.o.thinlto.bc %t2.o.thinlto.bc %t3.o.thinlto.bc +; RUN: ld.lld -shared %t1.o %t2.o %t3.o -o %t4 +; RUN: not ls %t1.o.thinlto.bc +; RUN: not ls %t2.o.thinlto.bc +; RUN: not ls %t3.o.thinlto.bc + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/ELF/lto/thinlto-obj-path.ll b/test/ELF/lto/thinlto-obj-path.ll new file mode 100644 index 000000000000..bb69bb876a28 --- /dev/null +++ b/test/ELF/lto/thinlto-obj-path.ll @@ -0,0 +1,23 @@ +; REQUIRES: x86 + +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o + +; Test to ensure that thinlto-index-only with obj-path creates the file. +; RUN: rm -f %t4.o +; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=obj-path=%t4.o -shared %t1.o %t2.o -o %t3 +; RUN: llvm-readobj -h %t4.o | FileCheck %s +; RUN: llvm-nm %t4.o | count 0 + +; CHECK: Format: ELF64-x86-64 + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/ELF/lto/thinlto-object-suffix-replace.ll b/test/ELF/lto/thinlto-object-suffix-replace.ll new file mode 100644 index 000000000000..05ce942c70f8 --- /dev/null +++ b/test/ELF/lto/thinlto-object-suffix-replace.ll @@ -0,0 +1,50 @@ +; REQUIRES: x86 + +; Test to make sure the thinlto-object-suffix-replace option is handled +; correctly. + +; Generate bitcode file with summary, as well as a minimized bitcode without +; the debug metadata for the thin link. +; RUN: opt -thinlto-bc %s -thin-link-bitcode-file=%t1.thinlink.bc -o %t1.o + +; First perform the thin link on the normal bitcode file, and save the +; resulting index. +; RUN: ld.lld --plugin-opt=thinlto-index-only -shared %t1.o -o %t3 +; RUN: cp %t1.o.thinlto.bc %t1.o.thinlto.bc.orig + +; Next perform the thin link on the minimized bitcode file, and compare dump +; of the resulting index to the above dump to ensure they are identical. +; RUN: rm -f %t1.o.thinlto.bc +; Make sure it isn't inadvertently using the regular bitcode file. +; RUN: rm -f %t1.o +; RUN: ld.lld --plugin-opt=thinlto-index-only \ +; RUN: --plugin-opt=thinlto-object-suffix-replace=".thinlink.bc;.o" \ +; RUN: -shared %t1.thinlink.bc -o %t3 +; RUN: diff %t1.o.thinlto.bc.orig %t1.o.thinlto.bc + +; Ensure lld generates error if object suffix replace option does not have 'old;new' format +; RUN: rm -f %t1.o.thinlto.bc +; RUN: not ld.lld --plugin-opt=thinlto-index-only \ +; RUN: --plugin-opt=thinlto-object-suffix-replace="abc:def" -shared %t1.thinlink.bc \ +; RUN: -o %t3 2>&1 | FileCheck %s --check-prefix=ERR1 +; ERR1: --plugin-opt=thinlto-object-suffix-replace= expects 'old;new' format, but got abc:def + +; Ensure lld generates error if old suffix doesn't exist in file name +; RUN: rm -f %t1.o +; RUN: not ld.lld --plugin-opt=thinlto-index-only \ +; RUN: --plugin-opt=thinlto-object-suffix-replace=".abc;.o" -shared %t1.thinlink.bc \ +; RUN: -o %t3 2>&1 | FileCheck %s --check-prefix=ERR2 +; ERR2: error: -thinlto-object-suffix-replace=.abc;.o was given, but {{.*}} does not end with the suffix + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f() { +entry: + ret void +} + +!llvm.dbg.cu = !{} + +!1 = !{i32 2, !"Debug Info Version", i32 3} +!llvm.module.flags = !{!1} diff --git a/test/ELF/lto/thinlto-prefix-replace.ll b/test/ELF/lto/thinlto-prefix-replace.ll new file mode 100644 index 000000000000..c276dae7b260 --- /dev/null +++ b/test/ELF/lto/thinlto-prefix-replace.ll @@ -0,0 +1,23 @@ +; REQUIRES: x86 +; Check that changing the output path via thinlto-prefix-replace works +; RUN: mkdir -p %t/oldpath +; RUN: opt -module-summary %s -o %t/oldpath/thinlto_prefix_replace.o + +; Ensure that there is no existing file at the new path, so we properly +; test the creation of the new file there. +; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc +; RUN: ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace="%t/oldpath/;%t/newpath/" -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace +; RUN: ls %t/newpath/thinlto_prefix_replace.o.thinlto.bc + +; Ensure that lld generates error if prefix replace option does not have 'old;new' format +; RUN: rm -f %t/newpath/thinlto_prefix_replace.o.thinlto.bc +; RUN: not ld.lld --plugin-opt=thinlto-index-only --plugin-opt=thinlto-prefix-replace=abc:def -shared %t/oldpath/thinlto_prefix_replace.o -o %t/thinlto_prefix_replace 2>&1 | FileCheck %s --check-prefix=ERR +; ERR: --plugin-opt=thinlto-prefix-replace= expects 'old;new' format, but got abc:def + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define void @f() { +entry: + ret void +} diff --git a/test/ELF/lto/thinlto.ll b/test/ELF/lto/thinlto.ll index 37d2b88131f6..51c82ece5876 100644 --- a/test/ELF/lto/thinlto.ll +++ b/test/ELF/lto/thinlto.ll @@ -1,30 +1,29 @@ ; REQUIRES: x86 + ; Basic ThinLTO tests. -; RUN: opt -module-summary %s -o %t.o +; RUN: opt -module-summary %s -o %t1.o ; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o ; First force single-threaded mode -; RUN: rm -f %t.lto.o %t1.lto.o -; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t.o %t2.o -o %t -; RUN: llvm-nm %t1.lto.o | FileCheck %s --check-prefix=NM1 -; RUN: llvm-nm %t2.lto.o | FileCheck %s --check-prefix=NM2 +; RUN: rm -f %t31.lto.o %t32.lto.o +; RUN: ld.lld -save-temps --thinlto-jobs=1 -shared %t1.o %t2.o -o %t3 +; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2 ; Next force multi-threaded mode -; RUN: rm -f %t2.lto.o %t21.lto.o -; RUN: ld.lld -save-temps --thinlto-jobs=2 -shared %t.o %t2.o -o %t2 -; RUN: llvm-nm %t21.lto.o | FileCheck %s --check-prefix=NM1 -; RUN: llvm-nm %t22.lto.o | FileCheck %s --check-prefix=NM2 +; RUN: rm -f %t31.lto.o %t32.lto.o +; RUN: ld.lld -save-temps --thinlto-jobs=2 -shared %t1.o %t2.o -o %t3 +; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2 -; NM1: T f -; NM1-NOT: U g +; Then check without --thinlto-jobs (which currently default to hardware_concurrency) +; RUN: ld.lld -shared %t1.o %t2.o -o %t3 +; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2 +; NM1: T f ; NM2: T g -; Then check without --thinlto-jobs (which currently default to hardware_concurrency) -; We just check that we don't crash or fail (as it's not sure which tests are -; stable on the final output file itself. -; RUN: ld.lld -shared %t.o %t2.o -o %t2 - target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/timepasses.ll b/test/ELF/lto/timepasses.ll index 5c893e661945..86c9b8ed7951 100644 --- a/test/ELF/lto/timepasses.ll +++ b/test/ELF/lto/timepasses.ll @@ -1,8 +1,7 @@ -; We use lld -flavor gnu because llvm-lit will append --full-shutdown to -; the ld.lld invocation. ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: lld -flavor gnu %t.o -o %t.so -shared -mllvm -time-passes 2>&1 | FileCheck %s +; RUN: env LLD_IN_TEST=0 ld.lld %t.o -o %t.so -shared -mllvm \ +; RUN: -time-passes 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" @@ -11,5 +10,5 @@ define void @patatino() { ret void } -; We should get the output of -time-passes even when --full-shutdown is not specified. +; We should get the output of -time-passes even when full shutdown is not specified. ; CHECK: Total Execution Time diff --git a/test/ELF/lto/tls-mixed.ll b/test/ELF/lto/tls-mixed.ll index 524bb4fb44a3..9d5a69303728 100644 --- a/test/ELF/lto/tls-mixed.ll +++ b/test/ELF/lto/tls-mixed.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-mc %p/Inputs/tls-mixed.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux -; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -shared +; RUN: ld.lld %t1.o %t2.o -o %t.so -shared target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/tls-preserve.ll b/test/ELF/lto/tls-preserve.ll index 8aebcb783f48..c9b7675cd22f 100644 --- a/test/ELF/lto/tls-preserve.ll +++ b/test/ELF/lto/tls-preserve.ll @@ -1,7 +1,7 @@ ; TLS attribute needs to be preserved. ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o -; RUN: ld.lld -shared %t1.o -m elf_x86_64 -o %t1 +; RUN: ld.lld -shared %t1.o -o %t1 ; RUN: llvm-readobj -t %t1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/type-merge.ll b/test/ELF/lto/type-merge.ll index d6f196d7c3ba..985c44b796e1 100644 --- a/test/ELF/lto/type-merge.ll +++ b/test/ELF/lto/type-merge.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %p/Inputs/type-merge.ll -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -shared -save-temps +; RUN: ld.lld %t.o %t2.o -o %t -shared -save-temps ; RUN: llvm-dis < %t.0.0.preopt.bc | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/type-merge2.ll b/test/ELF/lto/type-merge2.ll index 6ebbf778dd8e..5944be7e6c09 100644 --- a/test/ELF/lto/type-merge2.ll +++ b/test/ELF/lto/type-merge2.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %p/Inputs/type-merge2.ll -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t.so -shared -save-temps +; RUN: ld.lld %t.o %t2.o -o %t.so -shared -save-temps ; RUN: llvm-dis %t.so.0.0.preopt.bc -o - | FileCheck %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/undef-weak.ll b/test/ELF/lto/undef-weak.ll index 215978a73df0..e090f5653a09 100644 --- a/test/ELF/lto/undef-weak.ll +++ b/test/ELF/lto/undef-weak.ll @@ -1,13 +1,12 @@ ; REQUIRES: x86 - ; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o ; RUN: rm -f %t.a ; RUN: llvm-ar rcs %t.a %t1.o - ; RUN: llvm-as %s -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t2.o -o %t2.so %t.a -shared +; RUN: ld.lld %t2.o -o %t2.so %t.a -shared ; RUN: llvm-readobj -t %t2.so | FileCheck %s + target triple = "x86_64-unknown-linux-gnu" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/undef.ll b/test/ELF/lto/undef.ll index 41da61052290..4ea7e833df10 100644 --- a/test/ELF/lto/undef.ll +++ b/test/ELF/lto/undef.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -shared +; RUN: ld.lld %t.o -o %t.so -shared ; RUN: llvm-readobj -t %t.so | FileCheck %s target triple = "x86_64-unknown-linux-gnu" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/undefined-puts.ll b/test/ELF/lto/undefined-puts.ll index d13630368de9..6c3dc76be12a 100644 --- a/test/ELF/lto/undefined-puts.ll +++ b/test/ELF/lto/undefined-puts.ll @@ -2,7 +2,7 @@ ; RUN: llvm-mc %p/Inputs/shared.s -o %t1.o -filetype=obj -triple=x86_64-unknown-linux ; RUN: ld.lld %t1.o -o %t1.so -shared ; RUN: llvm-as %s -o %t2.o -; RUN: ld.lld %t1.so %t2.o -m elf_x86_64 -o %t +; RUN: ld.lld %t1.so %t2.o -o %t ; RUN: llvm-readobj -dyn-symbols -dyn-relocations %t | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" diff --git a/test/ELF/lto/unnamed-addr-comdat.ll b/test/ELF/lto/unnamed-addr-comdat.ll index 29a59415851b..38b08ab23ee9 100644 --- a/test/ELF/lto/unnamed-addr-comdat.ll +++ b/test/ELF/lto/unnamed-addr-comdat.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -save-temps -shared +; RUN: ld.lld %t.o %t.o -o %t.so -save-temps -shared ; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/unnamed-addr-drop.ll b/test/ELF/lto/unnamed-addr-drop.ll index e827cbb435e6..ad662b7fe7b6 100644 --- a/test/ELF/lto/unnamed-addr-drop.ll +++ b/test/ELF/lto/unnamed-addr-drop.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-as %S/Inputs/unnamed-addr-drop.ll -o %t2.o -; RUN: ld.lld -m elf_x86_64 %t1.o %t2.o -o %t.so -save-temps -shared +; RUN: ld.lld %t1.o %t2.o -o %t.so -save-temps -shared ; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/unnamed-addr-lib.ll b/test/ELF/lto/unnamed-addr-lib.ll index c2bc6016efd5..0c47468e6b4f 100644 --- a/test/ELF/lto/unnamed-addr-lib.ll +++ b/test/ELF/lto/unnamed-addr-lib.ll @@ -2,7 +2,7 @@ ; RUN: llvm-as %s -o %t.o ; RUN: llvm-mc %p/Inputs/unnamed-addr-lib.s -o %t2.o -filetype=obj -triple=x86_64-pc-linux ; RUN: ld.lld %t2.o -shared -o %t2.so -; RUN: ld.lld -m elf_x86_64 %t.o %t2.so -o %t.so -save-temps -shared +; RUN: ld.lld %t.o %t2.so -o %t.so -save-temps -shared ; RUN: llvm-dis %t.so.0.2.internalize.bc -o - | FileCheck %s ; This documents a small limitation of lld's internalization logic. We decide diff --git a/test/ELF/lto/unnamed-addr.ll b/test/ELF/lto/unnamed-addr.ll index 56fe148b0995..7504fdf6733b 100644 --- a/test/ELF/lto/unnamed-addr.ll +++ b/test/ELF/lto/unnamed-addr.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t.so -save-temps -shared +; RUN: ld.lld %t.o -o %t.so -save-temps -shared ; RUN: llvm-dis %t.so.0.4.opt.bc -o - | FileCheck %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/verify-invalid.ll b/test/ELF/lto/verify-invalid.ll index e6138a3cca62..9fa0f9e0b5f9 100644 --- a/test/ELF/lto/verify-invalid.ll +++ b/test/ELF/lto/verify-invalid.ll @@ -1,10 +1,10 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \ +; RUN: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \ ; RUN: 2>&1 | FileCheck -check-prefix=DEFAULT %s -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \ +; RUN: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \ ; RUN: -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -mllvm -debug-pass=Arguments \ +; RUN: ld.lld %t.o -o %t2 -mllvm -debug-pass=Arguments \ ; RUN: --plugin-opt=disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/version-script.ll b/test/ELF/lto/version-script.ll index c43b443ff749..35a36b5a8d78 100644 --- a/test/ELF/lto/version-script.ll +++ b/test/ELF/lto/version-script.ll @@ -1,7 +1,7 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o ; RUN: echo "VERSION_1.0{ global: foo; local: *; }; VERSION_2.0{ global: bar; local: *; };" > %t.script -; RUN: ld.lld -m elf_x86_64 %t.o -o %t2 -shared --version-script %t.script -save-temps +; RUN: ld.lld %t.o -o %t2 -shared --version-script %t.script -save-temps ; RUN: llvm-dis < %t2.0.0.preopt.bc | FileCheck %s ; RUN: llvm-readobj -V -dyn-symbols %t2 | FileCheck --check-prefix=DSO %s diff --git a/test/ELF/lto/version-script2.ll b/test/ELF/lto/version-script2.ll new file mode 100644 index 000000000000..ab8f75a3eecc --- /dev/null +++ b/test/ELF/lto/version-script2.ll @@ -0,0 +1,15 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.o +; RUN: echo "VER1 {};" > %t.script +; RUN: ld.lld %t.o -o %t.so -shared --version-script %t.script +; RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s + +; test that we have the correct version. +; CHECK: Name: foo@@VER1 ( + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +module asm ".global foo" +module asm "foo:" +module asm ".symver foo,foo@@@VER1" diff --git a/test/ELF/lto/visibility.ll b/test/ELF/lto/visibility.ll index 9acc0e2efaaf..434b61ef294c 100644 --- a/test/ELF/lto/visibility.ll +++ b/test/ELF/lto/visibility.ll @@ -1,7 +1,8 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t1.o ; RUN: llvm-mc -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2.o -filetype=obj -; RUN: ld.lld %t1.o %t2.o -o %t.so -shared +; RUN: ld.lld %t1.o %t2.o -o %t.so -shared -save-temps +; RUN: llvm-dis < %t.so.0.2.internalize.bc | FileCheck --check-prefix=IR %s ; RUN: llvm-readobj -t %t.so | FileCheck %s ; CHECK: Name: g @@ -28,6 +29,8 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" declare hidden void @g() +; IR: declare hidden void @g() + define void @f() { call void @g() ret void diff --git a/test/ELF/lto/weak.ll b/test/ELF/lto/weak.ll index 381ef7a1a347..a807c1325db5 100644 --- a/test/ELF/lto/weak.ll +++ b/test/ELF/lto/weak.ll @@ -1,6 +1,6 @@ ; REQUIRES: x86 ; RUN: llvm-as %s -o %t.o -; RUN: ld.lld -m elf_x86_64 %t.o %t.o -o %t.so -shared +; RUN: ld.lld %t.o %t.o -o %t.so -shared ; RUN: llvm-readobj -t %t.so | FileCheck %s target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/lto/weakodr-visibility.ll b/test/ELF/lto/weakodr-visibility.ll new file mode 100644 index 000000000000..95bd3e4c5a28 --- /dev/null +++ b/test/ELF/lto/weakodr-visibility.ll @@ -0,0 +1,40 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t1.o +; RUN: llvm-as %p/Inputs/weakodr-visibility.ll -o %t2.o + +; Testcase checks we keep desired visibility of weak +; symbol in a library even if select different definition. +; We change the order of input files in command line and +; check that linker selects different symbol definitions, +; but keeps `protected` visibility. + +; RUN: ld.lld %t1.o %t2.o -o %t.so -shared +; RUN: llvm-readobj -t %t.so | FileCheck %s +; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=FIRST +; CHECK: Symbol { +; CHECK: Name: foo +; CHECK-NEXT: Value: +; CHECK-NEXT: Size: +; CHECK-NEXT: Binding: Weak +; CHECK-NEXT: Type: Function +; CHECK-NEXT: Other [ +; CHECK-NEXT: STV_PROTECTED +; CHECK-NEXT: ] +; CHECK-NEXT: Section: +; CHECK-NEXT: } +; FIRST: foo: +; FIRST-NEXT: movl $41, %eax + +; Now swap the files order. +; RUN: ld.lld %t2.o %t1.o -o %t.so -shared +; RUN: llvm-readobj -t %t.so | FileCheck %s +; RUN: llvm-objdump -d %t.so | FileCheck %s --check-prefix=SECOND +; SECOND: foo: +; SECOND-NEXT: movl $42, %eax + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define weak_odr i32 @foo(i8* %this) { + ret i32 41 +} diff --git a/test/ELF/lto/wrap-1.ll b/test/ELF/lto/wrap-1.ll index 83e09493fb5d..b82bece253d1 100644 --- a/test/ELF/lto/wrap-1.ll +++ b/test/ELF/lto/wrap-1.ll @@ -20,8 +20,8 @@ ; Make sure that the 'r' (linker redefined) bit is set for bar and __wrap_bar ; in the resolutions file. ; RESOLS: ,bar,xr -; RESOLS: ,__wrap_bar,px -; RESOLS: ,__real_bar,pxr +; RESOLS: ,__wrap_bar,plx +; RESOLS: ,__real_bar,plxr target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" diff --git a/test/ELF/map-file-i686.s b/test/ELF/map-file-i686.s new file mode 100644 index 000000000000..bab2c4b377e2 --- /dev/null +++ b/test/ELF/map-file-i686.s @@ -0,0 +1,21 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=i386-pc-linux %s -o %t1.o +// RUN: ld.lld %t1.o -o /dev/null -M | FileCheck -strict-whitespace %s + +.global _start +_start: + nop + +// CHECK: VMA LMA Size Align Out In Symbol +// CHECK-NEXT: 11000 11000 1 4 .text +// CHECK-NEXT: 11000 11000 1 4 {{.*}}{{/|\\}}map-file-i686.s.tmp1.o:(.text) +// CHECK-NEXT: 11000 11000 0 1 _start +// CHECK-NEXT: 0 0 8 1 .comment +// CHECK-NEXT: 0 0 8 1 <internal>:(.comment) +// CHECK-NEXT: 0 0 20 4 .symtab +// CHECK-NEXT: 0 0 20 4 <internal>:(.symtab) +// CHECK-NEXT: 0 0 2a 1 .shstrtab +// CHECK-NEXT: 0 0 2a 1 <internal>:(.shstrtab) +// CHECK-NEXT: 0 0 8 1 .strtab +// CHECK-NEXT: 0 0 8 1 <internal>:(.strtab) diff --git a/test/ELF/map-file.s b/test/ELF/map-file.s index d1acabe28126..76e50fb5db04 100644 --- a/test/ELF/map-file.s +++ b/test/ELF/map-file.s @@ -15,16 +15,21 @@ .global _start _start: +.cfi_startproc +.cfi_endproc .quad sharedFoo .quad sharedBar - callq sharedFunc1 - callq sharedFunc2 - call baz + .byte 0xe8 + .long sharedFunc1 - . + .byte 0xe8 + .long sharedFunc2 - . + .byte 0xe8 + .long baz - . .global _Z1fi _Z1fi: .cfi_startproc -.cfi_endproc nop +.cfi_endproc .weak bar bar: .long bar - . @@ -35,58 +40,61 @@ local: abs = 0xAB5 labs = 0x1AB5 -// CHECK: Address Size Align Out In Symbol -// CHECK-NEXT: 00000000002001c8 0000000000000078 8 .dynsym -// CHECK-NEXT: 00000000002001c8 0000000000000078 8 <internal>:(.dynsym) -// CHECK-NEXT: 0000000000200240 000000000000002c 8 .gnu.hash -// CHECK-NEXT: 0000000000200240 000000000000002c 8 <internal>:(.gnu.hash) -// CHECK-NEXT: 000000000020026c 0000000000000030 4 .hash -// CHECK-NEXT: 000000000020026c 0000000000000030 4 <internal>:(.hash) -// CHECK-NEXT: 000000000020029c 0000000000000031 1 .dynstr -// CHECK-NEXT: 000000000020029c 0000000000000031 1 <internal>:(.dynstr) -// CHECK-NEXT: 00000000002002d0 0000000000000030 8 .rela.dyn -// CHECK-NEXT: 00000000002002d0 0000000000000030 8 <internal>:(.rela.dyn) -// CHECK-NEXT: 0000000000200300 0000000000000030 8 .rela.plt -// CHECK-NEXT: 0000000000200300 0000000000000030 8 <internal>:(.rela.plt) -// CHECK-NEXT: 0000000000200330 0000000000000030 8 .eh_frame -// CHECK-NEXT: 0000000000200330 0000000000000030 8 <internal>:(.eh_frame) -// CHECK-NEXT: 0000000000201000 000000000000002d 4 .text -// CHECK-NEXT: 0000000000201000 0000000000000028 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text) -// CHECK-NEXT: 0000000000201000 0000000000000000 0 _start -// CHECK-NEXT: 000000000020101f 0000000000000000 0 f(int) -// CHECK-NEXT: 0000000000201028 0000000000000000 0 local -// CHECK-NEXT: 0000000000201028 0000000000000002 4 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text) -// CHECK-NEXT: 0000000000201028 0000000000000000 0 foo -// CHECK-NEXT: 0000000000201029 0000000000000000 0 bar -// CHECK-NEXT: 000000000020102a 0000000000000000 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text.zed) -// CHECK-NEXT: 000000000020102a 0000000000000000 0 zed -// CHECK-NEXT: 000000000020102c 0000000000000000 4 {{.*}}{{/|\\}}map-file.s.tmp3.o:(.text) -// CHECK-NEXT: 000000000020102c 0000000000000000 0 bah -// CHECK-NEXT: 000000000020102c 0000000000000001 4 {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text) -// CHECK-NEXT: 000000000020102c 0000000000000000 0 baz -// CHECK-NEXT: 0000000000201030 0000000000000030 16 .plt -// CHECK-NEXT: 0000000000201030 0000000000000030 16 <internal>:(.plt) -// CHECK-NEXT: 0000000000201040 0000000000000000 0 sharedFunc1 -// CHECK-NEXT: 0000000000201050 0000000000000000 0 sharedFunc2 -// CHECK-NEXT: 0000000000202000 0000000000000028 8 .got.plt -// CHECK-NEXT: 0000000000202000 0000000000000028 8 <internal>:(.got.plt) -// CHECK-NEXT: 0000000000203000 0000000000000100 8 .dynamic -// CHECK-NEXT: 0000000000203000 0000000000000100 8 <internal>:(.dynamic) -// CHECK-NEXT: 0000000000204000 0000000000000010 16 .bss -// CHECK-NEXT: 0000000000204000 0000000000000004 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON) -// CHECK-NEXT: 0000000000204000 0000000000000004 0 common -// CHECK-NEXT: 0000000000204004 0000000000000004 1 <internal>:(.bss) -// CHECK-NEXT: 0000000000204004 0000000000000004 0 sharedFoo -// CHECK-NEXT: 0000000000204008 0000000000000008 1 <internal>:(.bss) -// CHECK-NEXT: 0000000000204008 0000000000000008 0 sharedBar -// CHECK-NEXT: 0000000000000000 0000000000000008 1 .comment -// CHECK-NEXT: 0000000000000000 0000000000000008 1 <internal>:(.comment) -// CHECK-NEXT: 0000000000000000 0000000000000198 8 .symtab -// CHECK-NEXT: 0000000000000000 0000000000000198 8 <internal>:(.symtab) -// CHECK-NEXT: 0000000000000000 0000000000000084 1 .shstrtab -// CHECK-NEXT: 0000000000000000 0000000000000084 1 <internal>:(.shstrtab) -// CHECK-NEXT: 0000000000000000 000000000000006d 1 .strtab -// CHECK-NEXT: 0000000000000000 000000000000006d 1 <internal>:(.strtab) +// CHECK: VMA LMA Size Align Out In Symbol +// CHECK-NEXT: 2001c8 2001c8 78 8 .dynsym +// CHECK-NEXT: 2001c8 2001c8 78 8 <internal>:(.dynsym) +// CHECK-NEXT: 200240 200240 2c 8 .gnu.hash +// CHECK-NEXT: 200240 200240 2c 8 <internal>:(.gnu.hash) +// CHECK-NEXT: 20026c 20026c 30 4 .hash +// CHECK-NEXT: 20026c 20026c 30 4 <internal>:(.hash) +// CHECK-NEXT: 20029c 20029c 31 1 .dynstr +// CHECK-NEXT: 20029c 20029c 31 1 <internal>:(.dynstr) +// CHECK-NEXT: 2002d0 2002d0 30 8 .rela.dyn +// CHECK-NEXT: 2002d0 2002d0 30 8 <internal>:(.rela.dyn) +// CHECK-NEXT: 200300 200300 30 8 .rela.plt +// CHECK-NEXT: 200300 200300 30 8 <internal>:(.rela.plt) +// CHECK-NEXT: 200330 200330 64 8 .eh_frame +// CHECK-NEXT: 200330 200330 2c 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x0) +// CHECK-NEXT: 200360 200360 14 1 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.eh_frame+0x2c) +// CHECK-NEXT: 200378 200378 18 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.eh_frame+0x18) +// CHECK-NEXT: 201000 201000 2d 4 .text +// CHECK-NEXT: 201000 201000 28 4 {{.*}}{{/|\\}}map-file.s.tmp1.o:(.text) +// CHECK-NEXT: 201000 201000 0 1 _start +// CHECK-NEXT: 20101f 20101f 0 1 f(int) +// CHECK-NEXT: 201028 201028 0 1 local +// CHECK-NEXT: 201028 201028 2 4 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text) +// CHECK-NEXT: 201028 201028 0 1 foo +// CHECK-NEXT: 201029 201029 0 1 bar +// CHECK-NEXT: 20102a 20102a 0 1 {{.*}}{{/|\\}}map-file.s.tmp2.o:(.text.zed) +// CHECK-NEXT: 20102a 20102a 0 1 zed +// CHECK-NEXT: 20102c 20102c 0 4 {{.*}}{{/|\\}}map-file.s.tmp3.o:(.text) +// CHECK-NEXT: 20102c 20102c 0 1 bah +// CHECK-NEXT: 20102c 20102c 1 4 {{.*}}{{/|\\}}map-file.s.tmp4.a(map-file.s.tmp4.o):(.text) +// CHECK-NEXT: 20102c 20102c 0 1 baz +// CHECK-NEXT: 201030 201030 30 16 .plt +// CHECK-NEXT: 201030 201030 30 16 <internal>:(.plt) +// CHECK-NEXT: 201040 201040 0 1 sharedFunc1 +// CHECK-NEXT: 201050 201050 0 1 sharedFunc2 +// CHECK-NEXT: 202000 202000 28 8 .got.plt +// CHECK-NEXT: 202000 202000 28 8 <internal>:(.got.plt) +// CHECK-NEXT: 203000 203000 100 8 .dynamic +// CHECK-NEXT: 203000 203000 100 8 <internal>:(.dynamic) +// CHECK-NEXT: 204000 204000 10 16 .bss +// CHECK-NEXT: 204000 204000 4 16 {{.*}}{{/|\\}}map-file.s.tmp1.o:(COMMON) +// CHECK-NEXT: 204000 204000 4 1 common +// CHECK-NEXT: 204004 204004 4 1 <internal>:(.bss) +// CHECK-NEXT: 204004 204004 4 1 sharedFoo +// CHECK-NEXT: 204008 204008 8 1 <internal>:(.bss) +// CHECK-NEXT: 204008 204008 8 1 sharedBar +// CHECK-NEXT: 0 0 8 1 .comment +// CHECK-NEXT: 0 0 8 1 <internal>:(.comment) +// CHECK-NEXT: 0 0 198 8 .symtab +// CHECK-NEXT: 0 0 198 8 <internal>:(.symtab) +// CHECK-NEXT: 0 0 84 1 .shstrtab +// CHECK-NEXT: 0 0 84 1 <internal>:(.shstrtab) +// CHECK-NEXT: 0 0 6d 1 .strtab +// CHECK-NEXT: 0 0 6d 1 <internal>:(.strtab) + // RUN: not ld.lld %t1.o %t2.o %t3.o %t4.a -o %t -Map=/ 2>&1 \ // RUN: | FileCheck -check-prefix=FAIL %s diff --git a/test/ELF/map-gc-sections.s b/test/ELF/map-gc-sections.s index 717ab819889d..f69edf591f2f 100644 --- a/test/ELF/map-gc-sections.s +++ b/test/ELF/map-gc-sections.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: ld.lld %t.o -o %t -Map=- --gc-sections | FileCheck %s +// RUN: ld.lld %t.o -o /dev/null -Map=- --gc-sections | FileCheck %s .section .tbss,"awT",@nobits // CHECK-NOT: foo diff --git a/test/ELF/merge-gc-piece.s b/test/ELF/merge-gc-piece.s new file mode 100644 index 000000000000..4aec3b2aaed3 --- /dev/null +++ b/test/ELF/merge-gc-piece.s @@ -0,0 +1,38 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.so -shared --gc-sections +# RUN: llvm-readobj -s -section-data %t.so | FileCheck %s + + +# CHECK: Name: .foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x200 + +# CHECK: Name: .bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 01020000 00000000 02020000 00000000 +# CHECK-NEXT: ) + + .section .foo,"aM",@progbits,8 + .quad 42 + .global sym +sym: + .quad 43 + + .section .bar + .quad .foo + 1 + .quad .foo + 2 diff --git a/test/ELF/merge-gc-piece2.s b/test/ELF/merge-gc-piece2.s new file mode 100644 index 000000000000..88e0904caf2e --- /dev/null +++ b/test/ELF/merge-gc-piece2.s @@ -0,0 +1,27 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t.so -shared --gc-sections +# RUN: llvm-readobj -s -section-data %t.so | FileCheck %s + +# CHECK: Name: .bar +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: +# CHECK-NEXT: EntrySize: +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 01000000 00000000 02000000 00000000 +# CHECK-NEXT: ) + + .section .foo,"aM",@progbits,8 + .quad 42 + .quad 43 + + .section .bar + .quad .foo + 1 + .quad .foo + 2 diff --git a/test/ELF/merge-reloc-O0.s b/test/ELF/merge-reloc-O0.s new file mode 100644 index 000000000000..daf5c34b6c0a --- /dev/null +++ b/test/ELF/merge-reloc-O0.s @@ -0,0 +1,48 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -r -o %t2.o -O0 +# RUN: llvm-readobj -s -section-data %t2.o | FileCheck %s + +# We combine just the sections with the same name and sh_entsize. + +# CHECK: Name: .foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 16 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 8 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 41000000 00000000 42000000 00000000 +# CHECK-NEXT: ) + +# CHECK: Name: .foo +# CHECK-NEXT: Type: SHT_PROGBITS +# CHECK-NEXT: Flags [ +# CHECK-NEXT: SHF_ALLOC +# CHECK-NEXT: SHF_MERGE +# CHECK-NEXT: ] +# CHECK-NEXT: Address: +# CHECK-NEXT: Offset: +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: +# CHECK-NEXT: Info: +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 4 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 41000000 42000000 +# CHECK-NEXT: ) + + .section .foo, "aM",@progbits,8,unique,0 + .quad 0x41 + .section .foo, "aM",@progbits,8,unique,1 + .quad 0x42 + .section .foo, "aM",@progbits,4,unique,2 + .long 0x41 + .long 0x42 diff --git a/test/ELF/merge-shared-str.s b/test/ELF/merge-shared-str.s index 2ab03a4d66ab..7502eb93ab36 100644 --- a/test/ELF/merge-shared-str.s +++ b/test/ELF/merge-shared-str.s @@ -19,10 +19,10 @@ // CHECK-NEXT: SHF_MERGE // CHECK-NEXT: SHF_STRINGS // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1C8 +// CHECK-NEXT: Address: 0x228 // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1C9 +// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x229 // CHECK-NEXT: } // CHECK-NEXT: ] diff --git a/test/ELF/merge-shared.s b/test/ELF/merge-shared.s index 4c1d7c06a0ba..6615169f1ecd 100644 --- a/test/ELF/merge-shared.s +++ b/test/ELF/merge-shared.s @@ -17,10 +17,10 @@ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_MERGE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1C8 +// CHECK-NEXT: Address: 0x228 // CHECK: Relocations [ // CHECK-NEXT: Section ({{.*}}) .rela.dyn { -// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x1CA +// CHECK-NEXT: 0x{{.*}} R_X86_64_RELATIVE - 0x22A // CHECK-NEXT: } // CHECK-NEXT: ] diff --git a/test/ELF/merge-string-empty.s b/test/ELF/merge-string-empty.s index 0b82ce700a2c..dc6635c96123 100644 --- a/test/ELF/merge-string-empty.s +++ b/test/ELF/merge-string-empty.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // Ensure that a mergeable string with size 0 does not cause any issue. -// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: ld.lld %t.o -o %t +// RUN: ld.lld %t.o -o /dev/null .globl _start, s .section .rodata.str1.1,"aMS",@progbits,1 diff --git a/test/ELF/merge-string-error.s b/test/ELF/merge-string-error.s index 78895cecca9c..70a361b6ccde 100644 --- a/test/ELF/merge-string-error.s +++ b/test/ELF/merge-string-error.s @@ -1,6 +1,6 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s .section .rodata.str1.1,"aMS",@progbits,1 .asciz "abc" diff --git a/test/ELF/merge-string-no-null.s b/test/ELF/merge-string-no-null.s index fd3f5073810a..ea433fec7d46 100644 --- a/test/ELF/merge-string-no-null.s +++ b/test/ELF/merge-string-no-null.s @@ -1,6 +1,6 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s .section .rodata.str1.1,"aMS",@progbits,1 .ascii "abc" diff --git a/test/ELF/merge-string.s b/test/ELF/merge-string.s index d284d0ab523c..065e8003840a 100644 --- a/test/ELF/merge-string.s +++ b/test/ELF/merge-string.s @@ -28,8 +28,8 @@ zed: // CHECK-NEXT: SHF_MERGE // CHECK-NEXT: SHF_STRINGS // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1C8 -// CHECK-NEXT: Offset: 0x1C8 +// CHECK-NEXT: Address: 0x20D +// CHECK-NEXT: Offset: 0x20D // CHECK-NEXT: Size: 4 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -46,8 +46,8 @@ zed: // NOTAIL-NEXT: SHF_MERGE // NOTAIL-NEXT: SHF_STRINGS // NOTAIL-NEXT: ] -// NOTAIL-NEXT: Address: 0x1C8 -// NOTAIL-NEXT: Offset: 0x1C8 +// NOTAIL-NEXT: Address: 0x20D +// NOTAIL-NEXT: Offset: 0x20D // NOTAIL-NEXT: Size: 7 // NOTAIL-NEXT: Link: 0 // NOTAIL-NEXT: Info: 0 @@ -64,8 +64,8 @@ zed: // NOMERGE-NEXT: SHF_MERGE // NOMERGE-NEXT: SHF_STRINGS // NOMERGE-NEXT: ] -// NOMERGE-NEXT: Address: 0x1C8 -// NOMERGE-NEXT: Offset: 0x1C8 +// NOMERGE-NEXT: Address: 0x20D +// NOMERGE-NEXT: Offset: 0x20D // NOMERGE-NEXT: Size: 11 // NOMERGE-NEXT: Link: 0 // NOMERGE-NEXT: Info: 0 @@ -82,8 +82,8 @@ zed: // CHECK-NEXT: SHF_MERGE // CHECK-NEXT: SHF_STRINGS // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1CC -// CHECK-NEXT: Offset: 0x1CC +// CHECK-NEXT: Address: 0x212 +// CHECK-NEXT: Offset: 0x212 // CHECK-NEXT: Size: 4 // CHECK-NEXT: Link: 0 // CHECK-NEXT: Info: 0 @@ -95,11 +95,11 @@ zed: // CHECK: Name: bar -// CHECK-NEXT: Value: 0x1C9 +// CHECK-NEXT: Value: 0x20E // CHECK: Name: foo -// CHECK-NEXT: Value: 0x1C8 +// CHECK-NEXT: Value: 0x20D // CHECK: Name: zed -// CHECK-NEXT: Value: 0x1CC +// CHECK-NEXT: Value: 0x212 // CHECK-NEXT: Size: 0 diff --git a/test/ELF/merge-sym.s b/test/ELF/merge-sym.s index 4a4e9824a0de..89becc85531c 100644 --- a/test/ELF/merge-sym.s +++ b/test/ELF/merge-sym.s @@ -15,7 +15,7 @@ foo: // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: SHF_MERGE // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1C8 +// CHECK-NEXT: Address: 0x210 // CHECK: Name: foo -// CHECK-NEXT: Value: 0x1CA +// CHECK-NEXT: Value: 0x212 diff --git a/test/ELF/merge-to-non-alloc.s b/test/ELF/merge-to-non-alloc.s new file mode 100644 index 000000000000..86f6f260814b --- /dev/null +++ b/test/ELF/merge-to-non-alloc.s @@ -0,0 +1,33 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t.so -shared +// RUN: llvm-readobj -s -section-data -t %t.so | FileCheck %s + +// CHECK: Name: .bar +// CHECK-NEXT: Type: SHT_PROGBITS +// CHECK-NEXT: Flags [ +// CHECK-NEXT: ] +// CHECK-NEXT: Address: +// CHECK-NEXT: Offset: +// CHECK-NEXT: Size: 16 +// CHECK-NEXT: Link: +// CHECK-NEXT: Info: +// CHECK-NEXT: AddressAlignment: +// CHECK-NEXT: EntrySize: +// CHECK-NEXT: SectionData ( +// CHECK-NEXT: 0000: 10020000 00000000 18020000 00000000 | +// CHECK-NEXT: ) + +// CHECK: Name: foo +// CHECK-NEXT: Value: 0x210 + + .section .foo,"aM",@progbits,4 + .align 4 + .global foo + .hidden foo +foo: + .long 0x42 + + .section .bar + .quad foo + .quad foo + 8 diff --git a/test/ELF/mips-26-mask.s b/test/ELF/mips-26-mask.s index 4cf56cfe338c..874d5c4b2338 100644 --- a/test/ELF/mips-26-mask.s +++ b/test/ELF/mips-26-mask.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check reading/writing implicit addend for R_MIPS_26 relocation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK: __start: # CHECK-NEXT: 20000: 0e 00 80 00 jal 134348800 diff --git a/test/ELF/mips-26-n32-n64.s b/test/ELF/mips-26-n32-n64.s index 2e24873332a7..92f533152da3 100644 --- a/test/ELF/mips-26-n32-n64.s +++ b/test/ELF/mips-26-n32-n64.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_26 relocation handling in case of N64 ABIs. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ @@ -5,9 +6,11 @@ # RUN: ld.lld %t-so.o -shared -o %t.so # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o # RUN: ld.lld %t.o %t.so -o %t.exe -# RUN: llvm-objdump -d %t.exe | FileCheck %s +# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,DEFAULT +# RUN: ld.lld %t-so.o -shared -o %t.so -z hazardplt +# RUN: ld.lld %t.o %t.so -o %t.exe -z hazardplt +# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=CHECK,HAZARDPLT -# REQUIRES: mips # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: @@ -21,11 +24,13 @@ # CHECK-NEXT: 2001c: 03 0e c0 23 subu $24, $24, $14 # CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra # CHECK-NEXT: 20024: 00 18 c0 c2 srl $24, $24, 3 -# CHECK-NEXT: 20028: 03 20 f8 09 jalr $25 +# DEFAULT: 20028: 03 20 f8 09 jalr $25 +# HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25 # CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2 # CHECK-NEXT: 20030: 3c 0f 00 03 lui $15, 3 # CHECK-NEXT: 20034: 8d f9 00 18 lw $25, 24($15) -# CHECK-NEXT: 20038: 03 20 00 08 jr $25 +# DEFAULT: 20038: 03 20 00 08 jr $25 +# HAZARDPLT: 20038: 03 20 04 08 jr.hb $25 # CHECK-NEXT: 2003c: 25 f8 00 18 addiu $24, $15, 24 .text diff --git a/test/ELF/mips-26.s b/test/ELF/mips-26.s index 749920b88c8b..882129b1fa9e 100644 --- a/test/ELF/mips-26.s +++ b/test/ELF/mips-26.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_26 relocation handling. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o @@ -9,8 +10,6 @@ # RUN: llvm-readobj -dynamic-table -s -r -mips-plt-got %t.exe \ # RUN: | FileCheck -check-prefix=REL %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: bar: # CHECK-NEXT: 20000: 0c 00 80 06 jal 131096 <loc> diff --git a/test/ELF/mips-32.s b/test/ELF/mips-32.s index ef97afcc0313..7efcfcd65167 100644 --- a/test/ELF/mips-32.s +++ b/test/ELF/mips-32.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_32 relocation calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o @@ -14,8 +15,6 @@ # RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t-el.so \ # RUN: | FileCheck -check-prefix=REL %s -# REQUIRES: mips - .globl __start __start: nop diff --git a/test/ELF/mips-64-disp.s b/test/ELF/mips-64-disp.s index 29b62dcd050a..5d5049c4cae7 100644 --- a/test/ELF/mips-64-disp.s +++ b/test/ELF/mips-64-disp.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_GOT_DISP relocations against various kind of symbols. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ @@ -8,8 +9,6 @@ # RUN: llvm-objdump -d -t %t.exe | FileCheck %s # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s -# REQUIRES: mips - # CHECK: __start: # CHECK-NEXT: 20000: 24 42 80 40 addiu $2, $2, -32704 # CHECK-NEXT: 20004: 24 42 80 20 addiu $2, $2, -32736 diff --git a/test/ELF/mips-64-got-overflow.s b/test/ELF/mips-64-got-overflow.s new file mode 100644 index 000000000000..5de71b1b366e --- /dev/null +++ b/test/ELF/mips-64-got-overflow.s @@ -0,0 +1,80 @@ +# REQUIRES: mips +# Check the primary GOT cannot be made to overflow + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ +# RUN: %p/Inputs/mips-64-got-load.s -o %t1.so.o +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t2.so.o +# RUN: ld.lld -shared -mips-got-size 32 %t1.so.o %t2.so.o -o %t-sgot.so +# RUN: ld.lld -shared -mips-got-size 24 %t1.so.o %t2.so.o -o %t-mgot.so +# RUN: llvm-readobj -r -dt -mips-plt-got %t-sgot.so | FileCheck -check-prefix=SGOT %s +# RUN: llvm-readobj -r -dt -mips-plt-got %t-mgot.so | FileCheck -check-prefix=MGOT %s + +# SGOT: Primary GOT { +# SGOT-NEXT: Canonical gp value: 0x27FF0 +# SGOT-NEXT: Reserved entries [ +# SGOT-NEXT: Entry { +# SGOT-NEXT: Address: +# SGOT-NEXT: Access: -32752 +# SGOT-NEXT: Initial: 0x0 +# SGOT-NEXT: Purpose: Lazy resolver +# SGOT-NEXT: } +# SGOT-NEXT: Entry { +# SGOT-NEXT: Address: +# SGOT-NEXT: Access: -32744 +# SGOT-NEXT: Initial: 0x80000000 +# SGOT-NEXT: Purpose: Module pointer (GNU extension) +# SGOT-NEXT: } +# SGOT-NEXT: ] +# SGOT-NEXT: Local entries [ +# SGOT-NEXT: Entry { +# SGOT-NEXT: Address: +# SGOT-NEXT: Access: -32736 +# SGOT-NEXT: Initial: 0x20020 +# SGOT-NEXT: } +# SGOT-NEXT: Entry { +# SGOT-NEXT: Address: +# SGOT-NEXT: Access: -32728 +# SGOT-NEXT: Initial: 0x20030 +# SGOT-NEXT: } +# SGOT-NEXT: ] +# SGOT-NEXT: Global entries [ +# SGOT-NEXT: ] +# SGOT-NEXT: Number of TLS and multi-GOT entries: 0 +# SGOT-NEXT: } + +# MGOT: Primary GOT { +# MGOT-NEXT: Canonical gp value: 0x27FF0 +# MGOT-NEXT: Reserved entries [ +# MGOT-NEXT: Entry { +# MGOT-NEXT: Address: +# MGOT-NEXT: Access: -32752 +# MGOT-NEXT: Initial: 0x0 +# MGOT-NEXT: Purpose: Lazy resolver +# MGOT-NEXT: } +# MGOT-NEXT: Entry { +# MGOT-NEXT: Address: +# MGOT-NEXT: Access: -32744 +# MGOT-NEXT: Initial: 0x80000000 +# MGOT-NEXT: Purpose: Module pointer (GNU extension) +# MGOT-NEXT: } +# MGOT-NEXT: ] +# MGOT-NEXT: Local entries [ +# MGOT-NEXT: Entry { +# MGOT-NEXT: Address: +# MGOT-NEXT: Access: -32736 +# MGOT-NEXT: Initial: 0x20020 +# MGOT-NEXT: } +# MGOT-NEXT: ] +# MGOT-NEXT: Global entries [ +# MGOT-NEXT: ] +# MGOT-NEXT: Number of TLS and multi-GOT entries: 1 +# MGOT-NEXT: } + + .text + .global foo2 +foo2: + ld $2, %got_disp(local2)($gp) + + .bss +local2: + .word 0 diff --git a/test/ELF/mips-64-got.s b/test/ELF/mips-64-got.s index f2b4d5b07ab5..e1b1f3475470 100644 --- a/test/ELF/mips-64-got.s +++ b/test/ELF/mips-64-got.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS N64 ABI GOT relocations # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ @@ -8,8 +9,6 @@ # RUN: llvm-objdump -d -t %t.exe | FileCheck %s # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck -check-prefix=GOT %s -# REQUIRES: mips - # CHECK: __start: # CHECK-NEXT: 20000: df 82 80 20 ld $2, -32736($gp) diff --git a/test/ELF/mips-64-gprel-so.s b/test/ELF/mips-64-gprel-so.s index 437238ef5f26..d741dd907137 100644 --- a/test/ELF/mips-64-gprel-so.s +++ b/test/ELF/mips-64-gprel-so.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check setup of GP relative offsets in a function's prologue. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -shared -o %t.so # RUN: llvm-objdump -d -t %t.so | FileCheck %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: foo: # CHECK-NEXT: 10000: 3c 1c 00 01 lui $gp, 1 diff --git a/test/ELF/mips-64-rels.s b/test/ELF/mips-64-rels.s index 78671554b1cb..e641b326ce56 100644 --- a/test/ELF/mips-64-rels.s +++ b/test/ELF/mips-64-rels.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check handling multiple MIPS N64 ABI relocations packed # into the single relocation record. @@ -6,8 +7,6 @@ # RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s # RUN: llvm-readobj -r %t.exe | FileCheck -check-prefix=REL %s -# REQUIRES: mips - # CHECK: __start: # CHECK-NEXT: 20000: 3c 1c 00 01 lui $gp, 1 # ^-- 0x20000 - 0x37ff0 diff --git a/test/ELF/mips-64.s b/test/ELF/mips-64.s index dd8a58d604c5..e37b75c070ec 100644 --- a/test/ELF/mips-64.s +++ b/test/ELF/mips-64.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_64 relocation calculation. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t.o @@ -5,8 +6,6 @@ # RUN: llvm-objdump -t %t.so | FileCheck -check-prefix=SYM %s # RUN: llvm-readobj -r -dynamic-table -mips-plt-got %t.so | FileCheck %s -# REQUIRES: mips - .global __start __start: nop @@ -30,17 +29,16 @@ v2: # SYM: 00020008 g .data 00000008 v2 # CHECK: Relocations [ -# CHECK-NEXT: Section (7) .rela.dyn { -# CHECK-NEXT: 0x20010 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x20000 -# ^-- v1 -# CHECK-NEXT: 0x20008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE v2 0x8 +# CHECK-NEXT: Section (7) .rel.dyn { +# CHECK-NEXT: 0x20010 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x0 +# CHECK-NEXT: 0x20008 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE v2 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK: DynamicSection [ # CHECK: Tag Type Name/Value -# CHECK: 0x0000000000000008 RELASZ 48 (bytes) -# CHECK: 0x0000000000000009 RELAENT 24 (bytes) +# CHECK: 0x0000000000000012 RELSZ 32 (bytes) +# CHECK: 0x0000000000000013 RELENT 16 (bytes) # CHECK: Primary GOT { # CHECK-NEXT: Canonical gp value: diff --git a/test/ELF/mips-abs-got.s b/test/ELF/mips-abs-got.s new file mode 100644 index 000000000000..4964c8558325 --- /dev/null +++ b/test/ELF/mips-abs-got.s @@ -0,0 +1,36 @@ +# REQUIRES: mips + +# Check GOT relocations against absolute symbols. + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -o %t.o %s +# RUN: echo "SECTIONS { \ +# RUN: zero = 0; foo = 0x11004; bar = 0x22000; }" > %t.script +# RUN: ld.lld --script %t.script -o %t.exe %t.o +# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s + +# CHECK: Static GOT { +# CHECK: Local entries [ +# CHECK-NEXT: Entry { +# CHECK-NEXT: Address: +# CHECK-NEXT: Access: -32736 +# CHECK-NEXT: Initial: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Entry { +# CHECK-NEXT: Address: +# CHECK-NEXT: Access: -32728 +# CHECK-NEXT: Initial: 0x10000 +# CHECK-NEXT: } +# CHECK-NEXT: Entry { +# CHECK-NEXT: Address: +# CHECK-NEXT: Access: -32720 +# CHECK-NEXT: Initial: 0x30000 +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } + + .text + nop + .reloc 0, R_MIPS_GOT_PAGE, 0 + ld $v0, %got_page(zero)($gp) + ld $v0, %got_page(foo)($gp) + ld $v0, %got_page(bar+0x10008)($gp) diff --git a/test/ELF/mips-align-err.s b/test/ELF/mips-align-err.s index a3bf134e4386..8bf01dc5c382 100644 --- a/test/ELF/mips-align-err.s +++ b/test/ELF/mips-align-err.s @@ -3,7 +3,7 @@ # RUN: -mcpu=mips32r6 # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ # RUN: -mcpu=mips32r6 %S/Inputs/mips-align-err.s -o %t2.o -# RUN: not ld.lld %t.o %t2.o -o %t.exe 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o %t2.o -o /dev/null 2>&1 | FileCheck %s # CHECK: {{.*}}:(.text+0x1): improper alignment for relocation R_MIPS_PC16: 0xB is not aligned to 4 bytes .globl __start diff --git a/test/ELF/mips-call-hilo.s b/test/ELF/mips-call-hilo.s index 2504612f9e34..9c7633a8464d 100644 --- a/test/ELF/mips-call-hilo.s +++ b/test/ELF/mips-call-hilo.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_CALL_HI16 / R_MIPS_CALL_LO16 relocations calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o @@ -5,8 +6,6 @@ # RUN: llvm-objdump -d %t.so | FileCheck %s # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: foo: # CHECK-NEXT: 10000: 3c 02 00 00 lui $2, 0 diff --git a/test/ELF/mips-call16.s b/test/ELF/mips-call16.s index 4a5d0bf3f871..7b3da0c41ff0 100644 --- a/test/ELF/mips-call16.s +++ b/test/ELF/mips-call16.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_CALL16 relocation calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o @@ -6,8 +7,6 @@ # RUN: llvm-readobj -mips-plt-got -symbols %t.exe \ # RUN: | FileCheck -check-prefix=GOT %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-dynamic.s b/test/ELF/mips-dynamic.s index 15afb028c1f1..ebc2625970cb 100644 --- a/test/ELF/mips-dynamic.s +++ b/test/ELF/mips-dynamic.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS specific .dynamic section entries. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o @@ -6,7 +7,11 @@ # RUN: ld.lld %t.o %td.so -o %t.exe # RUN: llvm-readobj -sections -dynamic-table %t.exe \ -# RUN: | FileCheck -check-prefix=EXE %s +# RUN: | FileCheck -check-prefixes=EXE,NOPIE %s + +# RUN: ld.lld -pie %t.o %td.so -o %t.so +# RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \ +# RUN: | FileCheck -check-prefixes=EXE,PIE %s # RUN: ld.lld %t.o --image-base=0x123000 %td.so -o %t.exe # RUN: llvm-readobj -sections -dynamic-table %t.exe \ @@ -16,8 +21,6 @@ # RUN: llvm-readobj -sections -dyn-symbols -dynamic-table %t.so \ # RUN: | FileCheck -check-prefix=DSO %s -# REQUIRES: mips - # EXE: Sections [ # EXE: Name: .dynamic # EXE-NEXT: Type: SHT_DYNAMIC @@ -44,17 +47,35 @@ # EXE-NEXT: Offset: # EXE-NEXT: Size: 8 # EXE: ] -# EXE: DynamicSection [ -# EXE-NEXT: Tag Type Name/Value -# EXE-DAG: 0x00000003 PLTGOT [[GOTADDR]] -# EXE-DAG: 0x70000001 MIPS_RLD_VERSION 1 -# EXE-DAG: 0x70000005 MIPS_FLAGS NOTPOT -# EXE-DAG: 0x70000006 MIPS_BASE_ADDRESS 0x10000 -# EXE-DAG: 0x7000000A MIPS_LOCAL_GOTNO 2 -# EXE-DAG: 0x70000011 MIPS_SYMTABNO 2 -# EXE-DAG: 0x70000013 MIPS_GOTSYM 0x2 -# EXE-DAG: 0x70000016 MIPS_RLD_MAP [[RLDMAPADDR]] -# EXE: ] + +# PIE: DynamicSection [ +# PIE-NEXT: Tag Type Name/Value +# PIE: 0x00000004 HASH 0x{{[0-9A-F]+}} +# PIE-NEXT: 0x70000001 MIPS_RLD_VERSION 1 +# PIE-NEXT: 0x70000005 MIPS_FLAGS NOTPOT +# PIE-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x0 +# PIE-NEXT: 0x70000011 MIPS_SYMTABNO 2 +# PIE-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2 +# PIE-NEXT: 0x70000013 MIPS_GOTSYM 0x2 +# PIE-NEXT: 0x00000003 PLTGOT [[GOTADDR]] +# PIE-NEXT: 0x70000035 MIPS_RLD_MAP_REL 0x{{[0-9A-F]+}} +# PIE-NEXT: 0x00000000 NULL 0x0 +# PIE-NEXT: ] + +# NOPIE: DynamicSection [ +# NOPIE-NEXT: Tag Type Name/Value +# NOPIE: 0x00000004 HASH 0x{{[0-9A-F]+}} +# NOPIE-NEXT: 0x70000001 MIPS_RLD_VERSION 1 +# NOPIE-NEXT: 0x70000005 MIPS_FLAGS NOTPOT +# NOPIE-NEXT: 0x70000006 MIPS_BASE_ADDRESS 0x10000 +# NOPIE-NEXT: 0x70000011 MIPS_SYMTABNO 2 +# NOPIE-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2 +# NOPIE-NEXT: 0x70000013 MIPS_GOTSYM 0x2 +# NOPIE-NEXT: 0x00000003 PLTGOT [[GOTADDR]] +# NOPIE-NEXT: 0x70000016 MIPS_RLD_MAP [[RLDMAPADDR]] +# NOPIE-NEXT: 0x70000035 MIPS_RLD_MAP_REL 0x{{[0-9A-F]+}} +# NOPIE-NEXT: 0x00000000 NULL 0x0 +# NOPIE-NEXT: ] # IMAGE_BASE: 0x70000006 MIPS_BASE_ADDRESS 0x123000 diff --git a/test/ELF/mips-dynsym-sort.s b/test/ELF/mips-dynsym-sort.s index 7d4559cf9335..d1b935b63cff 100644 --- a/test/ELF/mips-dynsym-sort.s +++ b/test/ELF/mips-dynsym-sort.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check the order of dynamic symbols for the MIPS target. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o @@ -8,8 +9,6 @@ # RUN: ld.lld -shared %t-el.o -o %t-el.so # RUN: llvm-readobj -symbols -dyn-symbols %t-el.so | FileCheck %s -# REQUIRES: mips - .data .globl v1,v2,v3 v1: diff --git a/test/ELF/mips-elf-abi.s b/test/ELF/mips-elf-abi.s new file mode 100644 index 000000000000..86c02f34f6a5 --- /dev/null +++ b/test/ELF/mips-elf-abi.s @@ -0,0 +1,22 @@ +# REQUIRES: mips +# Check EI_ABIVERSION flags + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld -shared -o %t.so %t.o +# RUN: llvm-readobj -h %t.so | FileCheck -check-prefix=DSO %s +# RUN: ld.lld -o %t.exe %t.o +# RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=EXE %s +# RUN: ld.lld -pie -o %t.pie %t.o +# RUN: llvm-readobj -h %t.pie | FileCheck -check-prefix=PIE %s +# RUN: ld.lld -r -o %t.rel %t.o +# RUN: llvm-readobj -h %t.rel | FileCheck -check-prefix=REL %s + +# DSO: ABIVersion: 0 +# EXE: ABIVersion: 1 +# PIE: ABIVersion: 0 +# REL: ABIVersion: 0 + + .global __start + .text +__start: + nop diff --git a/test/ELF/mips-elf-flags-err.s b/test/ELF/mips-elf-flags-err.s index e1ac8c5e015e..caa33ab28c7a 100644 --- a/test/ELF/mips-elf-flags-err.s +++ b/test/ELF/mips-elf-flags-err.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS ELF ISA flag calculation if input files have different ISAs. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -24,14 +25,6 @@ # RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 \ # RUN: | FileCheck -check-prefix=R6OCTEON %s -# Check that lld does not allow to link incompatible floating point ABI. - -# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: -mcpu=mips32 %S/Inputs/mips-dynamic.s -o %t1.o -# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: -mcpu=mips32 -mattr=+fp64 %s -o %t2.o -# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=FPABI %s - # Check that lld take in account EF_MIPS_MACH_XXX ISA flags # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ @@ -41,24 +34,6 @@ # RUN: ld.lld %t1.o %t2.o -o %t.exe # RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=OCTEON %s -# Check that lld does not allow to link incompatible ABIs. - -# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: -target-abi n32 %S/Inputs/mips-dynamic.s -o %t1.o -# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: -target-abi o32 %s -o %t2.o -# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=N32O32 %s - -# Check that lld does not allow to link modules with incompatible NAN flags. - -# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: -mattr=+nan2008 %S/Inputs/mips-dynamic.s -o %t1.o -# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: %s -o %t2.o -# RUN: not ld.lld %t1.o %t2.o -o %t.exe 2>&1 | FileCheck -check-prefix=NAN %s - -# REQUIRES: mips - .option pic0 .text .global __start @@ -79,14 +54,8 @@ __start: # R6OCTEON-NEXT: >>> {{.+}}mips-elf-flags-err.s.tmp1.o: mips64r6 # R6OCTEON-NEXT: >>> {{.+}}mips-elf-flags-err.s.tmp2.o: mips64r2 (octeon) -# FPABI: target floating point ABI '-mdouble-float' is incompatible with '-mgp32 -mfp64': {{.*}}mips-elf-flags-err.s.tmp2.o - # OCTEON: Flags [ # OCTEON-NEXT: EF_MIPS_ARCH_64R2 # OCTEON-NEXT: EF_MIPS_CPIC # OCTEON-NEXT: EF_MIPS_MACH_OCTEON # OCTEON: ] - -# N32O32: error: {{.*}}mips-elf-flags-err.s.tmp2.o is incompatible with {{.*}}mips-elf-flags-err.s.tmp1.o - -# NAN: target -mnan=2008 is incompatible with -mnan=legacy: {{.*}}mips-elf-flags-err.s.tmp2.o diff --git a/test/ELF/mips-elf-flags-err.test b/test/ELF/mips-elf-flags-err.test new file mode 100644 index 000000000000..12fd418274ce --- /dev/null +++ b/test/ELF/mips-elf-flags-err.test @@ -0,0 +1,89 @@ +# REQUIRES: mips +# +# Check warning and errors in case of input +# files with incompatible ELF header flags. + +# RUN: yaml2obj -docnum 1 %s -o %t-n64.o +# RUN: yaml2obj -docnum 2 %s -o %t-o64.o +# RUN: yaml2obj -docnum 3 %s -o %t-n32.o +# RUN: yaml2obj -docnum 4 %s -o %t-o32.o +# RUN: yaml2obj -docnum 5 %s -o %t-eabi64.o +# RUN: yaml2obj -docnum 6 %s -o %t-eabi32.o + +# RUN: not ld.lld %t-n64.o %t-eabi64.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefixes=MM64,N64EABI64 %s +# +# RUN: not ld.lld %t-n64.o %t-o64.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefixes=MM64,N64O64 %s + +# RUN: not ld.lld %t-o32.o %t-eabi32.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefixes=O32EABI32,FP64,CPIC1 %s + +# RUN: not ld.lld %t-eabi32.o %t-o32.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefix=CPIC2 %s + +# MM64: {{.*}}n64.o: microMIPS 64-bit is not supported + +# N64EABI64: {{.*}}eabi64.o: ABI 'eabi64' is incompatible with target ABI 'n64' +# N64O64: {{.*}}o64.o: ABI 'o64' is incompatible with target ABI 'n64' +# O32EABI32: {{.*}}eabi32.o: ABI 'eabi32' is incompatible with target ABI 'o32' + +# NAN: {{.*}}o32.o: -mnan=legacy is incompatible with target -mnan=2008 +# FP64: {{.*}}eabi32.o: -mfp64 is incompatible with target -mfp32 + +# CPIC1: {{.*}}tmp-eabi32.o: linking non-abicalls code with abicalls code {{.*}}o32.o +# CPIC2: {{.*}}tmp-o32.o: linking abicalls code with non-abicalls code {{.*}}eabi32.o + +# n64.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64, EF_MIPS_MICROMIPS ] + +# o64.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ABI_O64, EF_MIPS_ARCH_64 ] + +# n32.o +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64, EF_MIPS_ABI2, EF_MIPS_NAN2008 ] + +# o32.o +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_32, EF_MIPS_ABI_O32, EF_MIPS_CPIC ] + +# eabi64.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64, EF_MIPS_ABI_EABI64 ] + +# eabi32.o +--- !ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_32, EF_MIPS_ABI_EABI32, EF_MIPS_FP64 ] diff --git a/test/ELF/mips-elf-flags.s b/test/ELF/mips-elf-flags.s index d2b3d929e2f5..68f4cc3008e4 100644 --- a/test/ELF/mips-elf-flags.s +++ b/test/ELF/mips-elf-flags.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check generation of MIPS specific ELF header flags. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -41,8 +42,6 @@ # RUN: ld.lld %t.o %t-mm.o -o %t.exe # RUN: llvm-readobj -h -mips-abi-flags %t.exe | FileCheck -check-prefix=MICRO %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-fp-flags-err.test b/test/ELF/mips-fp-flags-err.test new file mode 100644 index 000000000000..68a290c2caa1 --- /dev/null +++ b/test/ELF/mips-fp-flags-err.test @@ -0,0 +1,162 @@ +# REQUIRES: mips +# +# Check warning and errors in case of input +# files with incompatible floating point ABI flags. + +# RUN: yaml2obj -docnum 1 %s -o %t-dbl.o +# RUN: yaml2obj -docnum 2 %s -o %t-sgl.o +# RUN: yaml2obj -docnum 3 %s -o %t-soft.o +# RUN: yaml2obj -docnum 4 %s -o %t-fp64.o +# RUN: yaml2obj -docnum 5 %s -o %t-fp64old.o +# RUN: yaml2obj -docnum 6 %s -o %t-fp64a.o +# RUN: yaml2obj -docnum 7 %s -o %t-fpxx.o + +# RUN: not ld.lld %t-dbl.o %t-fp64.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefixes=DBLFP64 %s + +# RUN: not ld.lld %t-sgl.o %t-fp64old.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefixes=SGLFP64OLD %s + +# RUN: not ld.lld %t-soft.o %t-fp64a.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefixes=SOFTFP64A %s + +# RUN: not ld.lld %t-sgl.o %t-fpxx.o -shared -o /dev/null 2>&1 \ +# RUN: | FileCheck -check-prefixes=SGLFPXX %s + +# DBLFP64: {{.*}}fp64.o: floating point ABI '-mgp32 -mfp64' is incompatible with target floating point ABI '-mdouble-float' +# SGLFP64OLD: {{.*}}fp64old.o: floating point ABI '-mgp32 -mfp64 (old)' is incompatible with target floating point ABI '-msingle-float' +# SOFTFP64A: {{.*}}fp64a.o: floating point ABI '-mgp32 -mfp64 -mno-odd-spreg' is incompatible with target floating point ABI '-msoft-float' +# SGLFPXX: {{.*}}fpxx.o: floating point ABI '-mfpxx' is incompatible with target floating point ABI '-msingle-float' + +# dbl.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64 ] + +Sections: +- Name: .MIPS.abiflags + Type: SHT_MIPS_ABIFLAGS + ISA: MIPS64 + ASEs: [] + FpABI: FP_DOUBLE + GPRSize: REG_64 + CPR1Size: REG_64 + CPR2Size: REG_NONE + +# sgl.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64 ] + +Sections: +- Name: .MIPS.abiflags + Type: SHT_MIPS_ABIFLAGS + ISA: MIPS64 + ASEs: [] + FpABI: FP_SINGLE + GPRSize: REG_64 + CPR1Size: REG_64 + CPR2Size: REG_NONE + +# soft.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64 ] + +Sections: +- Name: .MIPS.abiflags + Type: SHT_MIPS_ABIFLAGS + ISA: MIPS64 + ASEs: [] + FpABI: FP_SOFT + GPRSize: REG_64 + CPR1Size: REG_64 + CPR2Size: REG_NONE + +# fp64.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64 ] + +Sections: +- Name: .MIPS.abiflags + Type: SHT_MIPS_ABIFLAGS + ISA: MIPS64 + ASEs: [] + FpABI: FP_64 + GPRSize: REG_64 + CPR1Size: REG_64 + CPR2Size: REG_NONE + +# fp64old.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64 ] + +Sections: +- Name: .MIPS.abiflags + Type: SHT_MIPS_ABIFLAGS + ISA: MIPS64 + ASEs: [] + FpABI: FP_OLD_64 + GPRSize: REG_64 + CPR1Size: REG_64 + CPR2Size: REG_NONE + +# fp64a.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64 ] + +Sections: +- Name: .MIPS.abiflags + Type: SHT_MIPS_ABIFLAGS + ISA: MIPS64 + ASEs: [] + FpABI: FP_64A + GPRSize: REG_64 + CPR1Size: REG_64 + CPR2Size: REG_NONE + +# fpxx.o +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2MSB + Type: ET_REL + Machine: EM_MIPS + Flags: [ EF_MIPS_ARCH_64 ] + +Sections: +- Name: .MIPS.abiflags + Type: SHT_MIPS_ABIFLAGS + ISA: MIPS64 + ASEs: [] + FpABI: FP_XX + GPRSize: REG_64 + CPR1Size: REG_64 + CPR2Size: REG_NONE diff --git a/test/ELF/mips-gnu-hash.s b/test/ELF/mips-gnu-hash.s index 288d54043fc1..e66bc893a076 100644 --- a/test/ELF/mips-gnu-hash.s +++ b/test/ELF/mips-gnu-hash.s @@ -1,15 +1,14 @@ +# REQUIRES: mips # Shouldn't allow the GNU hash style to be selected with the MIPS target. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o -# RUN: not ld.lld -shared -hash-style=gnu %t-be.o -o %t-be.so 2>&1 | FileCheck %s +# RUN: not ld.lld -shared -hash-style=gnu %t-be.o -o /dev/null 2>&1 | FileCheck %s # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux %s -o %t-el.o -# RUN: not ld.lld -shared -hash-style=gnu %t-el.o -o %t-el.so 2>&1 | FileCheck %s +# RUN: not ld.lld -shared -hash-style=gnu %t-el.o -o /dev/null 2>&1 | FileCheck %s # CHECK: the .gnu.hash section is not compatible with the MIPS target. -# REQUIRES: mips - .globl __start __start: nop diff --git a/test/ELF/mips-got-and-copy.s b/test/ELF/mips-got-and-copy.s index 4e3ca5f2804a..f4640bf30dfa 100644 --- a/test/ELF/mips-got-and-copy.s +++ b/test/ELF/mips-got-and-copy.s @@ -23,13 +23,17 @@ # CHECK-NEXT: Reserved entries [ # CHECK: ] # CHECK-NEXT: Local entries [ +# CHECK-NEXT: ] +# CHECK-NEXT: Global entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: # CHECK-NEXT: Access: -32744 # CHECK-NEXT: Initial: 0x[[DATA0]] +# CHECK-NEXT: Value: 0x[[DATA0]] +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Section: .bss +# CHECK-NEXT: Name: data0@ # CHECK-NEXT: } -# CHECK-NEXT: ] -# CHECK-NEXT: Global entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: # CHECK-NEXT: Access: -32740 diff --git a/test/ELF/mips-got-extsym.s b/test/ELF/mips-got-extsym.s index 3af4ba07b234..ea57d77a0353 100644 --- a/test/ELF/mips-got-extsym.s +++ b/test/ELF/mips-got-extsym.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check creation of GOT entries for global symbols in case of executable # file linking. Symbols defined in DSO should get entries in the global part # of the GOT. Symbols defined in the executable itself should get local GOT @@ -10,8 +11,6 @@ # RUN: ld.lld %t.o %t.so -o %t.exe # RUN: llvm-readobj -dt -t -mips-plt-got %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Symbols [ # CHECK: Symbol { # CHECK: Name: _foo diff --git a/test/ELF/mips-got-hilo.s b/test/ELF/mips-got-hilo.s index fa7e752d9f91..1ae24f3472fe 100644 --- a/test/ELF/mips-got-hilo.s +++ b/test/ELF/mips-got-hilo.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_GOT_HI16 / R_MIPS_GOT_LO16 relocations calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o @@ -5,8 +6,6 @@ # RUN: llvm-objdump -d %t.so | FileCheck %s # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: foo: # CHECK-NEXT: 10000: 3c 02 00 00 lui $2, 0 diff --git a/test/ELF/mips-got-page-script.s b/test/ELF/mips-got-page-script.s index 056e4fda77c2..0ec19fc14ad4 100644 --- a/test/ELF/mips-got-page-script.s +++ b/test/ELF/mips-got-page-script.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check calculation of MIPS GOT page address entries number # when a linker script is provided. @@ -8,8 +9,6 @@ # RUN: ld.lld -shared --script %t.script -o %t.so %t.o # RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s -# REQUIRES: mips - # CHECK: Name: foo1 # CHECK-NEXT: Value: 0x10000 # CHECK: Name: foo2 diff --git a/test/ELF/mips-got-page.s b/test/ELF/mips-got-page.s index e2dc485ba661..46ddf4a7122c 100644 --- a/test/ELF/mips-got-page.s +++ b/test/ELF/mips-got-page.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check the case when small section (less that 0x10000 bytes) occupies # two adjacent 0xffff-bytes pages. We need to create two GOT entries # for R_MIPS_GOT_PAGE relocations. @@ -6,8 +7,6 @@ # RUN: ld.lld --section-start .rodata=0x27FFC -shared -o %t.so %t.o # RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s -# REQUIRES: mips - # CHECK: Name: bar # CHECK-NEXT: Value: 0x28000 # ^ page-address = (0x28000 + 0x8000) & ~0xffff = 0x30000 diff --git a/test/ELF/mips-got-redundant.s b/test/ELF/mips-got-redundant.s index b4c6a2b31a0e..24138ca19995 100644 --- a/test/ELF/mips-got-redundant.s +++ b/test/ELF/mips-got-redundant.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check number of redundant entries in the local part of MIPS GOT. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -shared -o %t.so # RUN: llvm-readobj -mips-plt-got %t.so | FileCheck %s -# REQUIRES: mips - # CHECK: Local entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: diff --git a/test/ELF/mips-got-relocs.s b/test/ELF/mips-got-relocs.s index 5b443e51938a..d085df06524a 100644 --- a/test/ELF/mips-got-relocs.s +++ b/test/ELF/mips-got-relocs.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_GOT16 relocation calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t-be.o @@ -30,8 +31,6 @@ # RUN: llvm-readobj -relocations %t-el.so | FileCheck -check-prefix=NORELOC %s # RUN: llvm-readobj -sections %t-el.so | FileCheck -check-prefix=SHFLAGS %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-got-script.s b/test/ELF/mips-got-script.s index da1858469863..6590c59e1cda 100644 --- a/test/ELF/mips-got-script.s +++ b/test/ELF/mips-got-script.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check number of got entries is adjusted for linker script-added space. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o @@ -5,10 +6,8 @@ # RUN: ld.lld %t.o -shared -o %t.so -T %t.script # RUN: llvm-readobj -mips-plt-got -dynamic-table %t.so | FileCheck %s -# REQUIRES: mips - -# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 5 -# ^-- 2 * header + 3 local entries +# CHECK: 0x7000000A MIPS_LOCAL_GOTNO 4 +# ^-- 2 * header + 2 local entries # CHECK: Local entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: @@ -22,12 +21,6 @@ # CHECK-NEXT: Initial: 0x10000 # ^-- loc2 # CHECK-NEXT: } -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: -# CHECK-NEXT: Access: -32736 -# CHECK-NEXT: Initial: 0x20000 -# ^-- redundant -# CHECK-NEXT: } # CHECK-NEXT: ] .text diff --git a/test/ELF/mips-got-string.s b/test/ELF/mips-got-string.s index 598865c681f6..cfdd0daf68dd 100644 --- a/test/ELF/mips-got-string.s +++ b/test/ELF/mips-got-string.s @@ -1,14 +1,13 @@ +# REQUIRES: mips # Check R_MIPS_GOT16 relocation against merge section. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -o %t.o %s # RUN: ld.lld -shared -o %t.so %t.o # RUN: llvm-readobj -t -mips-plt-got %t.so | FileCheck %s -# REQUIRES: mips - # CHECK: Symbol { # CHECK: Name: $.str -# CHECK-NEXT: Value: 0xF4 +# CHECK-NEXT: Value: 0x1B1 # CHECK: } # CHECK: Local entries [ diff --git a/test/ELF/mips-got-weak.s b/test/ELF/mips-got-weak.s index e860bb482a2c..478e294f02f3 100644 --- a/test/ELF/mips-got-weak.s +++ b/test/ELF/mips-got-weak.s @@ -1,17 +1,16 @@ +# REQUIRES: mips # Check R_MIPS_GOT16 relocation against weak symbols. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -shared -o %t1.so # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t1.so \ -# RUN: | FileCheck -check-prefix=NOSYM %s +# RUN: | FileCheck -check-prefixes=CHECK,NOSYM %s # RUN: ld.lld %t.o -shared -Bsymbolic -o %t2.so # RUN: llvm-readobj -r -dt -dynamic-table -mips-plt-got %t2.so \ -# RUN: | FileCheck -check-prefix=SYM %s - -# REQUIRES: mips +# RUN: | FileCheck -check-prefixes=CHECK,SYM %s -# NOSYM: Relocations [ -# NOSYM-NEXT: ] +# CHECK: Relocations [ +# CHECK-NEXT: ] # NOSYM: Symbol { # NOSYM: Name: foo @@ -22,17 +21,19 @@ # NOSYM-NEXT: Other: 0 # NOSYM-NEXT: Section: .data # NOSYM-NEXT: } -# NOSYM-NEXT: Symbol { -# NOSYM-NEXT: Name: bar -# NOSYM-NEXT: Value: 0x0 -# NOSYM-NEXT: Size: 0 -# NOSYM-NEXT: Binding: Weak -# NOSYM-NEXT: Type: None -# NOSYM-NEXT: Other: 0 -# NOSYM-NEXT: Section: Undefined -# NOSYM-NEXT: } -# NOSYM-NEXT: Symbol { -# NOSYM-NEXT: Name: sym + +# CHECK: Symbol { +# CHECK: Name: bar +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined +# CHECK-NEXT: } + +# NOSYM: Symbol { +# NOSYM: Name: sym # NOSYM-NEXT: Value: 0x20004 # NOSYM-NEXT: Size: 0 # NOSYM-NEXT: Binding: Global @@ -40,30 +41,48 @@ # NOSYM-NEXT: Other: 0 # NOSYM-NEXT: Section: .data # NOSYM-NEXT: } -# NOSYM-NEXT: ] -# NOSYM: 0x70000011 MIPS_SYMTABNO 4 -# NOSYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 2 -# NOSYM-NEXT: 0x70000013 MIPS_GOTSYM 0x1 +# CHECK: 0x70000011 MIPS_SYMTABNO 4 -# NOSYM: Primary GOT { -# NOSYM-NEXT: Canonical gp value: -# NOSYM-NEXT: Reserved entries [ -# NOSYM-NEXT: Entry { -# NOSYM-NEXT: Address: -# NOSYM-NEXT: Access: -32752 -# NOSYM-NEXT: Initial: 0x0 -# NOSYM-NEXT: Purpose: Lazy resolver -# NOSYM-NEXT: } -# NOSYM-NEXT: Entry { -# NOSYM-NEXT: Address: -# NOSYM-NEXT: Access: -32748 -# NOSYM-NEXT: Initial: 0x80000000 -# NOSYM-NEXT: Purpose: Module pointer (GNU extension) -# NOSYM-NEXT: } -# NOSYM-NEXT: ] -# NOSYM-NEXT: Local entries [ +# SYM: 0x7000000A MIPS_LOCAL_GOTNO 4 +# SYM: 0x70000013 MIPS_GOTSYM 0x3 + +# NOSYM: 0x7000000A MIPS_LOCAL_GOTNO 2 +# NOSYM: 0x70000013 MIPS_GOTSYM 0x1 + +# CHECK: Primary GOT { +# CHECK-NEXT: Canonical gp value: +# CHECK-NEXT: Reserved entries [ +# CHECK: ] + +# SYM: Local entries [ +# SYM-NEXT: Entry { +# SYM-NEXT: Address: +# SYM-NEXT: Access: -32744 +# SYM-NEXT: Initial: 0x20000 +# SYM-NEXT: } +# SYM-NEXT: Entry { +# SYM-NEXT: Address: +# SYM-NEXT: Access: -32740 +# SYM-NEXT: Initial: 0x20004 +# SYM-NEXT: } +# SYM-NEXT: ] + +# NOSYM: Local entries [ # NOSYM-NEXT: ] + +# SYM-NEXT: Global entries [ +# SYM-NEXT: Entry { +# SYM-NEXT: Address: +# SYM-NEXT: Access: -32736 +# SYM-NEXT: Initial: 0x0 +# SYM-NEXT: Value: 0x0 +# SYM-NEXT: Type: None +# SYM-NEXT: Section: Undefined +# SYM-NEXT: Name: bar +# SYM-NEXT: } +# SYM-NEXT: ] + # NOSYM-NEXT: Global entries [ # NOSYM-NEXT: Entry { # NOSYM-NEXT: Address: @@ -93,68 +112,9 @@ # NOSYM-NEXT: Name: sym # NOSYM-NEXT: } # NOSYM-NEXT: ] -# NOSYM-NEXT: Number of TLS and multi-GOT entries: 0 -# NOSYM-NEXT: } - -# SYM: Relocations [ -# SYM-NEXT: ] - -# SYM: Symbol { -# SYM: Name: bar -# SYM-NEXT: Value: 0x0 -# SYM-NEXT: Size: 0 -# SYM-NEXT: Binding: Weak -# SYM-NEXT: Type: None -# SYM-NEXT: Other: 0 -# SYM-NEXT: Section: Undefined -# SYM-NEXT: } -# SYM-NEXT: ] - -# SYM: 0x70000011 MIPS_SYMTABNO 4 -# SYM-NEXT: 0x7000000A MIPS_LOCAL_GOTNO 4 -# SYM-NEXT: 0x70000013 MIPS_GOTSYM 0x3 - -# SYM: Primary GOT { -# SYM-NEXT: Canonical gp value: -# SYM-NEXT: Reserved entries [ -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32752 -# SYM-NEXT: Initial: 0x0 -# SYM-NEXT: Purpose: Lazy resolver -# SYM-NEXT: } -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32748 -# SYM-NEXT: Initial: 0x80000000 -# SYM-NEXT: Purpose: Module pointer (GNU extension) -# SYM-NEXT: } -# SYM-NEXT: ] -# SYM-NEXT: Local entries [ -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32744 -# SYM-NEXT: Initial: 0x20000 -# SYM-NEXT: } -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32740 -# SYM-NEXT: Initial: 0x20004 -# SYM-NEXT: } -# SYM-NEXT: ] -# SYM-NEXT: Global entries [ -# SYM-NEXT: Entry { -# SYM-NEXT: Address: -# SYM-NEXT: Access: -32736 -# SYM-NEXT: Initial: 0x0 -# SYM-NEXT: Value: 0x0 -# SYM-NEXT: Type: None -# SYM-NEXT: Section: Undefined -# SYM-NEXT: Name: bar -# SYM-NEXT: } -# SYM-NEXT: ] -# SYM-NEXT: Number of TLS and multi-GOT entries: 0 -# SYM-NEXT: } + +# CHECK: Number of TLS and multi-GOT entries: 0 +# CHECK-NEXT: } .text .global sym diff --git a/test/ELF/mips-got16-relocatable.s b/test/ELF/mips-got16-relocatable.s index bbacfdbaa682..04b7cbb8e904 100644 --- a/test/ELF/mips-got16-relocatable.s +++ b/test/ELF/mips-got16-relocatable.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check writing updated addend for R_MIPS_GOT16 relocation, # when produce a relocatable output. @@ -7,8 +8,6 @@ # RUN: ld.lld -shared -o %t.so %t # RUN: llvm-objdump -d %t.so | FileCheck -check-prefix=SO %s -# REQUIRES: mips - # OBJ: Disassembly of section .text: # OBJ-NEXT: .text: # OBJ-NEXT: 0: 8f 99 00 00 lw $25, 0($gp) diff --git a/test/ELF/mips-got16.s b/test/ELF/mips-got16.s index 6ad7b2b0d46e..cf0847da53d3 100644 --- a/test/ELF/mips-got16.s +++ b/test/ELF/mips-got16.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_GOT16 relocation calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o @@ -5,8 +6,6 @@ # RUN: llvm-objdump -d -t %t.so | FileCheck %s # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: # CHECK-NEXT: 10000: 8f 88 80 18 lw $8, -32744($gp) diff --git a/test/ELF/mips-gp-disp-ver.s b/test/ELF/mips-gp-disp-ver.s new file mode 100644 index 000000000000..8eaee19daf19 --- /dev/null +++ b/test/ELF/mips-gp-disp-ver.s @@ -0,0 +1,14 @@ +# REQUIRES: mips +# MIPS BFD linker puts _gp_disp symbol into DSO files and assigns zero +# version definition index to it. This value means 'unversioned local symbol' +# while _gp_disp is a section global symbol. We have to handle this bug +# in the LLD because BFD linker is used for building MIPS toolchain +# libraries. This test checks such handling. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o %S/Inputs/mips-gp-dips-corrupt-ver.so + + .global __start + .text +__start: + lw $t0, %got(foo)($gp) diff --git a/test/ELF/mips-gp-disp.s b/test/ELF/mips-gp-disp.s index 7a0fd6409d18..1b4226d6022b 100644 --- a/test/ELF/mips-gp-disp.s +++ b/test/ELF/mips-gp-disp.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check that even if _gp_disp symbol is defined in the shared library # we use our own value. @@ -9,8 +10,6 @@ # RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=DIS %s # RUN: llvm-readobj -relocations %t.so | FileCheck -check-prefix=REL %s -# REQUIRES: mips - # INT-SO: Name: _gp_disp # INT-SO-NEXT: Value: # INT-SO-NEXT: Size: diff --git a/test/ELF/mips-gp-ext.s b/test/ELF/mips-gp-ext.s index 2fd21b7a9818..9f12f1313166 100644 --- a/test/ELF/mips-gp-ext.s +++ b/test/ELF/mips-gp-ext.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check that the linker use a value of _gp symbol defined # in a linker script to calculate GOT relocations. @@ -24,45 +25,45 @@ # RUN: ld.lld -shared -o %t.abs.so --script %t.abs.script %t.o # RUN: llvm-objdump -s -t %t.abs.so | FileCheck --check-prefix=ABS %s -# REQUIRES: mips +# REL: Contents of section .reginfo: +# REL-NEXT: 0018 10000104 00000000 00000000 00000000 +# REL-NEXT: 0028 00000000 000001ec +# ^-- _gp # REL: Contents of section .text: -# REL-NEXT: 0000 3c080000 2108010c 8f82fffc +# REL-NEXT: 00e0 3c080000 2108010c 8f82ff1c # ^-- %hi(_gp_disp) # ^-- %lo(_gp_disp) -# ^-- 8 - (0x10c - 0x100) +# ^-- 8 - (0x1ec - 0x100) # G - (GP - .got) -# REL: Contents of section .reginfo: -# REL-NEXT: 0028 10000104 00000000 00000000 00000000 -# REL-NEXT: 0038 00000000 0000010c -# ^-- _gp - # REL: Contents of section .data: # REL-NEXT: 00f0 fffffef4 -# ^-- 0-0x10c +# ^-- 0x30-0x1ec +# foo - GP -# REL: 00000000 .text 00000000 foo +# REL: 000000e0 .text 00000000 foo # REL: 00000000 *ABS* 00000000 .hidden _gp_disp -# REL: 0000010c *ABS* 00000000 .hidden _gp +# REL: 000001ec *ABS* 00000000 .hidden _gp + +# ABS: Contents of section .reginfo: +# ABS-NEXT: 0018 10000104 00000000 00000000 00000000 +# ABS-NEXT: 0028 00000000 00000200 +# ^-- _gp # ABS: Contents of section .text: -# ABS-NEXT: 0000 3c080000 21080200 8f82ff08 +# ABS-NEXT: 00e0 3c080000 21080120 8f82ff08 # ^-- %hi(_gp_disp) # ^-- %lo(_gp_disp) # ^-- 8 - (0x200 - 0x100) # G - (GP - .got) -# ABS: Contents of section .reginfo: -# ABS-NEXT: 0028 10000104 00000000 00000000 00000000 -# ABS-NEXT: 0038 00000000 00000200 -# ^-- _gp - # ABS: Contents of section .data: -# ABS-NEXT: 00f0 fffffe00 -# ^-- 0-0x200 +# ABS-NEXT: 00f0 fffffee0 +# ^-- 0xe0-0x200 +# foo - GP -# ABS: 00000000 .text 00000000 foo +# ABS: 000000e0 .text 00000000 foo # ABS: 00000000 *ABS* 00000000 .hidden _gp_disp # ABS: 00000200 *ABS* 00000000 .hidden _gp diff --git a/test/ELF/mips-gp-local.s b/test/ELF/mips-gp-local.s index 8bb3c236edf0..1146af8ff751 100644 --- a/test/ELF/mips-gp-local.s +++ b/test/ELF/mips-gp-local.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check handling of relocations against __gnu_local_gp symbol. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld -o %t.exe %t.o # RUN: llvm-objdump -d -t %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: # CHECK-NEXT: 20000: 3c 08 00 03 lui $8, 3 diff --git a/test/ELF/mips-gp-lowest.s b/test/ELF/mips-gp-lowest.s index 32a3e85ee9ec..46da50334f5a 100644 --- a/test/ELF/mips-gp-lowest.s +++ b/test/ELF/mips-gp-lowest.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check that default _gp value is calculated relative # to the GP-relative section with the lowest address. @@ -8,8 +9,6 @@ # RUN: ld.lld %t.o --script %t.rel.script -shared -o %t.so # RUN: llvm-readobj -s -t %t.so | FileCheck %s -# REQUIRES: mips - .text .global foo foo: @@ -26,7 +25,7 @@ foo: # CHECK-NEXT: SHF_MIPS_GPREL # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] -# CHECK-NEXT: Address: 0xE0 +# CHECK-NEXT: Address: 0xF0 # CHECK: } # CHECK: Section { # CHECK: Name: .got @@ -36,9 +35,9 @@ foo: # CHECK-NEXT: SHF_MIPS_GPREL # CHECK-NEXT: SHF_WRITE # CHECK-NEXT: ] -# CHECK-NEXT: Address: 0xF0 +# CHECK-NEXT: Address: 0x100 # CHECK: } # CHECK: Name: _gp (5) -# CHECK-NEXT: Value: 0x80D0 -# ^-- 0xE0 + 0x7ff0 +# CHECK-NEXT: Value: 0x80E0 +# ^-- 0xF0 + 0x7ff0 diff --git a/test/ELF/mips-gprel-sec.s b/test/ELF/mips-gprel-sec.s index dc54f87216da..7517983895b8 100644 --- a/test/ELF/mips-gprel-sec.s +++ b/test/ELF/mips-gprel-sec.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check order of gp-relative sections, i.e. sections with SHF_MIPS_GPREL flag. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -shared -o %t.so # RUN: llvm-readobj -s %t.so | FileCheck %s -# REQUIRES: mips - .text nop diff --git a/test/ELF/mips-gprel32-relocs-gp0.s b/test/ELF/mips-gprel32-relocs-gp0.s index 507224e05d15..1abdeec1b11a 100644 --- a/test/ELF/mips-gprel32-relocs-gp0.s +++ b/test/ELF/mips-gprel32-relocs-gp0.s @@ -1,8 +1,5 @@ +# REQUIRES: mips # Check that relocatable object produced by LLD has zero gp0 value. -# Also check an error message if input object file has non-zero gp0 value -# and the linker generates a relocatable object. -# mips-gp0-non-zero.o is a relocatable object produced from the asm code -# below and linked by GNU bfd linker. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld -r -o %t-rel.o %t.o @@ -12,11 +9,6 @@ # RUN: llvm-readobj -mips-reginfo %t.so | FileCheck --check-prefix=DSO %s # RUN: llvm-objdump -s -t %t.so | FileCheck --check-prefix=DUMP %s -# RUN: not ld.lld -r -o %t-rel.o %S/Inputs/mips-gp0-non-zero.o 2>&1 \ -# RUN: | FileCheck --check-prefix=ERR %s - -# REQUIRES: mips - # REL: GP: 0x0 # DSO: GP: 0x27FF0 @@ -31,8 +23,6 @@ # DUMP: 00010004 .text 00000000 foo # DUMP: 00027ff0 .got 00000000 .hidden _gp -# ERR: error: {{.*}}mips-gp0-non-zero.o: unsupported non-zero ri_gp_value - .text .global __start __start: diff --git a/test/ELF/mips-gprel32-relocs.s b/test/ELF/mips-gprel32-relocs.s index 047165f19ae4..8f31aa87411d 100644 --- a/test/ELF/mips-gprel32-relocs.s +++ b/test/ELF/mips-gprel32-relocs.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check R_MIPS_GPREL32 relocation calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld -shared -o %t.so %t.o # RUN: llvm-objdump -s -section=.rodata -t %t.so | FileCheck %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-higher-highest.s b/test/ELF/mips-higher-highest.s index 123b51a65add..3af7dcb4b527 100644 --- a/test/ELF/mips-higher-highest.s +++ b/test/ELF/mips-higher-highest.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_HIGHER / R_MIPS_HIGHEST relocations calculation. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o @@ -6,8 +7,6 @@ # RUN: ld.lld %t1.o %t2.o -o %t.exe # RUN: llvm-objdump -d %t.exe | FileCheck %s -# REQUIRES: mips - .global __start __start: lui $6, %highest(_foo+0x300047FFF7FF7) diff --git a/test/ELF/mips-hilo-gp-disp.s b/test/ELF/mips-hilo-gp-disp.s index c7229ee0da25..997074efff16 100644 --- a/test/ELF/mips-hilo-gp-disp.s +++ b/test/ELF/mips-hilo-gp-disp.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_HI16 / LO16 relocations calculation against _gp_disp. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o @@ -8,8 +9,6 @@ # RUN: ld.lld %t1.o %t2.o -shared -o %t.so # RUN: llvm-objdump -d -t %t.so | FileCheck -check-prefix=SO %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-hilo-hi-only.s b/test/ELF/mips-hilo-hi-only.s index 0858e3f6cd17..6fd4c683fd91 100644 --- a/test/ELF/mips-hilo-hi-only.s +++ b/test/ELF/mips-hilo-hi-only.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check warning on orphaned R_MIPS_HI16 relocations. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t.exe 2>&1 | FileCheck -check-prefix=WARN %s # RUN: llvm-objdump -d -t %t.exe | FileCheck %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-hilo.s b/test/ELF/mips-hilo.s index d5de9422c427..a00ffaa9fb1c 100644 --- a/test/ELF/mips-hilo.s +++ b/test/ELF/mips-hilo.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check R_MIPS_HI16 / LO16 relocations calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld %t.o -o %t.exe # RUN: llvm-objdump -d -t %t.exe | FileCheck %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-lo16-not-relative.s b/test/ELF/mips-lo16-not-relative.s index 614e6396cc92..2af1eead8847 100644 --- a/test/ELF/mips-lo16-not-relative.s +++ b/test/ELF/mips-lo16-not-relative.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check that R_MIPS_LO16 relocation is handled as non-relative, # and if a target symbol is a DSO data symbol, LLD create a copy # relocation. @@ -9,8 +10,6 @@ # RUN: ld.lld %t.o %t.so -o %t.exe # RUN: llvm-readobj -r %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Relocations [ # CHECK-NEXT: Section (7) .rel.dyn { # CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0 diff --git a/test/ELF/mips-merge-abiflags.s b/test/ELF/mips-merge-abiflags.s index 2e8b43bcc3b8..d061c1b022bd 100644 --- a/test/ELF/mips-merge-abiflags.s +++ b/test/ELF/mips-merge-abiflags.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Test that lld handles input files with concatenated .MIPS.abiflags sections # This happens e.g. with the FreeBSD BFD (BFD 2.17.50 [FreeBSD] 2007-07-03) @@ -8,7 +9,6 @@ # RUN: %p/Inputs/mips-concatenated-abiflags.o | \ # RUN: FileCheck --check-prefix=INPUT-OBJECT %s -# REQUIRES: mips .globl __start __start: nop diff --git a/test/ELF/mips-mgot.s b/test/ELF/mips-mgot.s new file mode 100644 index 000000000000..0bb1a76ea8f5 --- /dev/null +++ b/test/ELF/mips-mgot.s @@ -0,0 +1,117 @@ +# REQUIRES: mips +# Check MIPS multi-GOT layout. + +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t0.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-mgot-1.s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: %p/Inputs/mips-mgot-2.s -o %t2.o +# RUN: ld.lld -shared -mips-got-size 52 %t0.o %t1.o %t2.o -o %t.so +# RUN: llvm-objdump -s -section=.got -t %t.so | FileCheck %s +# RUN: llvm-readobj -r -dt -mips-plt-got %t.so | FileCheck -check-prefix=GOT %s + +# CHECK: Contents of section .got: +# CHECK-NEXT: 60000 00000000 80000000 00010000 00010030 +# CHECK-NEXT: 60010 00000000 00000004 00020000 00030000 +# CHECK-NEXT: 60020 00040000 00050000 00060000 00070000 +# CHECK-NEXT: 60030 00000000 00000000 00000000 00000000 +# CHECK-NEXT: 60040 00000000 00000000 00000000 + +# CHECK: SYMBOL TABLE: +# CHECK: 00000000 l .tdata 00000000 loc0 +# CHECK: 00010000 .text 00000000 foo0 +# CHECK: 00000000 g .tdata 00000000 tls0 +# CHECK: 00010020 .text 00000000 foo1 +# CHECK: 00000004 g .tdata 00000000 tls1 +# CHECK: 00010030 .text 00000000 foo2 +# CHECK: 00000008 g .tdata 00000000 tls2 + +# GOT: Relocations [ +# GOT-NEXT: Section (7) .rel.dyn { +# GOT-NEXT: 0x60018 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x6001C R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60020 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60024 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60028 R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x6002C R_MIPS_REL32 - 0x0 +# GOT-NEXT: 0x60030 R_MIPS_REL32 foo0 0x0 +# GOT-NEXT: 0x60034 R_MIPS_REL32 foo2 0x0 +# GOT-NEXT: 0x60044 R_MIPS_TLS_DTPMOD32 - 0x0 +# GOT-NEXT: 0x60010 R_MIPS_TLS_TPREL32 tls0 0x0 +# GOT-NEXT: 0x60038 R_MIPS_TLS_TPREL32 tls0 0x0 +# GOT-NEXT: 0x6003C R_MIPS_TLS_DTPMOD32 tls0 0x0 +# GOT-NEXT: 0x60040 R_MIPS_TLS_DTPREL32 tls0 0x0 +# GOT-NEXT: 0x60014 R_MIPS_TLS_TPREL32 tls1 0x0 +# GOT-NEXT: } +# GOT-NEXT: ] + +# GOT: DynamicSymbols [ +# GOT: Symbol { +# GOT: Name: foo0 +# GOT-NEXT: Value: 0x10000 +# GOT: } +# GOT-NEXT: Symbol { +# GOT-NEXT: Name: foo2 +# GOT-NEXT: Value: 0x10030 +# GOT: } +# GOT-NEXT: ] + +# GOT: Primary GOT { +# GOT-NEXT: Canonical gp value: 0x67FF0 +# GOT-NEXT: Reserved entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32752 +# GOT-NEXT: Initial: 0x0 +# GOT-NEXT: Purpose: Lazy resolver +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32748 +# GOT-NEXT: Initial: 0x80000000 +# GOT-NEXT: Purpose: Module pointer (GNU extension) +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Local entries [ +# GOT-NEXT: ] +# GOT-NEXT: Global entries [ +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32744 +# GOT-NEXT: Initial: 0x10000 +# GOT-NEXT: Value: 0x10000 +# GOT-NEXT: Type: None +# GOT-NEXT: Section: .text +# GOT-NEXT: Name: foo0 +# GOT-NEXT: } +# GOT-NEXT: Entry { +# GOT-NEXT: Address: +# GOT-NEXT: Access: -32740 +# GOT-NEXT: Initial: 0x10030 +# GOT-NEXT: Value: 0x10030 +# GOT-NEXT: Type: None +# GOT-NEXT: Section: .text +# GOT-NEXT: Name: foo2 +# GOT-NEXT: } +# GOT-NEXT: ] +# GOT-NEXT: Number of TLS and multi-GOT entries: 15 +# GOT-NEXT: } + + .text + .global foo0 +foo0: + lw $2, %got(.data)($gp) # page entry + addi $2, $2, %lo(.data) + lw $2, %call16(foo0)($gp) # global entry + addiu $2, $2, %tlsgd(tls0) # tls gd entry + addiu $2, $2, %gottprel(tls0) # tls got entry + addiu $2, $2, %tlsldm(loc0) # tls ld entry + + .data + .space 0x20000 + + .section .tdata,"awT",%progbits + .global tls0 +tls0: +loc0: + .word 0 diff --git a/test/ELF/mips-micro-got.s b/test/ELF/mips-micro-got.s index 8d077f2800f1..a881e0ae5fcb 100644 --- a/test/ELF/mips-micro-got.s +++ b/test/ELF/mips-micro-got.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check microMIPS GOT relocations for O32 ABI. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux -mattr=micromips \ @@ -8,8 +9,6 @@ # RUN: ld.lld %t1.o %t.so -o %t.exe # RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Local entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: diff --git a/test/ELF/mips-micro-got64.s b/test/ELF/mips-micro-got64.s deleted file mode 100644 index 653bfbfbe8ce..000000000000 --- a/test/ELF/mips-micro-got64.s +++ /dev/null @@ -1,48 +0,0 @@ -# Check microMIPS GOT relocations for N64 ABI. - -# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \ -# RUN: %s -o %t1.o -# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux -mattr=micromips \ -# RUN: %S/Inputs/mips-dynamic.s -o %t2.o -# RUN: ld.lld %t2.o -shared -o %t.so -# RUN: ld.lld %t1.o %t.so -o %t.exe -# RUN: llvm-readobj -mips-plt-got %t.exe | FileCheck %s - -# REQUIRES: mips - -# CHECK: Local entries [ -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: -# CHECK-NEXT: Access: -32736 -# CHECK-NEXT: Initial: 0x30000 -# CHECK-NEXT: } -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: -# CHECK-NEXT: Access: -32728 -# CHECK-NEXT: Initial: 0x40000 -# CHECK-NEXT: } -# CHECK-NEXT: ] -# CHECK-NEXT: Global entries [ -# CHECK-NEXT: Entry { -# CHECK-NEXT: Address: -# CHECK-NEXT: Access: -32720 -# CHECK-NEXT: Initial: 0x0 -# CHECK-NEXT: Value: 0x0 -# CHECK-NEXT: Type: Function -# CHECK-NEXT: Section: Undefined -# CHECK-NEXT: Name: foo0 -# CHECK-NEXT: } -# CHECK-NEXT: ] - - .text - .global __start -__start: - lui $28, %hi(%neg(%gp_rel(foo0))) - addiu $28, $28, %lo(%neg(%gp_rel(foo0))) - lw $4, %got_page(data)($28) - addiu $4, $4, %got_ofst(data) - lw $25, %call16(foo0)($28) - - .data -data: - .word 0 diff --git a/test/ELF/mips-micro-jal.s b/test/ELF/mips-micro-jal.s index 83826126f766..18d41cf13cbc 100644 --- a/test/ELF/mips-micro-jal.s +++ b/test/ELF/mips-micro-jal.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check PLT creation for microMIPS to microMIPS calls. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -45,8 +46,6 @@ # RUN: llvm-objdump -d -mattr=micromips %teb.exe \ # RUN: | FileCheck --check-prefix=MIXED %s -# REQUIRES: mips - # EB: Disassembly of section .plt: # EB-NEXT: .plt: # EB-NEXT: 20010: 79 80 3f fd addiupc $3, 65524 diff --git a/test/ELF/mips-micro-plt.s b/test/ELF/mips-micro-plt.s index 5671dc420c55..6dcd6fbeec2d 100644 --- a/test/ELF/mips-micro-plt.s +++ b/test/ELF/mips-micro-plt.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check less-significant bit setup for microMIPS PLT. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -7,13 +8,12 @@ # RUN: -mattr=micromips %s -o %t-exe.o # RUN: ld.lld %t-exe.o %t.so -o %t.exe # RUN: llvm-readobj -t -dt -mips-plt-got %t.exe | FileCheck %s - -# REQUIRES: mips +# RUN: llvm-objdump -d -mattr=micromips %t.exe | FileCheck --check-prefix=ASM %s # CHECK: Symbols [ # CHECK: Symbol { # CHECK: Name: foo -# CHECK-NEXT: Value: 0x20008 +# CHECK-NEXT: Value: 0x20010 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Local # CHECK-NEXT: Type: None @@ -36,22 +36,28 @@ # CHECK-NEXT: } # CHECK: Symbol { # CHECK: Name: foo0 -# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Value: 0x20040 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Function -# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Other [ +# CHECK-NEXT: STO_MIPS_MICROMIPS +# CHECK-NEXT: STO_MIPS_PLT +# CHECK-NEXT: ] # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK: DynamicSymbols [ # CHECK: Symbol { # CHECK: Name: foo0 -# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Value: 0x20041 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Function -# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Other [ +# CHECK-NEXT: STO_MIPS_MICROMIPS +# CHECK-NEXT: STO_MIPS_PLT +# CHECK-NEXT: ] # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } # CHECK-NEXT: ] @@ -61,7 +67,7 @@ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: # CHECK-NEXT: Access: -# CHECK-NEXT: Initial: 0x20009 +# CHECK-NEXT: Initial: 0x20011 # CHECK-NEXT: } # CHECK: ] # CHECK: } @@ -70,8 +76,8 @@ # CHECK: Entries [ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: -# CHECK-NEXT: Initial: 0x20011 -# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Initial: 0x20021 +# CHECK-NEXT: Value: 0x20041 # CHECK-NEXT: Type: Function # CHECK-NEXT: Section: Undefined # CHECK-NEXT: Name: foo0@ @@ -79,6 +85,15 @@ # CHECK-NEXT: ] # CHECK-NEXT: } +# ASM: __start: +# ASM-NEXT: 20000: fd 1c 80 18 lw $8, -32744($gp) +# ASM-NEXT: 20004: 11 08 00 10 addi $8, $8, 16 +# ASM-NEXT: 20008: 41 a8 00 02 lui $8, 2 +# ASM-NEXT: 2000c: 11 08 00 40 addi $8, $8, 64 +# +# ASM: foo: +# ASM-NEXT: 20010: f4 01 00 20 jal 131136 + .text .set micromips .global foo @@ -87,5 +102,7 @@ __start: lw $t0,%got(foo)($gp) addi $t0,$t0,%lo(foo) + lui $t0,%hi(foo0) + addi $t0,$t0,%lo(foo0) foo: jal foo0 diff --git a/test/ELF/mips-micro-relocs.s b/test/ELF/mips-micro-relocs.s index 3986711cc7f7..b539aa946763 100644 --- a/test/ELF/mips-micro-relocs.s +++ b/test/ELF/mips-micro-relocs.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check handling of microMIPS relocations. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -16,8 +17,6 @@ # RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \ # RUN: | FileCheck --check-prefixes=EL,SYM %s -# REQUIRES: mips - # EB: __start: # EB-NEXT: 20010: 41 a3 00 01 lui $3, 1 # EB-NEXT: 20014: 30 63 7f df addiu $3, $3, 32735 diff --git a/test/ELF/mips-micro-thunks.s b/test/ELF/mips-micro-thunks.s index 18a8fc33f53c..0505361e4a66 100644 --- a/test/ELF/mips-micro-thunks.s +++ b/test/ELF/mips-micro-thunks.s @@ -1,44 +1,77 @@ +# REQUIRES: mips # Check microMIPS thunk generation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: -mattr=micromips %s -o %t-eb.o +# RUN: -mcpu=mips32r2 -mattr=micromips %s -o %t-eb.o # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ -# RUN: -position-independent -mattr=micromips \ +# RUN: -position-independent -mcpu=mips32r2 -mattr=micromips \ # RUN: %S/Inputs/mips-micro.s -o %t-eb-pic.o # RUN: ld.lld -o %t-eb.exe %t-eb.o %t-eb-pic.o # RUN: llvm-objdump -d -mattr=+micromips %t-eb.exe \ -# RUN: | FileCheck --check-prefix=EB %s +# RUN: | FileCheck --check-prefix=EB-R2 %s # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \ -# RUN: -mattr=micromips %s -o %t-el.o +# RUN: -mcpu=mips32r2 -mattr=micromips %s -o %t-el.o # RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \ -# RUN: -position-independent -mattr=micromips \ +# RUN: -position-independent -mcpu=mips32r2 -mattr=micromips \ # RUN: %S/Inputs/mips-micro.s -o %t-el-pic.o # RUN: ld.lld -o %t-el.exe %t-el.o %t-el-pic.o # RUN: llvm-objdump -d -mattr=+micromips %t-el.exe \ -# RUN: | FileCheck --check-prefix=EL %s +# RUN: | FileCheck --check-prefix=EL-R2 %s -# REQUIRES: mips +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: -mcpu=mips32r6 -mattr=micromips %s -o %t-eb-r6.o +# RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ +# RUN: -position-independent -mcpu=mips32r6 -mattr=micromips \ +# RUN: %S/Inputs/mips-micro.s -o %t-eb-pic-r6.o +# RUN: ld.lld -o %t-eb-r6.exe %t-eb-r6.o %t-eb-pic-r6.o +# RUN: llvm-objdump -d -mattr=+micromips %t-eb-r6.exe \ +# RUN: | FileCheck --check-prefix=EB-R6 %s + +# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \ +# RUN: -mcpu=mips32r6 -mattr=micromips %s -o %t-el-r6.o +# RUN: llvm-mc -filetype=obj -triple=mipsel-unknown-linux \ +# RUN: -position-independent -mcpu=mips32r6 -mattr=micromips \ +# RUN: %S/Inputs/mips-micro.s -o %t-el-pic-r6.o +# RUN: ld.lld -o %t-el-r6.exe %t-el-r6.o %t-el-pic-r6.o +# RUN: llvm-objdump -d -mattr=+micromips %t-el-r6.exe \ +# RUN: | FileCheck --check-prefix=EL-R6 %s + +# EB-R2: __start: +# EB-R2-NEXT: 20000: f4 01 00 04 jal 131080 <__microLA25Thunk_foo> +# EB-R2-NEXT: 20004: 00 00 00 00 nop + +# EB-R2: __microLA25Thunk_foo: +# EB-R2-NEXT: 20008: 41 b9 00 02 lui $25, 2 +# EB-R2-NEXT: 2000c: d4 01 00 10 j 131104 +# EB-R2-NEXT: 20010: 33 39 00 21 addiu $25, $25, 33 +# EB-R2-NEXT: 20014: 0c 00 nop + +# EL-R2: __start: +# EL-R2-NEXT: 20000: 01 f4 04 00 jal 131080 <__microLA25Thunk_foo> +# EL-R2-NEXT: 20004: 00 00 00 00 nop + +# EL-R2: __microLA25Thunk_foo: +# EL-R2-NEXT: 20008: b9 41 02 00 lui $25, 2 +# EL-R2-NEXT: 2000c: 01 d4 10 00 j 131104 +# EL-R2-NEXT: 20010: 39 33 21 00 addiu $25, $25, 33 +# EL-R2-NEXT: 20014: 00 0c nop + +# EB-R6: __start: +# EB-R6-NEXT: 20000: b4 00 00 00 balc 0 <__start> + +# EB-R6: __microLA25Thunk_foo: +# EB-R6-NEXT: 20004: 13 20 00 02 lui $25, 2 +# EB-R6-NEXT: 20008: 33 39 00 11 addiu $25, $25, 17 +# EB-R6-NEXT: 2000c: 94 00 00 00 bc 0 <__microLA25Thunk_foo+0x8> + +# EL-R6: __start: +# EL-R6-NEXT: 20000: 00 b4 00 00 balc 0 <__start> -# EB: __start: -# EB-NEXT: 20000: f4 01 00 04 jal 131080 <__microLA25Thunk_foo> -# EB-NEXT: 20004: 00 00 00 00 nop - -# EB: __microLA25Thunk_foo: -# EB-NEXT: 20008: 41 b9 00 02 lui $25, 2 -# EB-NEXT: 2000c: d4 01 00 10 j 131104 -# EB-NEXT: 20010: 33 39 00 21 addiu $25, $25, 33 -# EB-NEXT: 20014: 0c 00 nop - -# EL: __start: -# EL-NEXT: 20000: 01 f4 04 00 jal 131080 <__microLA25Thunk_foo> -# EL-NEXT: 20004: 00 00 00 00 nop - -# EL: __microLA25Thunk_foo: -# EL-NEXT: 20008: b9 41 02 00 lui $25, 2 -# EL-NEXT: 2000c: 01 d4 10 00 j 131104 -# EL-NEXT: 20010: 39 33 21 00 addiu $25, $25, 33 -# EL-NEXT: 20014: 00 0c nop +# EL-R6: __microLA25Thunk_foo: +# EL-R6-NEXT: 20004: 20 13 02 00 lui $25, 2 +# EL-R6-NEXT: 20008: 39 33 11 00 addiu $25, $25, 17 +# EL-R6-NEXT: 2000c: 00 94 00 00 bc 0 <__microLA25Thunk_foo+0x8> .text .set micromips diff --git a/test/ELF/mips-micror6-relocs.s b/test/ELF/mips-micror6-relocs.s new file mode 100644 index 000000000000..ca2c1c064f56 --- /dev/null +++ b/test/ELF/mips-micror6-relocs.s @@ -0,0 +1,38 @@ +# REQUIRES: mips + +# Check handling of microMIPS R6 relocations. + +# RUN: llvm-mc -filetype=obj -triple=mips -mcpu=mips32r6 \ +# RUN: %S/Inputs/mips-micro.s -o %t1eb.o +# RUN: llvm-mc -filetype=obj -triple=mips -mcpu=mips32r6 %s -o %t2eb.o +# RUN: ld.lld -o %teb.exe %t1eb.o %t2eb.o +# RUN: llvm-objdump -d -t -mattr=micromips %teb.exe \ +# RUN: | FileCheck --check-prefixes=EB,SYM %s + +# RUN: llvm-mc -filetype=obj -triple=mipsel -mcpu=mips32r6 \ +# RUN: %S/Inputs/mips-micro.s -o %t1el.o +# RUN: llvm-mc -filetype=obj -triple=mipsel -mcpu=mips32r6 %s -o %t2el.o +# RUN: ld.lld -o %tel.exe %t1el.o %t2el.o +# RUN: llvm-objdump -d -t -mattr=micromips %tel.exe \ +# RUN: | FileCheck --check-prefixes=EL,SYM %s + +# EB: __start: +# EB-NEXT: 20010: 78 47 ff fd lapc $2, -12 +# EB-NEXT: 20014: 80 7f ff f6 beqzc $3, -36 +# EB-NEXT: 20018: b7 ff ff f4 balc -24 <foo> + +# EL: __start: +# EL-NEXT: 20010: 47 78 fd ff lapc $2, -12 +# EL-NEXT: 20014: 7f 80 f6 ff beqzc $3, -36 +# EL-NEXT: 20018: ff b7 f4 ff balc -24 <foo> + +# SYM: 00020000 g F .text 00000000 foo +# SYM: 00020010 .text 00000000 __start + + .text + .set micromips + .global __start +__start: + addiupc $2, foo+4 # R_MICROMIPS_PC19_S2 + beqzc $3, foo+4 # R_MICROMIPS_PC21_S1 + balc foo+4 # R_MICROMIPS_PC26_S1 diff --git a/test/ELF/mips-n32-emul.s b/test/ELF/mips-n32-emul.s index d0d81cc1c95f..3385d512d968 100644 --- a/test/ELF/mips-n32-emul.s +++ b/test/ELF/mips-n32-emul.s @@ -1,10 +1,9 @@ +# REQUIRES: mips # Check that LLD shows an error when N32 ABI emulation argument # is combined with non-N32 ABI object files. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o -# RUN: not ld.lld -m elf32btsmipn32 %t.o -o %t.exe 2>&1 | FileCheck %s - -# REQUIRES: mips +# RUN: not ld.lld -m elf32btsmipn32 %t.o -o /dev/null 2>&1 | FileCheck %s .text .global __start diff --git a/test/ELF/mips-n32-rels.s b/test/ELF/mips-n32-rels.s index 954d4c30a157..b59000c06d86 100644 --- a/test/ELF/mips-n32-rels.s +++ b/test/ELF/mips-n32-rels.s @@ -1,29 +1,27 @@ +# REQUIRES: mips # Check handling of N32 ABI relocation records. -# For now llvm-mc generates incorrect object files for N32 ABI. -# We use the binary input file generated by GNU tool. -# llvm-mc -filetype=obj -triple=mips64-unknown-linux \ -# -target-abi n32 %s -o %t.o -# RUN: ld.lld %S/Inputs/mips-n32-rels.o -o %t.exe +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ +# RUN: -target-abi n32 -o %t.o %s +# RUN: ld.lld %t.o -o %t.exe # RUN: llvm-objdump -t -d -s %t.exe | FileCheck %s # RUN: llvm-readobj -h %t.exe | FileCheck -check-prefix=ELF %s -# REQUIRES: mips + .option pic2 + .text + .type __start, @function + .global __start +__start: + lui $gp,%hi(%neg(%gp_rel(__start))) # R_MIPS_GPREL16 + # R_MIPS_SUB + # R_MIPS_HI16 +loc: + daddiu $gp,$gp,%lo(%neg(%gp_rel(__start))) # R_MIPS_GPREL16 + # R_MIPS_SUB + # R_MIPS_LO16 -# .text -# .type __start, @function -# .global __start -# __start: -# lui $gp,%hi(%neg(%gp_rel(__start))) # R_MIPS_GPREL16 -# # R_MIPS_SUB -# # R_MIPS_HI16 -# loc: -# daddiu $gp,$gp,%lo(%neg(%gp_rel(__start))) # R_MIPS_GPREL16 -# # R_MIPS_SUB -# # R_MIPS_LO16 -# -# .section .rodata,"a",@progbits -# .gpword(loc) # R_MIPS_32 + .section .rodata,"a",@progbits + .gpword(loc) # R_MIPS_GPREL32 # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: @@ -38,8 +36,8 @@ # ^-- %lo(0x17ff0) # CHECK: Contents of section .rodata: -# CHECK-NEXT: {{[0-9a-f]+}} 00020004 -# ^-- loc +# CHECK-NEXT: {{[0-9a-f]+}} fffe8014 +# ^-- loc - _gp # CHECK: 00020004 .text 00000000 loc # CHECK: 00037ff0 .got 00000000 .hidden _gp @@ -67,5 +65,7 @@ # ELF-NEXT: SectionHeaderOffset: # ELF-NEXT: Flags [ # ELF-NEXT: EF_MIPS_ABI2 -# ELF-NEXT: EF_MIPS_ARCH_64R2 +# ELF-NEXT: EF_MIPS_ARCH_64 +# ELF-NEXT: EF_MIPS_CPIC +# ELF-NEXT: EF_MIPS_PIC # ELF-NEXT: ] diff --git a/test/ELF/mips-non-zero-gp0.s b/test/ELF/mips-non-zero-gp0.s new file mode 100644 index 000000000000..9e6b13c70725 --- /dev/null +++ b/test/ELF/mips-non-zero-gp0.s @@ -0,0 +1,54 @@ +# REQUIRES: mips + +# Check addend adjustment in case of generating a relocatable object +# if some input files have non-zero GP0 value. + +# We have to use GNU as and ld.bfd 2.28 to generate relocatable object +# files with non-zero GP0 value using the following command lines: +# +# as -mips32 -o test.o \ +# && ld.bfd -m elf32btsmip -r test.o -o mips-gp0-non-zero.o +# as -mips64 -o test.o \ +# && ld.bfd -m elf64btsmip -r test.o -o mips-n64-gp0-non-zero.o + +# Source code for mips-gp0-non-zero.o: +# .text +# .global __start +# __start: +# lw $t0,%call16(__start)($gp) +# foo: +# nop +# bar: +# nop +# +# .section .rodata, "a" +# v: +# .gpword foo +# .gpword bar + +# Source code for mips-n64-gp0-non-zero.o and mips-micro-gp0-non-zero.o: +# .text +# .global __start +# __start: +# foo: +# lui $gp,%hi(%neg(%gp_rel(foo))) + +# RUN: ld.lld -r -o %t-32.r %S/Inputs/mips-gp0-non-zero.o +# RUN: llvm-readobj -mips-reginfo %t-32.r | FileCheck --check-prefix=GPVAL %s +# RUN: llvm-objdump -s %t-32.r | FileCheck --check-prefix=ADDEND32 %s + +# RUN: ld.lld -r -o %t-64.r %S/Inputs/mips-n64-gp0-non-zero.o +# RUN: llvm-readobj -mips-options %t-64.r | FileCheck --check-prefix=GPVAL %s +# RUN: llvm-readobj -r %S/Inputs/mips-n64-gp0-non-zero.o %t-64.r \ +# RUN: | FileCheck --check-prefix=ADDEND64 %s + +# GPVAL: GP: 0x0 + +# ADDEND32: Contents of section .rodata: +# ADDEND32-NEXT: 0000 00007ff4 00007ff8 +# ^ 4+GP0 ^ 8+GP0 + +# ADDEND64: File: {{.*}}{{/|\\}}mips-n64-gp0-non-zero.o +# ADDEND64: .text 0xFFFFFFFFFFFF8011 +# ADDEND64: File: {{.*}}{{/|\\}}mips-non-zero-gp0.s.tmp-64.r +# ADDEND64: .text 0x0 diff --git a/test/ELF/mips-nonalloc.s b/test/ELF/mips-nonalloc.s index 7b0aa9469f9f..38d4599c689d 100644 --- a/test/ELF/mips-nonalloc.s +++ b/test/ELF/mips-nonalloc.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check reading addends for relocations in non-allocatable sections. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o @@ -6,8 +7,6 @@ # RUN: ld.lld %t1.o %t2.o -o %t.exe # RUN: llvm-objdump -s %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Contents of section .debug_info: # CHECK-NEXT: 0000 ffffffff 00020000 00020000 # ^--------^-- __start diff --git a/test/ELF/mips-options.s b/test/ELF/mips-options.s index 18f5af8ece6e..ad634171eff7 100644 --- a/test/ELF/mips-options.s +++ b/test/ELF/mips-options.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS .MIPS.options section generation. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o @@ -9,8 +10,6 @@ # RUN: ld.lld %t1.o %t2.o --gc-sections --script %t.rel.script -shared -o %t.so # RUN: llvm-readobj -symbols -mips-options %t.so | FileCheck %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-out-of-bounds-call16-reloc.s b/test/ELF/mips-out-of-bounds-call16-reloc.s index 64e9ab3aa7e2..cc2494af5948 100644 --- a/test/ELF/mips-out-of-bounds-call16-reloc.s +++ b/test/ELF/mips-out-of-bounds-call16-reloc.s @@ -1,8 +1,8 @@ +# REQUIRES: mips # Check that we create an error on an out-of-bounds R_MIPS_CALL_16 -# REQUIRES: mips # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t1.o -# RUN: not ld.lld %t1.o -o %t.exe 2>&1 | FileCheck %s +# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | FileCheck %s # CHECK: relocation R_MIPS_CALL16 out of range: 32768 is not in [-32768, 32767] diff --git a/test/ELF/mips-pc-relocs.s b/test/ELF/mips-pc-relocs.s index e0f39e7ed7c4..46c2b75578d9 100644 --- a/test/ELF/mips-pc-relocs.s +++ b/test/ELF/mips-pc-relocs.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check R_MIPS_PCxxx relocations calculation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -7,8 +8,6 @@ # RUN: ld.lld %t1.o %t2.o -o %t.exe # RUN: llvm-objdump -mcpu=mips32r6 -d -t -s %t.exe | FileCheck %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-plt-copy.s b/test/ELF/mips-plt-copy.s index 58883d884563..e035c5bd588c 100644 --- a/test/ELF/mips-plt-copy.s +++ b/test/ELF/mips-plt-copy.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check creating of R_MIPS_COPY and R_MIPS_JUMP_SLOT dynamic relocations # and corresponding PLT entries. @@ -8,16 +9,14 @@ # RUN: ld.lld %t.o %t.so -o %t.exe # RUN: llvm-readobj -r -mips-plt-got %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Relocations [ # CHECK-NEXT: Section ({{.*}}) .rel.dyn { -# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0 -# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0 +# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_COPY data0 0x0 +# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_COPY data1 0x0 # CHECK-NEXT: } # CHECK-NEXT: Section ({{.*}}) .rel.plt { -# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0 -# CHECK-NEXT: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0 +# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo0 0x0 +# CHECK-DAG: 0x{{[0-9A-F]+}} R_MIPS_JUMP_SLOT foo1 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] diff --git a/test/ELF/mips-plt-n32.s b/test/ELF/mips-plt-n32.s new file mode 100644 index 000000000000..06699fc1d045 --- /dev/null +++ b/test/ELF/mips-plt-n32.s @@ -0,0 +1,43 @@ +# REQUIRES: mips + +# Check PLT entries generation in case of using N32 ABI. + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ +# RUN: -target-abi n32 %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ +# RUN: -target-abi n32 %S/Inputs/mips-dynamic.s -o %t2.o +# RUN: ld.lld %t2.o -shared -o %t.so +# RUN: ld.lld %t1.o %t.so -o %t.exe +# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=DEFAULT,CHECK +# RUN: ld.lld %t2.o -shared -o %t.so -z hazardplt +# RUN: ld.lld %t1.o %t.so -o %t.exe -z hazardplt +# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=HAZARDPLT,CHECK + +# CHECK: Disassembly of section .text: +# CHECK-NEXT: __start: +# CHECK-NEXT: 20000: 0c 00 80 0c jal 131120 +# ^-- 0x20030 gotplt[foo0] +# CHECK-NEXT: 20004: 00 00 00 00 nop +# +# CHECK-NEXT: Disassembly of section .plt: +# CHECK-NEXT: .plt: +# CHECK-NEXT: 20010: 3c 0e 00 03 lui $14, 3 +# CHECK-NEXT: 20014: 8d d9 00 04 lw $25, 4($14) +# CHECK-NEXT: 20018: 25 ce 00 04 addiu $14, $14, 4 +# CHECK-NEXT: 2001c: 03 0e c0 23 subu $24, $24, $14 +# CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra +# CHECK-NEXT: 20024: 00 18 c0 82 srl $24, $24, 2 +# DEFAULT: 20028: 03 20 f8 09 jalr $25 +# HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25 +# CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2 + +# CHECK-NEXT: 20030: 3c 0f 00 03 lui $15, 3 +# CHECK-NEXT: 20034: 8d f9 00 0c lw $25, 12($15) +# DEFAULT: 20038: 03 20 00 08 jr $25 +# HAZARDPLT: 20038: 03 20 04 08 jr.hb $25 +# CHECK-NEXT: 2003c: 25 f8 00 0c addiu $24, $15, 12 + + .text + .global __start +__start: + jal foo0 # R_MIPS_26 against 'foo0' from DSO diff --git a/test/ELF/mips-plt-r6.s b/test/ELF/mips-plt-r6.s index 4bab21c32eb9..b0ceb8214f02 100644 --- a/test/ELF/mips-plt-r6.s +++ b/test/ELF/mips-plt-r6.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check PLT entries generation in case of R6 ABI version. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -6,9 +7,10 @@ # RUN: -mcpu=mips32r6 %S/Inputs/mips-dynamic.s -o %t2.o # RUN: ld.lld %t2.o -shared -o %t.so # RUN: ld.lld %t1.o %t.so -o %t.exe -# RUN: llvm-objdump -d %t.exe | FileCheck %s - -# REQUIRES: mips +# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=DEFAULT,CHECK +# RUN: ld.lld %t2.o -shared -o %t.so -z hazardplt +# RUN: ld.lld %t1.o %t.so -o %t.exe -z hazardplt +# RUN: llvm-objdump -d %t.exe | FileCheck %s --check-prefixes=HAZARDPLT,CHECK # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: @@ -24,12 +26,14 @@ # CHECK-NEXT: 2001c: 03 1c c0 23 subu $24, $24, $gp # CHECK-NEXT: 20020: 03 e0 78 25 move $15, $ra # CHECK-NEXT: 20024: 00 18 c0 82 srl $24, $24, 2 -# CHECK-NEXT: 20028: 03 20 f8 09 jalr $25 +# DEFAULT: 20028: 03 20 f8 09 jalr $25 +# HAZARDPLT: 20028: 03 20 fc 09 jalr.hb $25 # CHECK-NEXT: 2002c: 27 18 ff fe addiu $24, $24, -2 # CHECK-NEXT: 20030: 3c 0f 00 03 aui $15, $zero, 3 # CHECK-NEXT: 20034: 8d f9 00 0c lw $25, 12($15) -# CHECK-NEXT: 20038: 03 20 00 09 jr $25 +# DEFAULT: 20038: 03 20 00 09 jr $25 +# HAZARDPLT: 20038: 03 20 04 09 jr.hb $25 # CHECK-NEXT: 2003c: 25 f8 00 0c addiu $24, $15, 12 .text diff --git a/test/ELF/mips-reginfo.s b/test/ELF/mips-reginfo.s index 4024a2f6634f..049950d7424b 100644 --- a/test/ELF/mips-reginfo.s +++ b/test/ELF/mips-reginfo.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS .reginfo section generation. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t1.o @@ -6,8 +7,6 @@ # RUN: ld.lld %t1.o %t2.o --gc-sections -shared -o %t.so # RUN: llvm-readobj -symbols -mips-reginfo %t.so | FileCheck %s -# REQUIRES: mips - .text .globl __start __start: diff --git a/test/ELF/mips-relocatable.s b/test/ELF/mips-relocatable.s index 168ddf736e1e..0ab62774a4d8 100644 --- a/test/ELF/mips-relocatable.s +++ b/test/ELF/mips-relocatable.s @@ -1,11 +1,10 @@ +# REQUIRES: mips # Check linking MIPS code in case of -r linker's option. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux %s -o %t.o # RUN: ld.lld -r -o %t-r.o %t.o # RUN: llvm-objdump -s -t %t-r.o | FileCheck %s -# REQUIRES: mips - .text .global __start __start: diff --git a/test/ELF/mips-sto-pic-flag.s b/test/ELF/mips-sto-pic-flag.s index 3960ba322387..ae496979f7c6 100644 --- a/test/ELF/mips-sto-pic-flag.s +++ b/test/ELF/mips-sto-pic-flag.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # In case of linking PIC and non-PIC code together and generation # of a relocatable object, all PIC symbols should have STO_MIPS_PIC # flag in the symbol table of the ouput file. @@ -8,8 +9,6 @@ # RUN: ld.lld -r %t-npic.o %t-pic.o -o %t-rel.o # RUN: llvm-readobj -t %t-rel.o | FileCheck %s -# REQUIRES: mips - # CHECK: Symbol { # CHECK: Name: main # CHECK-NEXT: Value: diff --git a/test/ELF/mips-sto-plt.s b/test/ELF/mips-sto-plt.s index bd8de416680a..b4d3ee391414 100644 --- a/test/ELF/mips-sto-plt.s +++ b/test/ELF/mips-sto-plt.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check assigning STO_MIPS_PLT flag to symbol needs a pointer equality. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -7,8 +8,6 @@ # RUN: ld.lld %t.o %t.so -o %t.exe # RUN: llvm-readobj -dt -mips-plt-got %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Symbol { # CHECK: Name: foo0@ # CHECK-NEXT: Value: 0x0 @@ -18,9 +17,9 @@ # CHECK-NEXT: Other: 0 # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } -# CHECK: Symbol { -# CHECK: Name: foo1@ -# CHECK-NEXT: Value: 0x20050 +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Name: foo1@ +# CHECK-NEXT: Value: 0x[[FOO1:[0-9A-F]+]] # CHECK-NEXT: Size: 0 # CHECK-NEXT: Binding: Global # CHECK-NEXT: Type: Function @@ -48,7 +47,7 @@ # CHECK-NEXT: Entry { # CHECK-NEXT: Address: # CHECK-NEXT: Initial: -# CHECK-NEXT: Value: 0x20050 +# CHECK-NEXT: Value: 0x[[FOO1]] # CHECK-NEXT: Type: Function # CHECK-NEXT: Section: Undefined # CHECK-NEXT: Name: foo1 diff --git a/test/ELF/mips-tls-64-pic-local-variable.s b/test/ELF/mips-tls-64-pic-local-variable.s new file mode 100644 index 000000000000..04d916f42c6c --- /dev/null +++ b/test/ELF/mips-tls-64-pic-local-variable.s @@ -0,0 +1,49 @@ +# REQUIRES: mips +# MIPS TLS variables that are marked as local by a version script were previously +# writing values to the GOT that caused runtime crashes. This was happending when +# linking jemalloc_tsd.c in FreeBSD libc. Check that we do the right thing now: + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o +# RUN: echo "{ global: foo; local: *; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-objdump --section=.got -s %t.so | FileCheck %s -check-prefix GOT +# RUN: llvm-readobj -r %t.so | FileCheck %s -check-prefix RELOCS + +# GOT: Contents of section .got: +# GOT-NEXT: 20000 00000000 00000000 80000000 00000000 +# GOT-NEXT: 20010 00000000 00000000 00000000 00000000 +# GOT-NEXT: 20020 ffffffff ffff8000 + +# RELOCS: Section ({{.+}}) .rel.dyn { +# RELOCS-NEXT: 0x20018 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE +# RELOCS-NEXT: } + +# Test case generated using clang -mcpu=mips4 -target mips64-unknown-freebsd12.0 -fpic -O -G0 -EB -mabi=n64 -msoft-float -std=gnu99 -S %s -o %t.s +# from the following source: +# +# _Thread_local int x; +# int foo() { return x; } +# + .text + .globl foo + .p2align 3 + .type foo,@function + .ent foo +foo: + lui $1, %hi(%neg(%gp_rel(foo))) + daddu $1, $1, $25 + daddiu $gp, $1, %lo(%neg(%gp_rel(foo))) + ld $25, %call16(__tls_get_addr)($gp) + jalr $25 + daddiu $4, $gp, %tlsgd(x) + .end foo + + .type x,@object + .section .tbss,"awT",@nobits + .globl x + .p2align 2 +x: + .4byte 0 + .size x, 4 + + diff --git a/test/ELF/mips-tls-64.s b/test/ELF/mips-tls-64.s index db29789ee117..f000755b4e82 100644 --- a/test/ELF/mips-tls-64.s +++ b/test/ELF/mips-tls-64.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS TLS 64-bit relocations handling. # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux \ @@ -13,31 +14,29 @@ # RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s # RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s -# REQUIRES: mips - # DIS: __start: -# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736 -# DIS-NEXT: 20004: 24 62 80 30 addiu $2, $3, -32720 -# DIS-NEXT: 20008: 24 62 80 38 addiu $2, $3, -32712 -# DIS-NEXT: 2000c: 24 62 80 48 addiu $2, $3, -32696 -# DIS-NEXT: 20010: 24 62 80 58 addiu $2, $3, -32680 +# DIS-NEXT: 20000: 24 62 80 30 addiu $2, $3, -32720 +# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736 +# DIS-NEXT: 20008: 24 62 80 40 addiu $2, $3, -32704 +# DIS-NEXT: 2000c: 24 62 80 50 addiu $2, $3, -32688 +# DIS-NEXT: 20010: 24 62 80 28 addiu $2, $3, -32728 # DIS: Contents of section .got: # DIS-NEXT: 30010 00000000 00000000 80000000 00000000 -# DIS-NEXT: 30020 00000000 00000000 00000000 00000000 -# DIS-NEXT: 30030 00000000 00000000 00000000 00000001 -# DIS-NEXT: 30040 00000000 00000000 00000000 00000001 -# DIS-NEXT: 30050 ffffffff ffff8004 ffffffff ffff9004 +# DIS-NEXT: 30020 00000000 00000000 ffffffff ffff9004 +# DIS-NEXT: 30030 00000000 00000000 00000000 00000000 +# DIS-NEXT: 30040 00000000 00000001 00000000 00000000 +# DIS-NEXT: 30050 00000000 00000001 ffffffff ffff8004 # DIS: 0000000000000000 l .tdata 00000000 loc # DIS: 0000000000000004 g .tdata 00000000 bar # DIS: 0000000000000000 g *UND* 00000000 foo # CHECK: Relocations [ -# CHECK-NEXT: Section (7) .rela.dyn { -# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# CHECK-NEXT: 0x30028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# CHECK-NEXT: 0x30030 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# CHECK-NEXT: Section (7) .rel.dyn { +# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# CHECK-NEXT: 0x30030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# CHECK-NEXT: 0x30038 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Primary GOT { @@ -49,31 +48,31 @@ # CHECK-NEXT: Global entries [ # CHECK-NEXT: ] # CHECK-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo -# ^-- -32728 R_MIPS_TLS_DTPREL64 foo -# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo -# ^-- -32712 R_MIPS_TLS_LDM 1 loc -# ^-- -32704 0 loc -# ^-- -32696 R_MIPS_TLS_GD 1 bar -# ^-- -32688 VA - 0x8000 bar -# ^-- -32680 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo +# ^-- -32728 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo +# ^-- -32712 R_MIPS_TLS_DTPREL64 foo +# ^-- -32704 R_MIPS_TLS_LDM 1 loc +# ^-- -32696 0 loc +# ^-- -32688 R_MIPS_TLS_GD 1 bar +# ^-- -32680 VA - 0x8000 bar # DIS-SO: Contents of section .got: # DIS-SO-NEXT: 20000 00000000 00000000 80000000 00000000 -# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000 +# DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000004 # DIS-SO-NEXT: 20020 00000000 00000000 00000000 00000000 # DIS-SO-NEXT: 20030 00000000 00000000 00000000 00000000 # DIS-SO-NEXT: 20040 00000000 00000000 00000000 00000000 # SO: Relocations [ -# SO-NEXT: Section (7) .rela.dyn { -# SO-NEXT: 0x20028 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0 -# SO-NEXT: 0x20038 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 -# SO-NEXT: 0x20040 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 -# SO-NEXT: 0x20048 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 -# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# SO-NEXT: 0x20018 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 -# SO-NEXT: 0x20020 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# SO-NEXT: Section (7) .rel.dyn { +# SO-NEXT: 0x20030 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE - 0x0 +# SO-NEXT: 0x20018 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 +# SO-NEXT: 0x20040 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 +# SO-NEXT: 0x20048 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE bar 0x0 +# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 +# SO-NEXT: 0x20028 R_MIPS_TLS_DTPREL64/R_MIPS_NONE/R_MIPS_NONE foo 0x0 # SO-NEXT: } # SO-NEXT: ] # SO-NEXT: Primary GOT { @@ -85,14 +84,14 @@ # SO-NEXT: Global entries [ # SO-NEXT: ] # SO-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo -# ^-- -32728 R_MIPS_TLS_DTPREL64 foo -# ^-- -32720 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo -# ^-- -32712 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc -# ^-- -32704 0 loc -# ^-- -32696 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar -# ^-- -32688 R_MIPS_TLS_DTPREL64 bar -# ^-- -32680 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar +# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 foo +# ^-- -32728 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL64 bar +# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 foo +# ^-- -32712 R_MIPS_TLS_DTPREL64 foo +# ^-- -32704 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD64 loc +# ^-- -32696 0 loc +# ^-- -32688 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD64 bar +# ^-- -32680 R_MIPS_TLS_DTPREL64 bar .text .global __start diff --git a/test/ELF/mips-tls-hilo.s b/test/ELF/mips-tls-hilo.s index 47fadaa34b80..ae54602327a9 100644 --- a/test/ELF/mips-tls-hilo.s +++ b/test/ELF/mips-tls-hilo.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS R_MIPS_TLS_DTPREL_HI16/LO16 and R_MIPS_TLS_TPREL_HI16/LO16 # relocations handling. @@ -9,8 +10,6 @@ # RUN: ld.lld %t.o -shared -o %t.so # RUN: llvm-readobj -r -mips-plt-got %t.so | FileCheck -check-prefix=SO %s -# REQUIRES: mips - # DIS: __start: # DIS-NEXT: 20000: 24 62 00 00 addiu $2, $3, 0 # %hi(loc0 - .tdata - 0x8000) --^ diff --git a/test/ELF/mips-tls-static-64.s b/test/ELF/mips-tls-static-64.s index 6f88e86a3f44..04f18fa57585 100644 --- a/test/ELF/mips-tls-static-64.s +++ b/test/ELF/mips-tls-static-64.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check handling TLS related relocations and symbols when linking # a 64-bit static executable. @@ -5,8 +6,6 @@ # RUN: ld.lld -static %t -o %t.exe # RUN: llvm-objdump -s -t %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Contents of section .data: # CHECK-NEXT: 30000 00020004 ffffffff ffff8004 ffffffff # CHECK-NEXT: 30010 ffff9004 diff --git a/test/ELF/mips-tls-static.s b/test/ELF/mips-tls-static.s index 84b56cb42240..b09f5516bc89 100644 --- a/test/ELF/mips-tls-static.s +++ b/test/ELF/mips-tls-static.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check handling TLS related relocations and symbols when linking # a static executable. @@ -5,13 +6,11 @@ # RUN: ld.lld -static %t -o %t.exe # RUN: llvm-objdump -s -t %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Contents of section .data: # CHECK-NEXT: 30000 0002000c ffff8004 ffff9004 # CHECK: Contents of section .got: -# CHECK-NEXT: 30010 00000000 80000000 00000001 ffff8000 -# CHECK-NEXT: 30020 00000001 00000000 ffff9000 +# CHECK-NEXT: 30010 00000000 80000000 ffff9000 00000001 +# CHECK-NEXT: 30020 ffff8000 00000001 00000000 # # CHECK: SYMBOL TABLE: # CHECK: 0002000c .text 00000000 __tls_get_addr diff --git a/test/ELF/mips-tls.s b/test/ELF/mips-tls.s index b64f8db75731..ece55c69b303 100644 --- a/test/ELF/mips-tls.s +++ b/test/ELF/mips-tls.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check MIPS TLS relocations handling. # RUN: llvm-mc -filetype=obj -triple=mips-unknown-linux \ @@ -13,19 +14,17 @@ # RUN: llvm-objdump -d -s -t %t-out.so | FileCheck -check-prefix=DIS-SO %s # RUN: llvm-readobj -r -mips-plt-got %t-out.so | FileCheck -check-prefix=SO %s -# REQUIRES: mips - # DIS: __start: -# DIS-NEXT: 20000: 24 62 80 18 addiu $2, $3, -32744 -# DIS-NEXT: 20004: 24 62 80 20 addiu $2, $3, -32736 -# DIS-NEXT: 20008: 24 62 80 24 addiu $2, $3, -32732 -# DIS-NEXT: 2000c: 24 62 80 2c addiu $2, $3, -32724 -# DIS-NEXT: 20010: 24 62 80 34 addiu $2, $3, -32716 +# DIS-NEXT: 20000: 24 62 80 20 addiu $2, $3, -32736 +# DIS-NEXT: 20004: 24 62 80 18 addiu $2, $3, -32744 +# DIS-NEXT: 20008: 24 62 80 28 addiu $2, $3, -32728 +# DIS-NEXT: 2000c: 24 62 80 30 addiu $2, $3, -32720 +# DIS-NEXT: 20010: 24 62 80 1c addiu $2, $3, -32740 # DIS: Contents of section .got: -# DIS-NEXT: 30010 00000000 80000000 00000000 00000000 -# DIS-NEXT: 30020 00000000 00000001 00000000 00000001 -# DIS-NEXT: 30030 ffff8004 ffff9004 +# DIS-NEXT: 30010 00000000 80000000 00000000 ffff9004 +# DIS-NEXT: 30020 00000000 00000000 00000001 00000000 +# DIS-NEXT: 30030 00000001 ffff8004 # DIS: 00000000 l .tdata 00000000 loc # DIS: 00000004 g .tdata 00000000 bar @@ -33,9 +32,9 @@ # CHECK: Relocations [ # CHECK-NEXT: Section (7) .rel.dyn { -# CHECK-NEXT: 0x30018 R_MIPS_TLS_DTPMOD32 foo 0x0 -# CHECK-NEXT: 0x3001C R_MIPS_TLS_DTPREL32 foo 0x0 -# CHECK-NEXT: 0x30020 R_MIPS_TLS_TPREL32 foo 0x0 +# CHECK-NEXT: 0x30018 R_MIPS_TLS_TPREL32 foo 0x0 +# CHECK-NEXT: 0x30020 R_MIPS_TLS_DTPMOD32 foo 0x0 +# CHECK-NEXT: 0x30024 R_MIPS_TLS_DTPREL32 foo 0x0 # CHECK-NEXT: } # CHECK-NEXT: ] # CHECK-NEXT: Primary GOT { @@ -47,29 +46,29 @@ # CHECK-NEXT: Global entries [ # CHECK-NEXT: ] # CHECK-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo -# ^-- -32740 R_MIPS_TLS_DTPREL32 foo -# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo -# ^-- -32732 R_MIPS_TLS_LDM 1 loc -# ^-- -32728 0 loc -# ^-- -32724 R_MIPS_TLS_GD 1 bar -# ^-- -32720 VA - 0x8000 bar -# ^-- -32716 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo +# ^-- -32740 R_MIPS_TLS_GOTTPREL VA - 0x7000 bar +# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo +# ^-- -32732 R_MIPS_TLS_DTPREL32 foo +# ^-- -32728 R_MIPS_TLS_LDM 1 loc +# ^-- -32724 0 loc +# ^-- -32720 R_MIPS_TLS_GD 1 bar +# ^-- -32716 VA - 0x8000 bar # DIS-SO: Contents of section .got: -# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000000 +# DIS-SO-NEXT: 20000 00000000 80000000 00000000 00000004 # DIS-SO-NEXT: 20010 00000000 00000000 00000000 00000000 # DIS-SO-NEXT: 20020 00000000 00000000 # SO: Relocations [ # SO-NEXT: Section (7) .rel.dyn { -# SO-NEXT: 0x20014 R_MIPS_TLS_DTPMOD32 - 0x0 -# SO-NEXT: 0x2001C R_MIPS_TLS_DTPMOD32 bar 0x0 -# SO-NEXT: 0x20020 R_MIPS_TLS_DTPREL32 bar 0x0 -# SO-NEXT: 0x20024 R_MIPS_TLS_TPREL32 bar 0x0 -# SO-NEXT: 0x20008 R_MIPS_TLS_DTPMOD32 foo 0x0 -# SO-NEXT: 0x2000C R_MIPS_TLS_DTPREL32 foo 0x0 -# SO-NEXT: 0x20010 R_MIPS_TLS_TPREL32 foo 0x0 +# SO-NEXT: 0x20018 R_MIPS_TLS_DTPMOD32 - 0x0 +# SO-NEXT: 0x2000C R_MIPS_TLS_TPREL32 bar 0x0 +# SO-NEXT: 0x20020 R_MIPS_TLS_DTPMOD32 bar 0x0 +# SO-NEXT: 0x20024 R_MIPS_TLS_DTPREL32 bar 0x0 +# SO-NEXT: 0x20008 R_MIPS_TLS_TPREL32 foo 0x0 +# SO-NEXT: 0x20010 R_MIPS_TLS_DTPMOD32 foo 0x0 +# SO-NEXT: 0x20014 R_MIPS_TLS_DTPREL32 foo 0x0 # SO-NEXT: } # SO-NEXT: ] # SO-NEXT: Primary GOT { @@ -81,14 +80,14 @@ # SO-NEXT: Global entries [ # SO-NEXT: ] # SO-NEXT: Number of TLS and multi-GOT entries: 8 -# ^-- -32744 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo -# ^-- -32740 R_MIPS_TLS_DTPREL32 foo -# ^-- -32736 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo -# ^-- -32732 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc -# ^-- -32728 0 loc -# ^-- -32724 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar -# ^-- -32720 R_MIPS_TLS_DTPREL32 bar -# ^-- -32716 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar +# ^-- -32744 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 foo +# ^-- -32740 R_MIPS_TLS_GOTTPREL R_MIPS_TLS_TPREL32 bar +# ^-- -32736 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 foo +# ^-- -32732 R_MIPS_TLS_DTPREL32 foo +# ^-- -32728 R_MIPS_TLS_LDM R_MIPS_TLS_DTPMOD32 loc +# ^-- -32724 0 loc +# ^-- -32720 R_MIPS_TLS_GD R_MIPS_TLS_DTPMOD32 bar +# ^-- -32716 R_MIPS_TLS_DTPREL32 bar .text .global __start diff --git a/test/ELF/mips-xgot-order.s b/test/ELF/mips-xgot-order.s index 911731c713cd..c44cf64edd5a 100644 --- a/test/ELF/mips-xgot-order.s +++ b/test/ELF/mips-xgot-order.s @@ -1,3 +1,4 @@ +# REQUIRES: mips # Check that GOT entries accessed via 16-bit indexing are allocated # in the beginning of the GOT. @@ -5,8 +6,6 @@ # RUN: ld.lld %t.o -o %t.exe # RUN: llvm-objdump -d -s -t %t.exe | FileCheck %s -# REQUIRES: mips - # CHECK: Disassembly of section .text: # CHECK-NEXT: __start: # CHECK-NEXT: 20000: 3c 02 00 00 lui $2, 0 diff --git a/test/ELF/mips64-eh-abs-reloc.s b/test/ELF/mips64-eh-abs-reloc.s index 7bc500137992..7c31e1b51eda 100644 --- a/test/ELF/mips64-eh-abs-reloc.s +++ b/test/ELF/mips64-eh-abs-reloc.s @@ -1,5 +1,5 @@ -# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD # REQUIRES: mips +# Having an R_MIPS_64 relocation in eh_frame would previously crash LLD # RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o # RUN: llvm-readobj -r %t.o | FileCheck %s -check-prefix OBJ # RUN: ld.lld --eh-frame-hdr -shared -z notext -o %t.so %t.o @@ -20,8 +20,8 @@ # OBJ-NEXT: } # PIC-RELOCS: Relocations [ -# PIC-RELOCS-NEXT: Section (7) .rela.dyn { -# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x10000 +# PIC-RELOCS-NEXT: Section (7) .rel.dyn { +# PIC-RELOCS-NEXT: {{0x.+}} R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE - 0x0 # PIC-RELOCS-NEXT: } # PIC-RELOCS-NEXT:] diff --git a/test/ELF/multiple-cu.s b/test/ELF/multiple-cu.s new file mode 100644 index 000000000000..996a7bcd06d4 --- /dev/null +++ b/test/ELF/multiple-cu.s @@ -0,0 +1,38 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/multiple-cu.s -o %t2.o +# RUN: ld.lld -r -o %t.o %t1.o %t2.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: foo +# CHECK-NEXT: referenced by test1.c:2 + +# CHECK: error: undefined symbol: bar +# CHECK-NEXT: referenced by test2.c:2 + + .globl _start +_start: + .file 1 "test1.c" + .loc 1 2 0 + jmp foo + + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 0 # DW_CHILDREN_no + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + + .section .debug_info,"",@progbits + .long .Lend0 - .Lbegin0 # Length of Unit +.Lbegin0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit + .long .debug_line # DW_AT_stmt_list +.Lend0: + .section .debug_line,"",@progbits diff --git a/test/ELF/new-dtags.test b/test/ELF/new-dtags.test index 1ae328c6b502..bceea4bd6d65 100644 --- a/test/ELF/new-dtags.test +++ b/test/ELF/new-dtags.test @@ -1,8 +1,12 @@ # REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -rpath=/somepath -shared --disable-new-dtags -o %t -// RUN: ld.lld %t.o -rpath=/somepath -shared --enable-new-dtags -o %t2 // RUN: llvm-readobj --dynamic-table %t | FileCheck --check-prefix=DISABLE %s + +// RUN: ld.lld %t.o -rpath=/somepath -shared --enable-new-dtags -o %t2 +// RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=ENABLE %s + +// RUN: ld.lld %t.o -rpath=/somepath -shared --disable-new-dtags --enable-new-dtags -o %t2 // RUN: llvm-readobj --dynamic-table %t2 | FileCheck --check-prefix=ENABLE %s // DISABLE: DynamicSection [ diff --git a/test/ELF/no-augmentation.s b/test/ELF/no-augmentation.s index 31cd92e39b1c..f4912ba68366 100644 --- a/test/ELF/no-augmentation.s +++ b/test/ELF/no-augmentation.s @@ -1,7 +1,6 @@ -// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o -// RUN: ld.lld --eh-frame-hdr %t.o -o %t | FileCheck -allow-empty %s - // REQUIRES: mips +// RUN: llvm-mc -filetype=obj -triple=mips64-unknown-freebsd %s -o %t.o +// RUN: ld.lld --eh-frame-hdr %t.o -o /dev/null | FileCheck -allow-empty %s // CHECK-NOT: corrupted or unsupported CIE information // CHECK-NOT: corrupted CIE diff --git a/test/ELF/no-dynamic-linker.s b/test/ELF/no-dynamic-linker.s deleted file mode 100644 index f5c7f4b8d072..000000000000 --- a/test/ELF/no-dynamic-linker.s +++ /dev/null @@ -1,12 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %tso.o -# RUN: ld.lld -shared %tso.o -o %t.so -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o - -# RUN: ld.lld -dynamic-linker foo --no-dynamic-linker %t.o %t.so -o %t -# RUN: llvm-readobj --program-headers %t | FileCheck %s --check-prefix=NODL -# NODL-NOT: PT_INTERP - -# RUN: ld.lld --no-dynamic-linker -dynamic-linker foo %t.o %t.so -o %t -# RUN: llvm-readobj --program-headers %t | FileCheck %s --check-prefix=WITHDL -# WITHDL: PT_INTERP diff --git a/test/ELF/no-inhibit-exec.s b/test/ELF/no-inhibit-exec.s index afb7aed94c12..1535f6e7b87e 100644 --- a/test/ELF/no-inhibit-exec.s +++ b/test/ELF/no-inhibit-exec.s @@ -1,9 +1,9 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: not ld.lld %t -o %t2 # RUN: ld.lld %t --noinhibit-exec -o %t2 # RUN: llvm-objdump -d %t2 | FileCheck %s # RUN: llvm-readobj -r %t2 | FileCheck %s --check-prefix=RELOC -# REQUIRES: x86 # CHECK: Disassembly of section .text: # CHECK-NEXT: _start diff --git a/test/ELF/no-line-parser-errors-if-empty-section.s b/test/ELF/no-line-parser-errors-if-empty-section.s new file mode 100644 index 000000000000..808052e7ff0b --- /dev/null +++ b/test/ELF/no-line-parser-errors-if-empty-section.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 + +# LLD uses the debug data to get information for error messages, if possible. +# However, if the debug line section is empty, we should not attempt to parse +# it, as that would result in errors from the parser. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK-NOT: warning: +# CHECK-NOT: error: +# CHECK: error: undefined symbol: undefined +# CHECK-NEXT: {{.*}}.o:(.text+0x1) +# CHECK-NOT: warning: +# CHECK-NOT: error: + +.globl _start +_start: + callq undefined + +.section .debug_line,"",@progbits diff --git a/test/ELF/no-line-parser-errors-if-no-section.s b/test/ELF/no-line-parser-errors-if-no-section.s new file mode 100644 index 000000000000..4624601315d6 --- /dev/null +++ b/test/ELF/no-line-parser-errors-if-no-section.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# LLD uses the debug data to get information for error messages, if possible. +# However, if there is no debug line section, we should not attempt to parse +# it, as that would result in errors from the parser. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK-NOT: warning: +# CHECK-NOT: error: +# CHECK: error: undefined symbol: undefined +# CHECK-NEXT: {{.*}}.o:(.text+0x1) +# CHECK-NOT: warning: +# CHECK-NOT: error: + +.globl _start +_start: + callq undefined diff --git a/test/ELF/no-obj.s b/test/ELF/no-obj.s index 693cdf1e9d3f..1a4bf98c181e 100644 --- a/test/ELF/no-obj.s +++ b/test/ELF/no-obj.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-ar rcs %t.a %t.o -// RUN: not ld.lld -o %t2 -u _start %t.a 2>&1 | FileCheck %s +// RUN: not ld.lld -o /dev/null -u _start %t.a 2>&1 | FileCheck %s // CHECK: target emulation unknown: -m or at least one .o file required diff --git a/test/ELF/no-symtab.s b/test/ELF/no-symtab.s index af9df13e9768..2468c4f05fc4 100644 --- a/test/ELF/no-symtab.s +++ b/test/ELF/no-symtab.s @@ -1,5 +1,5 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: ld.lld %t.o %p/Inputs/no-symtab.o -o %t +// RUN: ld.lld %t.o %p/Inputs/no-symtab.o -o /dev/null .global _start _start: diff --git a/test/ELF/no-undefined.s b/test/ELF/no-undefined.s index 493a38987091..854114b6a072 100644 --- a/test/ELF/no-undefined.s +++ b/test/ELF/no-undefined.s @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: not ld.lld --no-undefined -shared %t -o %t.so -# RUN: ld.lld -shared %t -o %t1.so +# RUN: not ld.lld --no-undefined -shared %t -o /dev/null +# RUN: ld.lld -shared %t -o /dev/null .globl _shared _shared: diff --git a/test/ELF/non-abs-reloc.s b/test/ELF/non-abs-reloc.s index 454104cca076..ac69915b1b53 100644 --- a/test/ELF/non-abs-reloc.s +++ b/test/ELF/non-abs-reloc.s @@ -1,11 +1,21 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s -// CHECK: {{.*}}:(.dummy+0x0): has non-ABS relocation R_X86_64_GOTPCREL against symbol 'foo' +// RUN: ld.lld %t.o -o %t 2>&1 | FileCheck %s +// CHECK: (.nonalloc+0x1): has non-ABS relocation R_X86_64_PC32 against symbol '_start' +// CHECK: (.nonalloc+0x6): has non-ABS relocation R_X86_64_PC32 against symbol '_start' + +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=DISASM %s +// DISASM: Disassembly of section .nonalloc: +// DISASM-NEXT: .nonalloc: +// DISASM-NEXT: 0: {{.*}} callq {{.*}} <_start> +// DISASM-NEXT: 5: {{.*}} callq {{.*}} <_start> .globl _start _start: nop -.section .dummy - .long foo@gotpcrel +.section .nonalloc + .byte 0xe8 + .long _start - . - 4 + .byte 0xe8 + .long _start - . - 4 diff --git a/test/ELF/non-alloc-link-order-gc.s b/test/ELF/non-alloc-link-order-gc.s new file mode 100644 index 000000000000..8147c45090d9 --- /dev/null +++ b/test/ELF/non-alloc-link-order-gc.s @@ -0,0 +1,34 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t1 --gc-sections +# RUN: llvm-objdump -section-headers -D %t1 | FileCheck %s + +## Check that we are able to GC non-allocatable metadata sections without crash. + +# CHECK: Disassembly of section .stack_sizes: +# CHECK-NEXT: .stack_sizes: +# CHECK-NEXT: 01 + +# CHECK: Name Size +# CHECK: .stack_sizes 00000001 + +.section .text.live,"ax",@progbits +.globl live +live: + nop + +.section .stack_sizes,"o",@progbits,.text.live,unique,0 +.byte 1 + +.section .text.dead,"ax",@progbits +.globl dead +dead: + nop + +.section .stack_sizes,"o",@progbits,.text.dead,unique,1 +.byte 2 + +.section .text.main,"ax",@progbits +.globl _start +_start: + callq live@PLT diff --git a/test/ELF/note-contiguous.s b/test/ELF/note-contiguous.s index f49d0b68ca33..7b04e9849320 100644 --- a/test/ELF/note-contiguous.s +++ b/test/ELF/note-contiguous.s @@ -1,24 +1,42 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: echo "SECTIONS { \ -// RUN: .note : { *(.note.a) *(.note.b) } \ -// RUN: }" > %t.script -// RUN: ld.lld %t.o --script %t.script -o %t -// RUN: llvm-readobj -program-headers %t | FileCheck %s + +// RUN: ld.lld %t.o -o %t1 +// RUN: llvm-readobj -program-headers %t1 | FileCheck %s // CHECK: Type: PT_NOTE -// CHECK-NEXT: Offset: 0x1000 -// CHECK-NEXT: VirtualAddress: 0x0 -// CHECK-NEXT: PhysicalAddress: 0x0 +// CHECK-NEXT: Offset: +// CHECK-NEXT: VirtualAddress: +// CHECK-NEXT: PhysicalAddress: // CHECK-NEXT: FileSize: 16 // CHECK-NEXT: MemSize: 16 -// CHECK-NEXT: Flags [ +// CHECK-NEXT: Flags [ // CHECK-NEXT: PF_R // CHECK-NEXT: ] // CHECK-NEXT: Alignment: 1 +// CHECK-NOT: Type: PT_NOTE + +// RUN: echo "SECTIONS { .note : { *(.note.a) *(.note.b) } }" > %t.script +// RUN: ld.lld %t.o --script %t.script -o %t2 +// RUN: llvm-readobj -program-headers %t2 | FileCheck -check-prefix=SCRIPT %s + +// SCRIPT: Type: PT_NOTE +// SCRIPT-NEXT: Offset: +// SCRIPT-NEXT: VirtualAddress: +// SCRIPT-NEXT: PhysicalAddress: +// SCRIPT-NEXT: FileSize: 16 +// SCRIPT-NEXT: MemSize: 16 +// SCRIPT-NEXT: Flags [ +// SCRIPT-NEXT: PF_R +// SCRIPT-NEXT: ] +// SCRIPT-NEXT: Alignment: 1 +// SCRIPT-NOT: Type: PT_NOTE .section .note.a, "a", @note .quad 0 +.section .foo, "a" +.quad 0 + .section .note.b, "a", @note .quad 0 diff --git a/test/ELF/note-loadaddr.c b/test/ELF/note-loadaddr.s index 6d2ebaeeaa0a..6d2ebaeeaa0a 100644 --- a/test/ELF/note-loadaddr.c +++ b/test/ELF/note-loadaddr.s diff --git a/test/ELF/note-noalloc.s b/test/ELF/note-noalloc.s new file mode 100644 index 000000000000..80c7a4d23a03 --- /dev/null +++ b/test/ELF/note-noalloc.s @@ -0,0 +1,38 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t -shared +// RUN: llvm-readobj -program-headers -sections %t | FileCheck %s + +// PR37361: A note without SHF_ALLOC should not be included into a PT_NOTE program header. + +// CHECK: Section { +// CHECK: Index: +// CHECK: Name: .note.a +// CHECK-NEXT: Type: SHT_NOTE +// CHECK-NEXT: Flags [ +// CHECK-NEXT: SHF_ALLOC +// CHECK-NEXT: ] +// CHECK-NEXT: Address: 0x[[ADDR:.*]] + +// Check we still emit the non-alloc SHT_NOTE section and keep its type. + +// CHECK: Name: .note.b +// CHECK-NEXT: Type: SHT_NOTE +// CHECK-NEXT: Flags [ +// CHECK-NEXT: ] + +// CHECK: ProgramHeader { +// CHECK: Type: PT_NOTE +// CHECK-NEXT: Offset: +// CHECK-NEXT: VirtualAddress: 0x[[ADDR]] +// CHECK-NEXT: PhysicalAddress: 0x[[ADDR]] +// CHECK-NEXT: FileSize: 16 +// CHECK-NEXT: MemSize: 16 +// CHECK-NOT: PT_NOTE + +.section .note.a,"a",@note +.quad 1 +.quad 2 + +.section .note.b,"",@note +.quad 3 diff --git a/test/ELF/note-noalloc2.s b/test/ELF/note-noalloc2.s new file mode 100644 index 000000000000..3705799d45cb --- /dev/null +++ b/test/ELF/note-noalloc2.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: llvm-readobj -program-headers %t | FileCheck %s + +## Check we do not create a PT_NOTE segment for non-allocatable note section. + +# CHECK-NOT: PT_NOTE + +.section .note,"",@note +.quad 0 diff --git a/test/ELF/oformat-binary.s b/test/ELF/oformat-binary.s index acd95c7cef36..44c7b5ac2d8d 100644 --- a/test/ELF/oformat-binary.s +++ b/test/ELF/oformat-binary.s @@ -15,7 +15,7 @@ # RUN: ld.lld -o %t2.out --script %t.script %t --oformat binary # RUN: od -t x1 -v %t2.out | FileCheck %s -# RUN: not ld.lld -o %t3.out %t --oformat foo 2>&1 \ +# RUN: not ld.lld -o /dev/null %t --oformat foo 2>&1 \ # RUN: | FileCheck %s --check-prefix ERR # ERR: unknown --oformat value: foo diff --git a/test/ELF/output-section.s b/test/ELF/output-section.s index 68505254686c..2a119d998218 100644 --- a/test/ELF/output-section.s +++ b/test/ELF/output-section.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-readobj -t %t2 | FileCheck %s -// REQUIRES: x86 // CHECK: Symbol { // CHECK: Name: bar_sym diff --git a/test/ELF/pack-dyn-relocs.s b/test/ELF/pack-dyn-relocs.s index cb8674318ec6..b37729dd890b 100644 --- a/test/ELF/pack-dyn-relocs.s +++ b/test/ELF/pack-dyn-relocs.s @@ -5,12 +5,10 @@ // RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.a32 // RUN: ld.lld -pie --pack-dyn-relocs=none %t.a32 %t.a32.so -o %t2.a32 // RUN: llvm-readobj -relocations %t2.a32 | FileCheck --check-prefix=UNPACKED32 %s -// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a32 %t.a32.so -o %t3.a32 -// RUN: llvm-readobj -s -dynamic-table %t3.a32 | FileCheck --check-prefix=PACKED32-HEADERS %s -// RUN: llvm-readobj -relocations %t3.a32 | FileCheck --check-prefix=PACKED32 %s // Unpacked should have the relative relocations in their natural order. -// UNPACKED32: 0x1000 R_ARM_RELATIVE - 0x0 +// UNPACKED32: Section ({{.+}}) .rel.dyn { +// UNPACKED32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 // UNPACKED32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 // UNPACKED32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 // UNPACKED32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 @@ -37,70 +35,146 @@ // UNPACKED32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 // UNPACKED32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 +// UNPACKED32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0 // UNPACKED32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 // UNPACKED32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 +// UNPACKED32-NEXT: } + +// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a32 %t.a32.so -o %t3.a32 +// RUN: llvm-readobj -s -dynamic-table %t3.a32 | FileCheck --check-prefix=ANDROID32-HEADERS %s +// RUN: llvm-readobj -relocations %t3.a32 | FileCheck --check-prefix=ANDROID32 %s + +// ANDROID32-HEADERS: Index: 1 +// ANDROID32-HEADERS-NEXT: Name: .dynsym + +// ANDROID32-HEADERS: Name: .rel.dyn +// ANDROID32-HEADERS-NEXT: Type: SHT_ANDROID_REL +// ANDROID32-HEADERS-NEXT: Flags [ (0x2) +// ANDROID32-HEADERS-NEXT: SHF_ALLOC (0x2) +// ANDROID32-HEADERS-NEXT: ] +// ANDROID32-HEADERS-NEXT: Address: [[ADDR:.*]] +// ANDROID32-HEADERS-NEXT: Offset: [[ADDR]] +// ANDROID32-HEADERS-NEXT: Size: [[SIZE:.*]] +// ANDROID32-HEADERS-NEXT: Link: 1 +// ANDROID32-HEADERS-NEXT: Info: 0 +// ANDROID32-HEADERS-NEXT: AddressAlignment: 4 +// ANDROID32-HEADERS-NEXT: EntrySize: 1 -// PACKED32-HEADERS: Index: 1 -// PACKED32-HEADERS-NEXT: Name: .dynsym - -// PACKED32-HEADERS: Name: .rel.dyn -// PACKED32-HEADERS-NEXT: Type: SHT_ANDROID_REL -// PACKED32-HEADERS-NEXT: Flags [ (0x2) -// PACKED32-HEADERS-NEXT: SHF_ALLOC (0x2) -// PACKED32-HEADERS-NEXT: ] -// PACKED32-HEADERS-NEXT: Address: [[ADDR:.*]] -// PACKED32-HEADERS-NEXT: Offset: [[ADDR]] -// PACKED32-HEADERS-NEXT: Size: [[SIZE:.*]] -// PACKED32-HEADERS-NEXT: Link: 1 -// PACKED32-HEADERS-NEXT: Info: 0 -// PACKED32-HEADERS-NEXT: AddressAlignment: 4 -// PACKED32-HEADERS-NEXT: EntrySize: 1 - -// PACKED32-HEADERS: 0x6000000F ANDROID_REL [[ADDR]] -// PACKED32-HEADERS: 0x60000010 ANDROID_RELSZ [[SIZE]] +// ANDROID32-HEADERS: 0x6000000F ANDROID_REL [[ADDR]] +// ANDROID32-HEADERS: 0x60000010 ANDROID_RELSZ [[SIZE]] // Packed should have the larger groups of relative relocations first, // i.e. the 8 and 9 followed by the 7. -// PACKED32: 0x1000 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 - -// PACKED32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 - -// PACKED32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 -// PACKED32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 - -// PACKED32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 -// PACKED32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 +// ANDROID32: Section ({{.+}}) .rel.dyn { +// ANDROID32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 + +// ANDROID32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 + +// ANDROID32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 + +// ANDROID32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0 +// ANDROID32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 +// ANDROID32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 +// ANDROID32-NEXT: } + +// RUN: ld.lld -pie --pack-dyn-relocs=relr %t.a32 %t.a32.so -o %t4.a32 +// RUN: llvm-readobj -s -dynamic-table %t4.a32 | FileCheck --check-prefix=RELR32-HEADERS %s +// RUN: llvm-readobj -relocations -raw-relr %t4.a32 | FileCheck --check-prefix=RAW-RELR32 %s +// RUN: llvm-readobj -relocations %t4.a32 | FileCheck --check-prefix=RELR32 %s + +// RELR32-HEADERS: Index: 1 +// RELR32-HEADERS-NEXT: Name: .dynsym + +// RELR32-HEADERS: Name: .relr.dyn +// RELR32-HEADERS-NEXT: Type: SHT_RELR +// RELR32-HEADERS-NEXT: Flags [ (0x2) +// RELR32-HEADERS-NEXT: SHF_ALLOC (0x2) +// RELR32-HEADERS-NEXT: ] +// RELR32-HEADERS-NEXT: Address: [[ADDR:.*]] +// RELR32-HEADERS-NEXT: Offset: [[ADDR]] +// RELR32-HEADERS-NEXT: Size: 8 +// RELR32-HEADERS-NEXT: Link: 0 +// RELR32-HEADERS-NEXT: Info: 0 +// RELR32-HEADERS-NEXT: AddressAlignment: 4 +// RELR32-HEADERS-NEXT: EntrySize: 4 + +// RELR32-HEADERS: 0x00000024 RELR [[ADDR]] +// RELR32-HEADERS: 0x00000023 RELRSZ 0x8 +// RELR32-HEADERS: 0x00000025 RELRENT 0x4 + +// SHT_RELR section contains address/bitmap entries +// encoding the offsets for relative relocation. +// RAW-RELR32: Section ({{.+}}) .relr.dyn { +// RAW-RELR32-NEXT: 0x1000 +// RAW-RELR32-NEXT: 0x3FEFEFF +// RAW-RELR32-NEXT: } + +// Decoded SHT_RELR section is same as UNPACKED, +// but contains only the relative relocations. +// Any relative relocations with odd offset stay in SHT_REL. +// RELR32: Section ({{.+}}) .rel.dyn { +// RELR32-NEXT: 0x1069 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1020 R_ARM_ABS32 bar2 0x0 +// RELR32-NEXT: 0x1040 R_ARM_ABS32 zed2 0x0 +// RELR32-NEXT: } +// RELR32-NEXT: Section ({{.+}}) .relr.dyn { +// RELR32-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x100C R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x101C R_ARM_RELATIVE - 0x0 + +// RELR32-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x102C R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x103C R_ARM_RELATIVE - 0x0 + +// RELR32-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x104C R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x105C R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 +// RELR32-NEXT: } // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %p/Inputs/shared2.s -o %t.a64.so.o // RUN: ld.lld -shared %t.a64.so.o -o %t.a64.so // RUN: llvm-mc -filetype=obj -triple=aarch64-unknown-linux %s -o %t.a64 // RUN: ld.lld -pie --pack-dyn-relocs=none %t.a64 %t.a64.so -o %t2.a64 // RUN: llvm-readobj -relocations %t2.a64 | FileCheck --check-prefix=UNPACKED64 %s -// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a64 %t.a64.so -o %t3.a64 -// RUN: llvm-readobj -s -dynamic-table %t3.a64 | FileCheck --check-prefix=PACKED64-HEADERS %s -// RUN: llvm-readobj -relocations %t3.a64 | FileCheck --check-prefix=PACKED64 %s -// UNPACKED64: 0x10000 R_AARCH64_RELATIVE - 0x1 +// UNPACKED64: Section ({{.+}}) .rela.dyn { +// UNPACKED64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x1 // UNPACKED64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2 // UNPACKED64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3 // UNPACKED64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4 @@ -127,59 +201,138 @@ // UNPACKED64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8 // UNPACKED64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9 +// UNPACKED64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA // UNPACKED64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 // UNPACKED64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 +// UNPACKED64-NEXT: } + +// RUN: ld.lld -pie --pack-dyn-relocs=android %t.a64 %t.a64.so -o %t3.a64 +// RUN: llvm-readobj -s -dynamic-table %t3.a64 | FileCheck --check-prefix=ANDROID64-HEADERS %s +// RUN: llvm-readobj -relocations %t3.a64 | FileCheck --check-prefix=ANDROID64 %s + +// ANDROID64-HEADERS: Index: 1 +// ANDROID64-HEADERS-NEXT: Name: .dynsym + +// ANDROID64-HEADERS: Name: .rela.dyn +// ANDROID64-HEADERS-NEXT: Type: SHT_ANDROID_RELA +// ANDROID64-HEADERS-NEXT: Flags [ (0x2) +// ANDROID64-HEADERS-NEXT: SHF_ALLOC (0x2) +// ANDROID64-HEADERS-NEXT: ] +// ANDROID64-HEADERS-NEXT: Address: [[ADDR:.*]] +// ANDROID64-HEADERS-NEXT: Offset: [[ADDR]] +// ANDROID64-HEADERS-NEXT: Size: [[SIZE:.*]] +// ANDROID64-HEADERS-NEXT: Link: 1 +// ANDROID64-HEADERS-NEXT: Info: 0 +// ANDROID64-HEADERS-NEXT: AddressAlignment: 8 +// ANDROID64-HEADERS-NEXT: EntrySize: 1 + +// ANDROID64-HEADERS: 0x0000000060000011 ANDROID_RELA [[ADDR]] +// ANDROID64-HEADERS: 0x0000000060000012 ANDROID_RELASZ [[SIZE]] + +// ANDROID64: Section ({{.+}}) .rela.dyn { +// ANDROID64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x1 +// ANDROID64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2 +// ANDROID64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3 +// ANDROID64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4 +// ANDROID64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5 +// ANDROID64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6 +// ANDROID64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7 +// ANDROID64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8 + +// ANDROID64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1 +// ANDROID64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2 +// ANDROID64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3 +// ANDROID64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4 +// ANDROID64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5 +// ANDROID64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6 +// ANDROID64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7 +// ANDROID64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8 +// ANDROID64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9 + +// ANDROID64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1 +// ANDROID64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2 +// ANDROID64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3 +// ANDROID64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4 +// ANDROID64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5 +// ANDROID64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6 +// ANDROID64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7 + +// ANDROID64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA +// ANDROID64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 +// ANDROID64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 +// ANDROID64-NEXT: } + +// RUN: ld.lld -pie --pack-dyn-relocs=relr %t.a64 %t.a64.so -o %t4.a64 +// RUN: llvm-readobj -s -dynamic-table %t4.a64 | FileCheck --check-prefix=RELR64-HEADERS %s +// RUN: llvm-readobj -relocations -raw-relr %t4.a64 | FileCheck --check-prefix=RAW-RELR64 %s +// RUN: llvm-readobj -relocations %t4.a64 | FileCheck --check-prefix=RELR64 %s + +// RELR64-HEADERS: Index: 1 +// RELR64-HEADERS-NEXT: Name: .dynsym + +// RELR64-HEADERS: Name: .relr.dyn +// RELR64-HEADERS-NEXT: Type: SHT_RELR +// RELR64-HEADERS-NEXT: Flags [ (0x2) +// RELR64-HEADERS-NEXT: SHF_ALLOC (0x2) +// RELR64-HEADERS-NEXT: ] +// RELR64-HEADERS-NEXT: Address: [[ADDR:.*]] +// RELR64-HEADERS-NEXT: Offset: [[ADDR]] +// RELR64-HEADERS-NEXT: Size: 16 +// RELR64-HEADERS-NEXT: Link: 0 +// RELR64-HEADERS-NEXT: Info: 0 +// RELR64-HEADERS-NEXT: AddressAlignment: 8 +// RELR64-HEADERS-NEXT: EntrySize: 8 + +// RELR64-HEADERS: 0x0000000000000024 RELR [[ADDR]] +// RELR64-HEADERS: 0x0000000000000023 RELRSZ 0x10 +// RELR64-HEADERS: 0x0000000000000025 RELRENT 0x8 + +// SHT_RELR section contains address/bitmap entries +// encoding the offsets for relative relocation. +// RAW-RELR64: Section ({{.+}}) .relr.dyn { +// RAW-RELR64-NEXT: 0x10000 +// RAW-RELR64-NEXT: 0x3FEFEFF +// RAW-RELR64-NEXT: } + +// Decoded SHT_RELR section is same as UNPACKED, +// but contains only the relative relocations. +// Any relative relocations with odd offset stay in SHT_RELA. +// RELR64: Section ({{.+}}) .rela.dyn { +// RELR64-NEXT: 0x100D1 R_AARCH64_RELATIVE - 0xA +// RELR64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 +// RELR64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 +// RELR64-NEXT: } +// RELR64-NEXT: Section ({{.+}}) .relr.dyn { +// RELR64-NEXT: 0x10000 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x0 + +// RELR64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x0 -// PACKED64: 0x10000 R_AARCH64_RELATIVE - 0x1 -// PACKED64-NEXT: 0x10008 R_AARCH64_RELATIVE - 0x2 -// PACKED64-NEXT: 0x10010 R_AARCH64_RELATIVE - 0x3 -// PACKED64-NEXT: 0x10018 R_AARCH64_RELATIVE - 0x4 -// PACKED64-NEXT: 0x10020 R_AARCH64_RELATIVE - 0x5 -// PACKED64-NEXT: 0x10028 R_AARCH64_RELATIVE - 0x6 -// PACKED64-NEXT: 0x10030 R_AARCH64_RELATIVE - 0x7 -// PACKED64-NEXT: 0x10038 R_AARCH64_RELATIVE - 0x8 - -// PACKED64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x1 -// PACKED64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x2 -// PACKED64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x3 -// PACKED64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x4 -// PACKED64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x5 -// PACKED64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x6 -// PACKED64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x7 -// PACKED64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x8 -// PACKED64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x9 - -// PACKED64-NEXT: 0x10048 R_AARCH64_RELATIVE - 0x1 -// PACKED64-NEXT: 0x10050 R_AARCH64_RELATIVE - 0x2 -// PACKED64-NEXT: 0x10058 R_AARCH64_RELATIVE - 0x3 -// PACKED64-NEXT: 0x10060 R_AARCH64_RELATIVE - 0x4 -// PACKED64-NEXT: 0x10068 R_AARCH64_RELATIVE - 0x5 -// PACKED64-NEXT: 0x10070 R_AARCH64_RELATIVE - 0x6 -// PACKED64-NEXT: 0x10078 R_AARCH64_RELATIVE - 0x7 - -// PACKED64-NEXT: 0x10040 R_AARCH64_ABS64 bar2 0x1 -// PACKED64-NEXT: 0x10080 R_AARCH64_ABS64 zed2 0x0 - -// PACKED64-HEADERS: Index: 1 -// PACKED64-HEADERS-NEXT: Name: .dynsym - -// PACKED64-HEADERS: Name: .rela.dyn -// PACKED64-HEADERS-NEXT: Type: SHT_ANDROID_RELA -// PACKED64-HEADERS-NEXT: Flags [ (0x2) -// PACKED64-HEADERS-NEXT: SHF_ALLOC (0x2) -// PACKED64-HEADERS-NEXT: ] -// PACKED64-HEADERS-NEXT: Address: [[ADDR:.*]] -// PACKED64-HEADERS-NEXT: Offset: [[ADDR]] -// PACKED64-HEADERS-NEXT: Size: [[SIZE:.*]] -// PACKED64-HEADERS-NEXT: Link: 1 -// PACKED64-HEADERS-NEXT: Info: 0 -// PACKED64-HEADERS-NEXT: AddressAlignment: 8 -// PACKED64-HEADERS-NEXT: EntrySize: 1 - -// PACKED64-HEADERS: 0x0000000060000011 ANDROID_RELA [[ADDR]] -// PACKED64-HEADERS: 0x0000000060000012 ANDROID_RELASZ [[SIZE]] +// RELR64-NEXT: 0x10088 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10090 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x10098 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x100A0 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x100A8 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x100B0 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x100B8 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x100C0 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: 0x100C8 R_AARCH64_RELATIVE - 0x0 +// RELR64-NEXT: } .data +.align 2 .dc.a __ehdr_start + 1 .dc.a __ehdr_start + 2 .dc.a __ehdr_start + 3 @@ -208,3 +361,5 @@ .dc.a __ehdr_start + 7 .dc.a __ehdr_start + 8 .dc.a __ehdr_start + 9 +.byte 00 +.dc.a __ehdr_start + 10 diff --git a/test/ELF/pack-dyn-relocs2.s b/test/ELF/pack-dyn-relocs2.s new file mode 100644 index 000000000000..20c7176a6061 --- /dev/null +++ b/test/ELF/pack-dyn-relocs2.s @@ -0,0 +1,85 @@ +// REQUIRES: arm, aarch64 + +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %p/Inputs/arm-shared.s -o %t.so.o +// RUN: ld.lld -shared %t.so.o -o %t.so + +// RUN: llvm-mc -filetype=obj -triple=armv7a-none-linux-gnueabi %s -o %t.o +// RUN: ld.lld -pie --pack-dyn-relocs=relr %t.o %t.so -o %t.exe +// RUN: llvm-readobj -relocations %t.exe | FileCheck %s + +// CHECK: Section (5) .relr.dyn { +// CHECK-NEXT: 0x1000 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1004 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1008 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x100C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1010 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1014 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1018 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x101C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1020 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1024 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1028 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x102C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1030 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1034 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1038 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x103C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1040 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1044 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1048 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x104C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1050 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1054 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1058 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x105C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1060 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1064 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1068 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x106C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1070 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1074 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1078 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x107C R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1080 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: 0x1084 R_ARM_RELATIVE - 0x0 +// CHECK-NEXT: } + +// RUN: llvm-readobj -s -dynamic-table %t.exe | FileCheck --check-prefix=HEADER %s +// HEADER: 0x00000023 RELRSZ 0xC + +.data +.align 2 +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start +.dc.a __ehdr_start diff --git a/test/ELF/pie.s b/test/ELF/pie.s index 5964db5c9399..ccab1623cd5c 100644 --- a/test/ELF/pie.s +++ b/test/ELF/pie.s @@ -48,7 +48,9 @@ # CHECK: Type: PT_DYNAMIC ## Check -nopie -# RUN: ld.lld -nopie %t1.o -o %t2 +# RUN: ld.lld -no-pie %t1.o -o %t2 +# RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE +# RUN: ld.lld -no-pic-executable %t1.o -o %t2 # RUN: llvm-readobj -file-headers -r %t2 | FileCheck %s --check-prefix=NOPIE # NOPIE-NOT: Type: SharedObject diff --git a/test/ELF/plt-aarch64.s b/test/ELF/plt-aarch64.s index 372186b4b1f4..8f637bf593f4 100644 --- a/test/ELF/plt-aarch64.s +++ b/test/ELF/plt-aarch64.s @@ -1,3 +1,4 @@ +// REQUIRES: aarch64 // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=aarch64-pc-freebsd %p/Inputs/plt-aarch64.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so @@ -10,8 +11,6 @@ // RUN: llvm-objdump -s -section=.got.plt %t.exe | FileCheck --check-prefix=DUMPEXE %s // RUN: llvm-objdump -d %t.exe | FileCheck --check-prefix=DISASMEXE %s -// REQUIRES: aarch64 - // CHECKDSO: Name: .plt // CHECKDSO-NEXT: Type: SHT_PROGBITS // CHECKDSO-NEXT: Flags [ diff --git a/test/ELF/plt-i686.s b/test/ELF/plt-i686.s index 9a2c7f53dc59..c24cab20e769 100644 --- a/test/ELF/plt-i686.s +++ b/test/ELF/plt-i686.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so @@ -9,7 +10,6 @@ // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMSHARED %s // RUN: ld.lld -pie %t.o %t2.so -o %t // RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASMPIE %s -// REQUIRES: x86 // CHECK: Name: .plt // CHECK-NEXT: Type: SHT_PROGBITS diff --git a/test/ELF/plt.s b/test/ELF/plt.s index 4ab81aaaed91..cce60d732063 100644 --- a/test/ELF/plt.s +++ b/test/ELF/plt.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so @@ -8,8 +9,6 @@ // RUN: llvm-readobj -s -r %t3 | FileCheck --check-prefix=CHECK2 %s // RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=DISASM2 %s -// REQUIRES: x86 - // CHECK: Name: .plt // CHECK-NEXT: Type: SHT_PROGBITS // CHECK-NEXT: Flags [ diff --git a/test/ELF/ppc-rela.s b/test/ELF/ppc-rela.s new file mode 100644 index 000000000000..430c5a748181 --- /dev/null +++ b/test/ELF/ppc-rela.s @@ -0,0 +1,11 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t +# RUN: ld.lld %t -o %t2 -shared +# RUN: llvm-readobj -r %t2 | FileCheck %s + +.data + .long foo + +// CHECK: Section ({{.*}}) .rela.dyn { +// CHECK-NEXT: 0x1000 R_PPC_ADDR32 foo 0x0 +// CHECK-NEXT: } diff --git a/test/ELF/ppc-relocs.s b/test/ELF/ppc-relocs.s index 5aa3474e6339..26810008bd12 100644 --- a/test/ELF/ppc-relocs.s +++ b/test/ELF/ppc-relocs.s @@ -1,7 +1,7 @@ +# REQUIRES: ppc # RUN: llvm-mc -filetype=obj -triple=powerpc-unknown-freebsd %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-objdump -d %t2 | FileCheck %s -# REQUIRES: ppc .section .R_PPC_ADDR16_HA,"ax",@progbits .globl _start diff --git a/test/ELF/ppc64-abi-version.s b/test/ELF/ppc64-abi-version.s new file mode 100644 index 000000000000..806a71ed8fa1 --- /dev/null +++ b/test/ELF/ppc64-abi-version.s @@ -0,0 +1,11 @@ +# REQUIRES: ppc + +# RUN: echo '.abiversion 1' | llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux - -o %t1.o +# RUN: not ld.lld -o /dev/null %t1.o 2>&1 | FileCheck -check-prefix=ERR1 %s + +# ERR1: ABI version 1 is not supported + +# RUN: echo '.abiversion 3' | llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux - -o %t1.o +# RUN: not ld.lld -o /dev/null %t1.o 2>&1 | FileCheck -check-prefix=ERR2 %s + +# ERR2: unrecognized e_flags: 3 diff --git a/test/ELF/ppc64-addr16-error.s b/test/ELF/ppc64-addr16-error.s index f16ca69957a3..5ffca587d6e5 100644 --- a/test/ELF/ppc64-addr16-error.s +++ b/test/ELF/ppc64-addr16-error.s @@ -1,7 +1,12 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2 +// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck %s + // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-addr16-error.s -o %t2 -// RUN: not ld.lld -shared %t %t2 -o %t3 2>&1 | FileCheck %s -// REQUIRES: ppc +// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck %s .short sym+65539 diff --git a/test/ELF/ppc64-dtprel.s b/test/ELF/ppc64-dtprel.s new file mode 100644 index 000000000000..43922fa80382 --- /dev/null +++ b/test/ELF/ppc64-dtprel.s @@ -0,0 +1,204 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisLE %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=GotDisBE %s + + .text + .abiversion 2 + .globl test + .p2align 4 + .type test,@function +test: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry test, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + addis 3, 2, i@got@tlsld@ha + addi 3, 3, i@got@tlsld@l + bl __tls_get_addr(i@tlsld) + nop + addi 4, 3, i@dtprel + lwa 4, i@dtprel(3) + ld 0, 16(1) + mtlr 0 + blr + + .globl test_64 + .p2align 4 + .type test_64,@function + + .globl test_adjusted + .p2align 4 + .type test_adjusted,@function +test_adjusted: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry test_adjusted, .Lfunc_lep1-.Lfunc_gep1 + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + addis 3, 2, k@got@tlsld@ha + addi 3, 3, k@got@tlsld@l + bl __tls_get_addr(k@tlsld) + nop + lis 4, k@dtprel@highesta + ori 4, 4, k@dtprel@highera + lis 5, k@dtprel@ha + addi 5, 5, k@dtprel@l + sldi 4, 4, 32 + or 4, 4, 5 + add 3, 3, 4 + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + + .globl test_not_adjusted + .p2align 4 + .type test_not_adjusted,@function +test_not_adjusted: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry test_not_adjusted, .Lfunc_lep2-.Lfunc_gep2 + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + addis 3, 2, i@got@tlsld@ha + addi 3, 3, i@got@tlsld@l + bl __tls_get_addr(k@tlsld) + nop + lis 4, k@dtprel@highest + ori 4, 4, k@dtprel@higher + sldi 4, 4, 32 + oris 4, 4, k@dtprel@h + ori 4, 4, k@dtprel@l + add 3, 3, 4 + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + + .globl test_got_dtprel + .p2align 4 + .type test_got_dtprel,@function +test_got_dtprel: + addis 3, 2, i@got@dtprel@ha + ld 3, i@got@dtprel@l(3) + addis 3, 2, i@got@dtprel@h + addi 3, 2, i@got@dtprel + + .section .debug_addr,"",@progbits + .quad i@dtprel+32768 + + .type i,@object + .section .tdata,"awT",@progbits + .space 1024 + .p2align 2 +i: + .long 55 + .size i, 4 + + .space 1024 * 1024 * 4 + .type k,@object + .p2align 2 +k: + .long 128 + .size k,4 + +// Verify the input has all the remaining DTPREL based relocations we want to +// test. +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_DTPREL16 {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_DTPREL16_DS {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_DTPREL16_HIGHESTA {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_DTPREL16_HIGHERA {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_DTPREL16_HA {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_DTPREL16_LO {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_DTPREL16_HIGHEST {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_DTPREL16_HIGHER {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_DTPREL16_HI {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_DTPREL16_LO {{[0-9a-f]+}} k + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_HA {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_LO_DS {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_HI {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_DTPREL16_DS {{[0-9a-f]+}} i + 0 +// InputRelocs: Relocation section '.rela.debug_addr' +// InputRelocs: R_PPC64_DTPREL64 {{[0-9a-f]+}} i + 8000 + +// Expect a single dynamic relocation in the '.rela.dyn section for the module id. +// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 1 entries: +// OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +// OutputRelocs-NEXT: R_PPC64_DTPMOD64 + + +// i@dtprel --> (1024 - 0x8000) = -31744 +// Dis: test: +// Dis: addi 4, 3, -31744 +// Dis: lwa 4, -31744(3) + +// #k@dtprel(1024 + 4 + 1024 * 1024 * 4) = 0x400404 + +// #highesta(k@dtprel) --> ((0x400404 - 0x8000 + 0x8000) >> 48) & 0xffff = 0 +// #highera(k@dtprel) --> ((0x400404 - 0x8000 + 0x8000) >> 32) & 0xffff = 0 +// #ha(k@dtprel) --> ((0x400404 - 0x8000 + 0x8000) >> 16) & 0xffff = 64 +// #lo(k@dtprel) --> ((0x400404 - 0x8000) & 0xffff = -31740 +// Dis: test_adjusted: +// Dis: lis 4, 0 +// Dis: ori 4, 4, 0 +// Dis: lis 5, 64 +// Dis: addi 5, 5, -31740 + +// #highest(k@dtprel) --> ((0x400404 - 0x8000) >> 48) & 0xffff = 0 +// #higher(k@dtprel) --> ((0x400404 - 0x8000) >> 32) & 0xffff = 0 +// #hi(k@dtprel) --> ((0x400404 - 0x8000) >> 16) & 0xffff = 63 +// #lo(k@dtprel) --> ((0x400404 - 0x8000) & 0xffff = 33796 +// Dis: test_not_adjusted: +// Dis: lis 4, 0 +// Dis: ori 4, 4, 0 +// Dis: oris 4, 4, 63 +// Dis: ori 4, 4, 33796 + +// Check for GOT entry for i. There should be a got entry which holds the offset +// of i relative to the dynamic thread pointer. +// i@dtprel -> (1024 - 0x8000) = 0xffff8400 +// GotDisBE: Disassembly of section .got: +// GotDisBE: 4204f8: 00 00 00 00 +// GotDisBE: 4204fc: 00 42 84 f8 +// GotDisBE: 420510: ff ff ff ff +// GotDisBE: 420514: ff ff 84 00 + +// GotDisLE: Disassembly of section .got: +// GotDisLE: 4204f8: f8 84 42 00 +// GotDisLE: 420510: 00 84 ff ff +// GotDisLE: 420514: ff ff ff ff + +// Check that we have the correct offset to the got entry for i@got@dtprel +// The got entry for i is 0x420510, and the TOC pointer is 0x4284f8. +// #ha(i@got@dtprel) --> ((0x420510 - 0x4284f8 + 0x8000) >> 16) & 0xffff = 0 +// #lo(i@got@dtprel) --> (0x420510 - 0x4284f8) & 0xffff = -32744 +// #hi(i@got@dtprel) --> ((0x420510 - 0x4284f8) >> 16) & 0xffff = -1 +// i@got@dtprel --> 0x420510 - 0x4284f8 = -32744 +// Dis: test_got_dtprel: +// Dis: addis 3, 2, 0 +// Dis: ld 3, -32744(3) +// Dis: addis 3, 2, -1 +// Dis: addi 3, 2, -32744 diff --git a/test/ELF/ppc64-dynamic-relocations.s b/test/ELF/ppc64-dynamic-relocations.s new file mode 100644 index 000000000000..2d9dfc6f804c --- /dev/null +++ b/test/ELF/ppc64-dynamic-relocations.s @@ -0,0 +1,50 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld %t.o %t2.so -o %t +// RUN: llvm-readobj -dyn-relocations %t | FileCheck %s +// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s +// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld %t.o %t2.so -o %t +// RUN: llvm-readobj -dyn-relocations %t | FileCheck %s +// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s +// RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s + + +// The dynamic relocation for foo should point to 16 bytes past the start of +// the .plt section. +// CHECK: Dynamic Relocations { +// CHECK-NEXT: 0x10030010 R_PPC64_JMP_SLOT foo 0x0 + +// There should be 2 reserved doublewords before the first entry. The dynamic +// linker will fill those in with the address of the resolver entry point and +// the dynamic object identifier. +// DIS: Idx Name Size Address Type +// DIS: .plt 00000018 0000000010030000 BSS + +// DT_PLTGOT should point to the start of the .plt section. +// DT: 0x0000000000000003 PLTGOT 0x10030000 + + .text + .abiversion 2 + .globl _start + .p2align 4 + .type _start,@function +_start: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 + bl foo + nop + li 0, 1 + sc + .size _start, .-.Lfunc_begin0 diff --git a/test/ELF/ppc64-error-toc-restore.s b/test/ELF/ppc64-error-toc-restore.s new file mode 100644 index 000000000000..19153b730ce1 --- /dev/null +++ b/test/ELF/ppc64-error-toc-restore.s @@ -0,0 +1,20 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s + +# Calling external function bar needs a nop +// CHECK: call lacks nop, can't restore toc + .text + .abiversion 2 + +.global _start +_start: + bl foo diff --git a/test/ELF/ppc64-error-toc-tail-call.s b/test/ELF/ppc64-error-toc-tail-call.s new file mode 100644 index 000000000000..da8fea26cc23 --- /dev/null +++ b/test/ELF/ppc64-error-toc-tail-call.s @@ -0,0 +1,20 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck %s + +# A tail call to an external function without a nop should issue an error. +// CHECK: call lacks nop, can't restore toc + .text + .abiversion 2 + +.global _start +_start: + b foo diff --git a/test/ELF/ppc64-func-entry-points.s b/test/ELF/ppc64-func-entry-points.s new file mode 100644 index 000000000000..640c94fe8cfb --- /dev/null +++ b/test/ELF/ppc64-func-entry-points.s @@ -0,0 +1,80 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o +// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t +// RUN: llvm-objdump -d %t | FileCheck %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-local-entry.s -o %t3.o +// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.o %t3.o -o %t +// RUN: llvm-objdump -d %t | FileCheck %s + + .text + .abiversion 2 + .globl _start # -- Begin function _start + .p2align 4 + .type _start,@function +_start: # @_start +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: # %entry + mflr 0 + std 0, 16(1) + stdu 1, -48(1) + li 3, 1 + li 4, 1 + std 30, 32(1) # 8-byte Folded Spill + bl foo_external_same + nop + mr 30, 3 + li 3, 2 + li 4, 2 + bl foo_external_diff + nop + addis 4, 2, .LC0@toc@ha + add 3, 3, 30 + ld 30, 32(1) # 8-byte Folded Reload + ld 4, .LC0@toc@l(4) + lwz 4, 0(4) + add 3, 3, 4 + extsw 3, 3 + addi 1, 1, 48 + ld 0, 16(1) + li 0, 1 + sc + .long 0 + .quad 0 +.Lfunc_end0: + .size _start, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section .toc,"aw",@progbits +.LC0: + .tc glob[TC],glob + .type glob,@object # @glob + .data + .globl glob + .p2align 2 +glob: + .long 10 # 0xa + .size glob, 4 + +# Check that foo_external_diff has a global entry point and we branch to +# foo_external_diff+8. Also check that foo_external_same has no global entry +# point and we branch to start of foo_external_same. + +// CHECK: _start: +// CHECK: 10010020: {{.*}} bl .+144 +// CHECK: 10010034: {{.*}} bl .+84 +// CHECK: foo_external_diff: +// CHECK-NEXT: 10010080: {{.*}} addis 2, 12, 2 +// CHECK-NEXT: 10010084: {{.*}} addi 2, 2, 32640 +// CHECK-NEXT: 10010088: {{.*}} addis 5, 2, 0 +// CHECK: foo_external_same: +// CHECK-NEXT: 100100b0: {{.*}} add 3, 4, 3 diff --git a/test/ELF/ppc64-gd-to-ie.s b/test/ELF/ppc64-gd-to-ie.s new file mode 100644 index 000000000000..1a6cc5b5f2a0 --- /dev/null +++ b/test/ELF/ppc64-gd-to-ie.s @@ -0,0 +1,104 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t3.so +# RUN: ld.lld %t.o %t3.so -o %t +# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s +# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s +# RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t3.so +# RUN: ld.lld %t.o %t3.so -o %t +# RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s +# RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s +# RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s + + .text + .abiversion 2 + .globl _start + .p2align 4 + .type _start,@function +_start: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + addis 3, 2, a@got@tlsgd@ha + addi 3, 3, a@got@tlsgd@l + bl __tls_get_addr(a@tlsgd) + nop + lwa 3, 0(3) + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + + + .globl other_reg + .p2align 4 + .type other_reg,@function +other_reg: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry other_reg, .Lfunc_lep1-.Lfunc_gep1 + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + addis 5, 2, a@got@tlsgd@ha + addi 3, 5, a@got@tlsgd@l + bl __tls_get_addr(a@tlsgd) + nop + lwa 4, 0(3) + addis 30, 2, b@got@tlsgd@ha + addi 3, 30, b@got@tlsgd@l + bl __tls_get_addr(b@tlsgd) + nop + lwa 3, 0(3) + add 3, 4, 3 + addi 1, 1, 32 + ld 0, 16(1) + mtlr 0 + blr + + .globl __tls_get_addr + .type __tls_get_addr,@function +__tls_get_addr: + + +# CheckGot: .got 00000018 00000000100200c0 DATA +# .got is at 0x100200c0 so the toc-base is 100280c0. +# `a` is at .got[1], we expect the offsets to be: +# Ha(a) = ((0x100200c8 - 0x100280c0) + 0x8000) >> 16 = 0 +# Lo(a) = (0x100200c8 - 0x100280c0) = -32760 + +# Dis-LABEL: _start +# Dis: addis 3, 2, 0 +# Dis-NEXT: ld 3, -32760(3) +# Dis-NEXT: nop +# Dis-NEXT: add 3, 3, 13 + +# Dis-LABEL: other_reg +# Dis: addis 5, 2, 0 +# Dis-NEXT: ld 3, -32760(5) +# Dis-NEXT: nop +# Dis-NEXT: add 3, 3, 13 +# Dis: addis 30, 2, 0 +# Dis: ld 3, -32752(30) +# Dis-NEXT: nop +# Dis-NEXT: add 3, 3, 13 + +# Verify that the only dynamic relocations we emit are TPREL ones rather then +# the DTPMOD64/DTPREL64 pair for general-dynamic. +# OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 2 entries: +# OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} a + 0 +# OutputRelocs-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_TPREL64 {{[0-9a-f]+}} b + 0 diff --git a/test/ELF/ppc64-general-dynamic-tls.s b/test/ELF/ppc64-general-dynamic-tls.s new file mode 100644 index 000000000000..66dab936575f --- /dev/null +++ b/test/ELF/ppc64-general-dynamic-tls.s @@ -0,0 +1,112 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s + + .text + .abiversion 2 + .globl test + .p2align 4 + .type test,@function +test: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry test, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + std 31, -8(1) + std 0, 16(1) + stdu 1, -48(1) + mr 31, 1 + std 30, 32(31) + addis 3, 2, i@got@tlsgd@ha + addi 3, 3, i@got@tlsgd@l + bl __tls_get_addr(i@tlsgd) + nop + lwz 30, 0(3) + extsw 3, 30 + ld 30, 32(31) + addi 1, 1, 48 + ld 0, 16(1) + ld 31, -8(1) + mtlr 0 + blr + + +test_hi: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry test2, .Lfunc_lep1-.Lfunc_gep1 + addis 3, 0, j@got@tlsgd@h + blr + +test_16: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry test16, .Lfunc_lep2-.Lfunc_gep2 + addi 3, 0, k@got@tlsgd + blr + +// Verify that the input has every general-dynamic tls relocation type. +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} i + 0 +// InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} i + 0 +// InputRelocs: R_PPC64_TLSGD {{0+}} i + 0 +// InputRelocs: R_PPC64_GOT_TLSGD16_HI {{0+}} j + 0 +// InputRelocs: R_PPC64_GOT_TLSGD16 {{0+}} k + 0 + +// There is 2 got entries for each tls variable that is accessed with the +// general-dynamic model. The entries can be though of as a structure to be +// filled in by the dynamic linker: +// typedef struct { +// unsigned long int ti_module; --> R_PPC64_DTPMOD64 +// unsigned long int ti_offset; --> R_PPC64_DTPREL64 +//} tls_index; +// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 6 entries: +// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} i + 0 +// OutputRelocs: R_PPC64_DTPREL64 {{0+}} i + 0 +// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} j + 0 +// OutputRelocs: R_PPC64_DTPREL64 {{0+}} j + 0 +// OutputRelocs: R_PPC64_DTPMOD64 {{0+}} k + 0 +// OutputRelocs: R_PPC64_DTPREL64 {{0+}} k + 0 + +// Check that the got has 7 entires. (1 for the TOC and 3 structures of +// 2 entries for the tls variables). Also verify the address so we can check +// the offsets we calculated for each relocation type. +// CheckGot: got 00000038 00000000000200f0 + +// got starts at 0x200f0, so .TOC. will be 0x280f0. + +// We are building the address of the first tls_index in the got which starts at +// 0x200f8 (got[1]). +// #ha(i@got@tlsgd) --> (0x200f8 - 0x280f0 + 0x8000) >> 16 = 0 +// #lo(i@got@tlsgd) --> (0x200f8 - 0x280f0) & 0xFFFF = -7ff8 = -32760 +// Dis: test: +// Dis: addis 3, 2, 0 +// Dis: addi 3, 3, -32760 + +// Second tls_index starts at got[3]. +// #hi(j@got@tlsgd) --> (0x20108 - 0x280f0) >> 16 = -1 +// Dis: test_hi: +// Dis: lis 3, -1 + +// Third tls index is at got[5]. +// k@got@tlsgd --> (0x20118 - 0x280f0) = -0x7fd8 = -32728 +// Dis: test_16: +// Dis: li 3, -32728 diff --git a/test/ELF/ppc64-got-indirect.s b/test/ELF/ppc64-got-indirect.s new file mode 100644 index 000000000000..2837582c4d6b --- /dev/null +++ b/test/ELF/ppc64-got-indirect.s @@ -0,0 +1,115 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-LE %s +# RUN: ld.lld %t.o -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-LE +# RUN: llvm-objdump -D %t2 | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s +# RUN: ld.lld %t.o -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=CHECK-BE +# RUN: llvm-objdump -D %t2 | FileCheck %s + +# Make sure we calculate the offset correctly for a got-indirect access to a +# global variable as described by the PPC64 ELF V2 abi. + .text + .abiversion 2 + .globl _start # -- Begin function _start + .p2align 4 + .type _start,@function +_start: # @_start +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: # %entry + addis 3, 2, .LC0@toc@ha + ld 3, .LC0@toc@l(3) + li 4, 0 + stw 4, -12(1) + li 0,1 + lwa 3, 0(3) + sc + .long 0 + .quad 0 +.Lfunc_end0: + .size _start, .Lfunc_end0-.Lfunc_begin0 + # -- End function + .section .toc,"aw",@progbits +.LC0: + .tc glob[TC],glob + .type glob,@object # @glob + .data + .globl glob + .p2align 2 +glob: + .long 55 # 0x37 + .size glob, 4 + +# Verify the relocations emitted for glob are through the .toc + +# RELOCS-LE: Relocations [ +# RELOCS-LE: .rela.text { +# RELOCS-LE: 0x0 R_PPC64_REL16_HA .TOC. 0x0 +# RELOCS-LE: 0x4 R_PPC64_REL16_LO .TOC. 0x4 +# RELOCS-LE: 0x8 R_PPC64_TOC16_HA .toc 0x0 +# RELOCS-LE: 0xC R_PPC64_TOC16_LO_DS .toc 0x0 +# RELOCS-LE: } +# RELOCS-LE: .rela.toc { +# RELOCS-LE: 0x0 R_PPC64_ADDR64 glob 0x0 +# RELOCS-LE: } + +# RELOCS-BE: Relocations [ +# RELOCS-BE: .rela.text { +# RELOCS-BE: 0x2 R_PPC64_REL16_HA .TOC. 0x2 +# RELOCS-BE: 0x6 R_PPC64_REL16_LO .TOC. 0x6 +# RELOCS-BE: 0xA R_PPC64_TOC16_HA .toc 0x0 +# RELOCS-BE: 0xE R_PPC64_TOC16_LO_DS .toc 0x0 +# RELOCS-BE: } +# RELOCS-BE: .rela.toc { +# RELOCS-BE: 0x0 R_PPC64_ADDR64 glob 0x0 +# RELOCS-BE: } +# RELOCS-BE:] + +# Verify that the global variable access is done through the correct +# toc entry: +# r2 = .TOC. = 0x10038000. +# r3 = r2 - 32760 = 0x10030008 -> .toc entry for glob. + +# CHECK: _start: +# CHECK-NEXT: 10010000: {{.*}} addis 2, 12, 3 +# CHECK-NEXT: 10010004: {{.*}} addi 2, 2, -32768 +# CHECK-NEXT: 10010008: {{.*}} addis 3, 2, 0 +# CHECK-NEXT: 1001000c: {{.*}} ld 3, -32760(3) +# CHECK: 1001001c: {{.*}} lwa 3, 0(3) + +# CHECK-LE: Disassembly of section .data: +# CHECK-LE-NEXT: glob: +# CHECK-LE-NEXT: 10020000: 37 00 00 00 + +# CHECK-LE: Disassembly of section .got: +# CHECK-LE-NEXT: .got: +# CHECK-LE-NEXT: 10030000: 00 80 03 10 +# CHECK-LE-NEXT: 10030004: 00 00 00 00 + +# Verify that .toc comes right after .got +# CHECK-LE: Disassembly of section .toc: +# CHECK-LE: 10030008: 00 00 02 10 + +# CHECK-BE: Disassembly of section .data: +# CHECK-BE-NEXT: glob: +# CHECK-BE-NEXT: 10020000: 00 00 00 37 + +# CHECK-BE: Disassembly of section .got: +# CHECK-BE-NEXT: .got: +# CHECK-BE-NEXT: 10030000: 00 00 00 00 +# CHECK-BE-NEXT: 10030004: 10 03 80 00 + +# Verify that .toc comes right after .got +# CHECK-BE: Disassembly of section .toc: +# CHECK-BE: 10030008: 00 00 00 00 +# CHECK-BE: 1003000c: 10 02 00 00 diff --git a/test/ELF/ppc64-ifunc.s b/test/ELF/ppc64-ifunc.s new file mode 100644 index 000000000000..6f2d3318b9c2 --- /dev/null +++ b/test/ELF/ppc64-ifunc.s @@ -0,0 +1,87 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t2.so +# RUN: ld.lld %t.o %t2.so -o %t +# RUN: llvm-objdump -D %t | FileCheck %s +# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s +# RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +# RUN: ld.lld -shared %t2.o -o %t2.so +# RUN: ld.lld %t.o %t2.so -o %t +# RUN: llvm-objdump -D %t | FileCheck %s +# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s +# RUN: llvm-readelf -dyn-relocations %t | FileCheck --check-prefix=DYNREL %s + +# CHECK: Disassembly of section .text: + +# Tocbase + (0 << 16) + 32560 +# 0x100280e0 + 0 + 32560 = 0x10030010 (.plt[2]) +# CHECK: __plt_foo: +# CHECK-NEXT: std 2, 24(1) +# CHECK-NEXT: addis 12, 2, 0 +# CHECK-NEXT: ld 12, 32560(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr + +# Tocbase + (0 << 16) + 32568 +# 0x100280e0 + 0 + 32568 = 0x1003018 (.plt[3]) +# CHECK: __plt_ifunc: +# CHECK-NEXT: std 2, 24(1) +# CHECK-NEXT: addis 12, 2, 0 +# CHECK-NEXT: ld 12, 32568(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr + +# CHECK: ifunc: +# CHECK-NEXT: 10010028: {{.*}} nop + +# CHECK: _start: +# CHECK-NEXT: addis 2, 12, 2 +# CHECK-NEXT: addi 2, 2, -32588 +# CHECK-NEXT: bl .+67108812 +# CHECK-NEXT: ld 2, 24(1) +# CHECK-NEXT: bl .+67108824 +# CHECK-NEXT: ld 2, 24(1) + +# Check tocbase +# CHECK: Disassembly of section .got: +# CHECK-NEXT: .got: +# CHECK-NEXT: 100200e0 + +# Check .plt address +# DT_PLTGOT should point to the start of the .plt section. +# DT: 0x0000000000000003 PLTGOT 0x10030000 + +# Check that we emit the correct dynamic relocation type for an ifunc +# DYNREL: 'PLT' relocation section at offset 0x{{[0-9a-f]+}} contains 48 bytes: +# 48 bytes --> 2 Elf64_Rela relocations +# DYNREL-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_JMP_SLOT {{0+}} foo + 0 +# DYNREL-NEXT: {{[0-9a-f]+}} {{[0-9a-f]+}} R_PPC64_IRELATIVE 10010028 + + + .text + .abiversion 2 + +.type ifunc STT_GNU_IFUNC +.globl ifunc +ifunc: + nop + + .global _start + .type _start,@function + +_start: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 + bl foo + nop + bl ifunc + nop diff --git a/test/ELF/ppc64-initial-exec-tls.s b/test/ELF/ppc64-initial-exec-tls.s new file mode 100644 index 000000000000..5218b68828ee --- /dev/null +++ b/test/ELF/ppc64-initial-exec-tls.s @@ -0,0 +1,102 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-tls.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld -dynamic-linker /lib64/ld64.so.2 %t.o %t2.so -o %t +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s + + .text + .abiversion 2 + .file "intial_exec.c" + .globl test_initial_exec # -- Begin function test_initial_exec + .p2align 4 + .type test_initial_exec,@function +test_initial_exec: # @test_initial_exec +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry test_initial_exec, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: # %entry + li 3, 0 + stw 3, -12(1) + addis 3, 2, a@got@tprel@ha + ld 3, a@got@tprel@l(3) + lwzx 4, 3, a@tls + extsw 3, 4 + blr + + +test_hi: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry test2, .Lfunc_lep1-.Lfunc_gep1 + addis 3, 0, b@got@tprel@h + blr + +test_ds: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry test16, .Lfunc_lep2-.Lfunc_gep2 + addi 3, 0, c@got@tprel + blr + +// Verify that the input has every initial-exec tls relocation type. +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_GOT_TPREL16_HA {{0+}} a + 0 +// InputRelocs: R_PPC64_GOT_TPREL16_LO_DS {{0+}} a + 0 +// InputRelocs: R_PPC64_TLS {{0+}} a + 0 +// InputRelocs: R_PPC64_GOT_TPREL16_HI {{0+}} b + 0 +// InputRelocs: R_PPC64_GOT_TPREL16_DS {{0+}} c + 0 + +// There is a got entry for each tls variable that is accessed with the +// initial-exec model to be filled in by the dynamic linker. +// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries: +// OutputRelocs: R_PPC64_TPREL64 {{0+}} a + 0 +// OutputRelocs: R_PPC64_TPREL64 {{0+}} b + 0 +// OutputRelocs: R_PPC64_TPREL64 {{0+}} c + 0 + +// Check that the got has 4 entires. (1 for the TOC and 3 entries for TLS +// variables). Also verify the address so we can check +// the offsets we calculated for each relocation type. +// CheckGot: got 00000020 00000000100200c0 + +// GOT stats at 0x100200c0, so TOC will be 0x100280c0 + +// We are building the address of the first TLS got entry which contains the +// offset of the tls variable relative to the thread pointer. +// 0x100200c8 (got[1]). +// #ha(a@got@tprel) --> (0x100200c8 - 0x100280c0 + 0x8000) >> 16 = 0 +// #lo(a@got@tprel)) --> (0x100200c8 - 0x100280c0) & 0xFFFF = -7ff8 = -32760 +// Dis: test_initial_exec: +// Dis: addis 3, 2, 0 +// Dis: ld 3, -32760(3) +// Dis: lwzx 4, 3, 13 + +// Second TLS got entry starts at got[2] 0x100200d0 +// #hi(b@got@tprel) --> (0x100200d0 - 0x100280c0) >> 16 = -1 +// Dis: test_hi: +// Dis: lis 3, -1 + +// Third TLS got entry starts at got[3] 0x100200d8. +// c@got@tprel--> (0x100200d8. - 0x100280c0) = -0x7fe8 = 32744 +// Dis: test_ds: +// Dis: li 3, -32744 diff --git a/test/ELF/ppc64-local-dynamic.s b/test/ELF/ppc64-local-dynamic.s new file mode 100644 index 000000000000..57f324edbc63 --- /dev/null +++ b/test/ELF/ppc64-local-dynamic.s @@ -0,0 +1,128 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-readelf -relocations --wide %t.so | FileCheck --check-prefix=OutputRelocs %s +// RUN: llvm-objdump --section-headers %t.so | FileCheck --check-prefix=CheckGot %s +// RUN: llvm-objdump -D %t.so | FileCheck --check-prefix=Dis %s + + .text + .abiversion 2 + .globl test + .p2align 4 + .type test,@function +test: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry test, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + std 0, 16(1) + stdu 1, -32(1) + addis 3, 2, i@got@tlsld@ha + addi 3, 3, i@got@tlsld@l + bl __tls_get_addr(i@tlsld) + nop + addis 3, 3, i@dtprel@ha + lwa 3, i@dtprel@l(3) + ld 0, 16(1) + mtlr 0 + blr + + .globl test_hi + .p2align 4 + .type test_hi,@function +test_hi: + lis 3, j@got@tlsld@h + blr + + .globl test_16 + .p2align 4 + .type test_16,@function +test_16: + li 3, k@got@tlsld + blr + + .type i,@object + .section .tdata,"awT",@progbits + .p2align 2 +i: + .long 55 + .size i, 4 + + .type j,@object + .section .tbss,"awT",@nobits + .p2align 2 +j: + .long 0 + .size j, 4 + + .type k,@object + .section .tdata,"awT",@progbits + .p2align 3 +k: + .quad 66 + .size k, 8 + +// Verify that the input contains all the R_PPC64_GOT_TLSLD16* relocations, as +// well as the DTPREL relocations used in a typical medium code model +// local-dynamic variable access. +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_GOT_TLSLD16_HA {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_TLSLD16_LO {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_TLSLD {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_DTPREL16_HA {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_DTPREL16_LO_DS {{[0-9a-f]+}} i + 0 +// InputRelocs: R_PPC64_GOT_TLSLD16_HI {{[0-9a-f]+}} j + 0 +// InputRelocs: R_PPC64_GOT_TLSLD16 {{[0-9a-f]+}} k + 0 + +// The local dynamic version of tls needs to use the same mechanism to look up +// a variables address as general-dynamic. ie a call to __tls_get_addr with the +// address of a tls_index struct as the argument. However for local-dynamic +// variables all will have the same ti_module, and the offset field is left as +// as 0, so the same struct can be used for every local-dynamic variable +// used in the shared-object. +// OutputRelocs: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 1 entries: +// OutputRelocs-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +// OutputRelocs-NEXT: R_PPC64_DTPMOD64 + +// Check that the got has 3 entries, 1 for the TOC and 1 stucture of 2 entries +// for the tls variables. Also verify the address so we can check the offsets +// we calculate for each relocation type. +// CheckGot: got 00000018 0000000000020100 + +// got starts at 0x20100 so .TOC. will be 0x28100, and the tls_index struct is +// at 0x20108. + +// #ha(i@got@tlsld) --> (0x20108 - 0x28100 + 0x8000) >> 16 = 0 +// #lo(i@got@tlsld) --> (0x20108 - 0x28100) = -7ff8 = -32760 +// When calculating offset relative to the dynamic thread pointer we have to +// adjust by 0x8000 since each DTV pointer points 0x8000 bytes past the start of +// its TLS block. +// #ha(i@dtprel) --> (0x0 -0x8000 + 0x8000) >> 16 = 0 +// #lo(i@dtprel) --> (0x0 -0x8000) = -0x8000 = -32768 +// Dis: test: +// Dis: addis 3, 2, 0 +// Dis-NEXT: addi 3, 3, -32760 +// Dis-NEXT: bl .+67108804 +// Dis-NEXT: ld 2, 24(1) +// Dis-NEXT: addis 3, 3, 0 +// Dis-NEXT: lwa 3, -32768(3) + + +// #hi(j@got@tlsld) --> (0x20108 - 0x28100 ) > 16 = -1 +// Dis: test_hi: +// Dis: lis 3, -1 + +// k@got@tlsld --> (0x20108 - 0x28100) = -7ff8 = -32760 +// Dis: test_16: +// Dis: li 3, -32760 diff --git a/test/ELF/ppc64-local-exec-tls.s b/test/ELF/ppc64-local-exec-tls.s new file mode 100644 index 000000000000..ff8c2b90102c --- /dev/null +++ b/test/ELF/ppc64-local-exec-tls.s @@ -0,0 +1,163 @@ +// REQUIRES: ppc +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: ld.lld %t.o -o %t +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s + + .text + .abiversion 2 + .globl test_local_exec # -- Begin function test_local_exec + .p2align 4 + .type test_local_exec,@function +test_local_exec: # @test_local_exec +.Lfunc_begin0: +# %bb.0: # %entry + li 3, 0 + stw 3, -12(1) + addis 3, 13, a@tprel@ha + addi 3, 3, a@tprel@l + ld 3, 0(3) + mr 4, 3 + extsw 3, 4 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size test_local_exec, .Lfunc_end0-.Lfunc_begin0 + # -- End function +test_tprel: +.Lfunc_gep1: + addis 2, 12, .TOC.-.Lfunc_gep1@ha + addi 2, 2, .TOC.-.Lfunc_gep1@l +.Lfunc_lep1: + .localentry test_tprel, .Lfunc_lep1-.Lfunc_gep1 + addi 3, 13, b@tprel + blr + + +test_hi: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry test_hi, .Lfunc_lep2-.Lfunc_gep2 + addis 3, 13, b@tprel@h + blr + +test_ds: +.Lfunc_gep3: + addis 2, 12, .TOC.-.Lfunc_gep3@ha + addi 2, 2, .TOC.-.Lfunc_gep3@l +.Lfunc_lep3: + .localentry test_ds, .Lfunc_lep3-.Lfunc_gep3 + ld 3, b@tprel, 13 + blr + +test_lo_ds: +.Lfunc_gep4: + addis 2, 12, .TOC.-.Lfunc_gep4@ha + addi 2, 2, .TOC.-.Lfunc_gep4@l +.Lfunc_lep4: + .localentry test_lo_ds, .Lfunc_lep4-.Lfunc_gep4 + ld 3, b@tprel@l, 13 + blr + +test_highest_a: +.Lfunc_gep5: + addis 2, 12, .TOC.-.Lfunc_gep5@ha + addi 2, 2, .TOC.-.Lfunc_gep5@l +.Lfunc_lep5: + .localentry test_highest_a, .Lfunc_lep5-.Lfunc_gep5 + lis 4, b@tprel@highesta + ori 4, 4, b@tprel@highera + lis 5, b@tprel@ha + addi 5, 5, b@tprel@l + sldi 4, 4, 32 + or 4, 4, 5 + add 3, 13, 4 + blr + +test_highest: +.Lfunc_gep6: + addis 2, 12, .TOC.-.Lfunc_gep6@ha + addi 2, 2, .TOC.-.Lfunc_gep6@l +.Lfunc_lep6: + .localentry test_highest, .Lfunc_lep6-.Lfunc_gep6 + lis 4, b@tprel@highest + ori 4, 4, b@tprel@higher + sldi 4, 4, 32 + oris 4, 4, b@tprel@h + ori 4, 4, b@tprel@l + add 3, 13, 4 + blr + + .type a,@object # @a + .type b,@object # @b + .section .tdata,"awT",@progbits + .p2align 3 +a: + .quad 55 # 0x37 + .size a, 8 + +b: + .quad 55 # 0x37 + .size b, 8 + +// Verify that the input has every initial-exec tls relocation type. +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_TPREL16_HA {{0+}} a + 0 +// InputRelocs: R_PPC64_TPREL16_LO {{0+}} a + 0 +// InputRelocs: R_PPC64_TPREL16 {{0+8}} b + 0 +// InputRelocs: R_PPC64_TPREL16_HI {{0+8}} b + 0 +// InputRelocs: R_PPC64_TPREL16_DS {{0+8}} b + 0 +// InputRelocs: R_PPC64_TPREL16_LO_DS {{0+8}} b + 0 +// InputRelocs: R_PPC64_TPREL16_HIGHESTA {{0+8}} b + 0 +// InputRelocs: R_PPC64_TPREL16_HIGHERA {{0+8}} b + 0 +// InputRelocs: R_PPC64_TPREL16_HIGHEST {{0+8}} b + 0 +// InputRelocs: R_PPC64_TPREL16_HIGHER {{0+8}} b + 0 + +// The start of the TLS storage area is 0x7000 bytes before the thread pointer (r13). +// We are building the address of the first TLS variable, relative to the thread pointer. +// #ha(a@tprel) --> (0 - 0x7000 + 0x8000) >> 16 = 0 +// #lo(a@tprel)) --> (0 - 0x7000) & 0xFFFF = -0x7000 = -28672 +// Dis: test_local_exec: +// Dis: addis 3, 13, 0 +// Dis: addi 3, 3, -28672 + +// We are building the offset for the second TLS variable +// Offset within tls storage - 0x7000 +// b@tprel = 8 - 0x7000 = 28664 +// Dis: test_tprel: +// Dis: addi 3, 13, -28664 + +// #hi(b@tprel) --> (8 - 0x7000) >> 16 = -1 +// Dis: test_hi: +// Dis: addis 3, 13, -1 + +// b@tprel = 8 - 0x7000 = -28664 +// Dis: test_ds: +// Dis: ld 3, -28664(13) + +// #lo(b@tprel) --> (8 - 0x7000) & 0xFFFF = -28664 +// Dis: test_lo_ds: +// Dis: ld 3, -28664(13) + +// #highesta(b@tprel) --> ((0x8 - 0x7000 + 0x8000) >> 48) & 0xFFFF = 0 +// #highera(b@tprel) --> ((0x8 - 0x7000 + 0x8000) >> 32) & 0xFFFF = 0 +// #ha(k@dtprel) --> ((0x8 - 0x7000 + 0x8000) >> 16) & 0xFFFF = 0 +// #lo(k@dtprel) --> ((0x8 - 0x7000) & 0xFFFF = -28664 +// Dis: test_highest_a: +// Dis: lis 4, 0 +// Dis: ori 4, 4, 0 +// Dis: lis 5, 0 +// Dis: addi 5, 5, -28664 + +// #highest(b@tprel) --> ((0x8 - 0x7000) >> 48) & 0xFFFF = 0xFFFF = -1 +// #higher(b@tprel) --> ((0x8 - 0x7000) >> 32) & 0xFFFF = 0xFFFF = 65535 +// #hi(k@dtprel) --> ((0x8 - 0x7000) >> 16) & 0xFFFF = 0xFFFF = 65535 +// #lo(k@dtprel) --> ((0x8 - 0x7000) & 0xFFFF = 33796 +// Dis: test_highest: +// Dis: lis 4, -1 +// Dis: ori 4, 4, 65535 +// Dis: oris 4, 4, 65535 +// Dis: ori 4, 4, 36872 diff --git a/test/ELF/ppc64-plt-stub.s b/test/ELF/ppc64-plt-stub.s new file mode 100644 index 000000000000..a644f487b8be --- /dev/null +++ b/test/ELF/ppc64-plt-stub.s @@ -0,0 +1,42 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld %t.o %t2.so -o %t +// RUN: llvm-objdump -d %t | FileCheck %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld %t.o %t2.so -o %t +// RUN: llvm-objdump -d %t | FileCheck %s + +// CHECK: Disassembly of section .text: +// CHECK-NEXT: __plt_foo: +// CHECK-NEXT: std 2, 24(1) +// CHECK-NEXT: addis 12, 2, 0 +// CHECK-NEXT: ld 12, 32560(12) +// CHECK-NEXT: mtctr 12 +// CHECK-NEXT: bctr + + +// CHECK: _start: +// CHECK: bl .+67108824 + .text + .abiversion 2 + .globl _start + .p2align 4 + .type _start,@function +_start: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 + bl foo + nop + li 0, 1 + sc + .size _start, .-.Lfunc_begin0 diff --git a/test/ELF/ppc64-rel-calls.s b/test/ELF/ppc64-rel-calls.s index f3b309f33dfb..4c79498dc56b 100644 --- a/test/ELF/ppc64-rel-calls.s +++ b/test/ELF/ppc64-rel-calls.s @@ -1,32 +1,29 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 +# RUN: llvm-objdump -d %t2 | FileCheck %s + # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-objdump -d %t2 | FileCheck %s -# REQUIRES: ppc # CHECK: Disassembly of section .text: -.section ".opd","aw" +.text .global _start _start: -.quad .Lfoo,.TOC.@tocbase,0 - -.text .Lfoo: li 0,1 li 3,42 sc -# CHECK: 10010000: 38 00 00 01 li 0, 1 -# CHECK: 10010004: 38 60 00 2a li 3, 42 -# CHECK: 10010008: 44 00 00 02 sc +# CHECK: 10010000: {{.*}} li 0, 1 +# CHECK: 10010004: {{.*}} li 3, 42 +# CHECK: 10010008: {{.*}} sc -.section ".opd","aw" .global bar bar: -.quad .Lbar,.TOC.@tocbase,0 - -.text -.Lbar: bl _start nop bl .Lfoo @@ -34,9 +31,8 @@ bar: blr # FIXME: The printing here is misleading, the branch offset here is negative. -# CHECK: 1001000c: 4b ff ff f5 bl .+67108852 -# CHECK: 10010010: 60 00 00 00 nop -# CHECK: 10010014: 4b ff ff ed bl .+67108844 -# CHECK: 10010018: 60 00 00 00 nop -# CHECK: 1001001c: 4e 80 00 20 blr - +# CHECK: 1001000c: {{.*}} bl .+67108852 +# CHECK: 10010010: {{.*}} nop +# CHECK: 10010014: {{.*}} bl .+67108844 +# CHECK: 10010018: {{.*}} nop +# CHECK: 1001001c: {{.*}} blr diff --git a/test/ELF/ppc64-rel-so-local-calls.s b/test/ELF/ppc64-rel-so-local-calls.s new file mode 100644 index 000000000000..834dbd50aa90 --- /dev/null +++ b/test/ELF/ppc64-rel-so-local-calls.s @@ -0,0 +1,87 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: ld.lld -shared -z notext %t.o -o %t.so +// RUN: llvm-readelf -dyn-relocations %t.so | FileCheck %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: ld.lld -shared -z notext %t.o -o %t.so +// RUN: llvm-readelf -dyn-relocations %t.so | FileCheck %s + + +// CHECK-NOT: foo +// CHECK-NOT: bar + + .text + .abiversion 2 + .globl baz + .p2align 4 + .type baz,@function +baz: +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry baz, .Lfunc_lep0-.Lfunc_gep0 + mflr 0 + std 0, 16(1) + stdu 1, -64(1) + std 30, 48(1) + std 29, 40(1) + mr 30, 3 + bl foo + mr 29, 3 + mr 3, 30 + bl bar + mullw 3, 3, 29 + ld 30, 48(1) + ld 29, 40(1) + extsw 3, 3 + addi 1, 1, 64 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size baz, .Lfunc_end0-.Lfunc_begin0 + + .p2align 4 + .type foo,@function +foo: +.Lfunc_begin1: + mullw 3, 3, 3 + extsw 3, 3 + blr + .long 0 + .quad 0 +.Lfunc_end1: + .size foo, .Lfunc_end1-.Lfunc_begin1 + + .p2align 4 + .type bar,@function +bar: +.Lfunc_begin2: +.Lfunc_gep2: + addis 2, 12, .TOC.-.Lfunc_gep2@ha + addi 2, 2, .TOC.-.Lfunc_gep2@l +.Lfunc_lep2: + .localentry bar, .Lfunc_lep2-.Lfunc_gep2 + mflr 0 + std 0, 16(1) + stdu 1, -48(1) + std 30, 32(1) + mr 30, 3 + bl foo + mullw 3, 3, 30 + ld 30, 32(1) + extsw 3, 3 + addi 1, 1, 48 + ld 0, 16(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end2: + .size bar, .Lfunc_end2-.Lfunc_begin2 diff --git a/test/ELF/ppc64-relocs.s b/test/ELF/ppc64-relocs.s index cb6177dfe305..88e3d4b13e5d 100644 --- a/test/ELF/ppc64-relocs.s +++ b/test/ELF/ppc64-relocs.s @@ -1,22 +1,33 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATALE +# RUN: llvm-objdump -D %t2 | FileCheck %s + # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t # RUN: ld.lld %t -o %t2 -# RUN: llvm-objdump -d %t2 | FileCheck %s -# REQUIRES: ppc +# RUN: llvm-objdump -D %t2 | FileCheck %s --check-prefix=DATABE +# RUN: llvm-objdump -D %t2 | FileCheck %s -.section ".opd","aw" +.text .global _start _start: -.quad .Lfoo,.TOC.@tocbase,0 - -.text .Lfoo: li 0,1 li 3,42 sc -.section ".toc","aw" +.section .rodata,"a",@progbits + .p2align 2 +.LJTI0_0: + .long .LBB0_2-.LJTI0_0 + +.section .toc,"aw",@progbits .L1: .quad 22, 37, 89, 47 +.LC0: + .tc .LJTI0_0[TC],.LJTI0_0 .section .R_PPC64_TOC16_LO_DS,"ax",@progbits .globl .FR_PPC64_TOC16_LO_DS @@ -25,7 +36,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_TOC16_LO_DS: # CHECK: .FR_PPC64_TOC16_LO_DS: -# CHECK: 1001000c: e8 22 80 00 ld 1, -32768(2) +# CHECK: 1001000c: {{.*}} ld 1, -32768(2) .section .R_PPC64_TOC16_LO,"ax",@progbits .globl .FR_PPC64_TOC16_LO @@ -34,7 +45,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_TOC16_LO: # CHECK: .FR_PPC64_TOC16_LO: -# CHECK: 10010010: 38 22 80 00 addi 1, 2, -32768 +# CHECK: 10010010: {{.*}} addi 1, 2, -32768 .section .R_PPC64_TOC16_HI,"ax",@progbits .globl .FR_PPC64_TOC16_HI @@ -43,7 +54,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_TOC16_HI: # CHECK: .FR_PPC64_TOC16_HI: -# CHECK: 10010014: 3c 22 ff fe addis 1, 2, -2 +# CHECK: 10010014: {{.*}} addis 1, 2, -1 .section .R_PPC64_TOC16_HA,"ax",@progbits .globl .FR_PPC64_TOC16_HA @@ -52,7 +63,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_TOC16_HA: # CHECK: .FR_PPC64_TOC16_HA: -# CHECK: 10010018: 3c 22 ff ff addis 1, 2, -1 +# CHECK: 10010018: {{.*}} addis 1, 2, 0 .section .R_PPC64_REL24,"ax",@progbits .globl .FR_PPC64_REL24 @@ -63,7 +74,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_REL24: # CHECK: .FR_PPC64_REL24: -# CHECK: 1001001c: 48 00 00 04 b .+4 +# CHECK: 1001001c: {{.*}} b .+4 .section .R_PPC64_ADDR16_LO,"ax",@progbits .globl .FR_PPC64_ADDR16_LO @@ -72,7 +83,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_ADDR16_LO: # CHECK: .FR_PPC64_ADDR16_LO: -# CHECK: 10010020: 38 20 00 00 li 1, 0 +# CHECK: 10010020: {{.*}} li 1, 0 .section .R_PPC64_ADDR16_HI,"ax",@progbits .globl .FR_PPC64_ADDR16_HI @@ -81,7 +92,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_ADDR16_HI: # CHECK: .FR_PPC64_ADDR16_HI: -# CHECK: 10010024: 38 20 10 01 li 1, 4097 +# CHECK: 10010024: {{.*}} li 1, 4097 .section .R_PPC64_ADDR16_HA,"ax",@progbits .globl .FR_PPC64_ADDR16_HA @@ -90,7 +101,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_ADDR16_HA: # CHECK: .FR_PPC64_ADDR16_HA: -# CHECK: 10010028: 38 20 10 01 li 1, 4097 +# CHECK: 10010028: {{.*}} li 1, 4097 .section .R_PPC64_ADDR16_HIGHER,"ax",@progbits .globl .FR_PPC64_ADDR16_HIGHER @@ -99,7 +110,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHER: # CHECK: .FR_PPC64_ADDR16_HIGHER: -# CHECK: 1001002c: 38 20 00 00 li 1, 0 +# CHECK: 1001002c: {{.*}} li 1, 0 .section .R_PPC64_ADDR16_HIGHERA,"ax",@progbits .globl .FR_PPC64_ADDR16_HIGHERA @@ -108,7 +119,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHERA: # CHECK: .FR_PPC64_ADDR16_HIGHERA: -# CHECK: 10010030: 38 20 00 00 li 1, 0 +# CHECK: 10010030: {{.*}} li 1, 0 .section .R_PPC64_ADDR16_HIGHEST,"ax",@progbits .globl .FR_PPC64_ADDR16_HIGHEST @@ -117,7 +128,7 @@ _start: # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHEST: # CHECK: .FR_PPC64_ADDR16_HIGHEST: -# CHECK: 10010034: 38 20 00 00 li 1, 0 +# CHECK: 10010034: {{.*}} li 1, 0 .section .R_PPC64_ADDR16_HIGHESTA,"ax",@progbits .globl .FR_PPC64_ADDR16_HIGHESTA @@ -126,5 +137,57 @@ _start: # CHECK: Disassembly of section .R_PPC64_ADDR16_HIGHESTA: # CHECK: .FR_PPC64_ADDR16_HIGHESTA: -# CHECK: 10010038: 38 20 00 00 li 1, 0 - +# CHECK: 10010038: {{.*}} li 1, 0 + +.section .R_PPC64_REL32, "ax",@progbits +.globl .FR_PPC64_REL32 +.FR_PPC64_REL32: + addis 5, 2, .LC0@toc@ha + ld 5, .LC0@toc@l(5) +.LBB0_2: + add 3, 3, 4 + +# DATALE: Disassembly of section .rodata: +# DATALE: .rodata: +# DATALE: 10000190: b4 fe 00 00 + +# DATABE: Disassembly of section .rodata: +# DATABE: .rodata: +# DATABE: 10000190: 00 00 fe b4 + +# Address of rodata + value stored at rodata entry +# should equal address of LBB0_2. +# 0x10000190 + 0xfeb4 = 0x10010044 +# CHECK: Disassembly of section .R_PPC64_REL32: +# CHECK: .FR_PPC64_REL32: +# CHECK: 1001003c: {{.*}} addis 5, 2, 0 +# CHECK: 10010040: {{.*}} ld 5, -32736(5) +# CHECK: 10010044: {{.*}} add 3, 3, 4 + +.section .R_PPC64_REL64, "ax",@progbits +.globl .FR_PPC64_REL64 +.FR_PPC64_REL64: + .cfi_startproc + .cfi_personality 148, __foo + li 0, 1 + li 3, 55 + sc + .cfi_endproc +__foo: + li 3,0 + +# Check that address of eh_frame entry + value stored +# should equal the address of foo. Since it is not aligned, +# the entry is not stored exactly at 100001a8. It starts at +# address 0x100001aa and has the value 0xfeaa. +# 0x100001aa + 0xfeaa = 0x10010054 +# DATALE: Disassembly of section .eh_frame: +# DATALE: .eh_frame: +# DATALE: 100001a8: {{.*}} aa fe + +# DATABE: Disassembly of section .eh_frame: +# DATABE: .eh_frame: +# DATABE: 100001b0: fe aa {{.*}} + +# CHECK: __foo +# CHECK-NEXT: 10010054: {{.*}} li 3, 0 diff --git a/test/ELF/ppc64-shared-rel-toc.s b/test/ELF/ppc64-shared-rel-toc.s deleted file mode 100644 index 445011bf8e26..000000000000 --- a/test/ELF/ppc64-shared-rel-toc.s +++ /dev/null @@ -1,27 +0,0 @@ -// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o -// RUN: ld.lld -shared %t.o -o %t.so -// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s -// REQUIRES: ppc - -// When we create the TOC reference in the shared library, make sure that the -// R_PPC64_RELATIVE relocation uses the correct (non-zero) offset. - - .globl foo - .align 2 - .type foo,@function - .section .opd,"aw",@progbits -foo: # @foo - .align 3 - .quad .Lfunc_begin0 - .quad .TOC.@tocbase - .quad 0 - .text -.Lfunc_begin0: - blr - -// CHECK: 0x20000 R_PPC64_RELATIVE - 0x10000 -// CHECK: 0x20008 R_PPC64_RELATIVE - 0x8000 - -// CHECK: Name: foo -// CHECK-NEXT: Value: 0x20000 - diff --git a/test/ELF/ppc64-tls-gd-le.s b/test/ELF/ppc64-tls-gd-le.s new file mode 100644 index 000000000000..c55ae5f670c1 --- /dev/null +++ b/test/ELF/ppc64-tls-gd-le.s @@ -0,0 +1,83 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s +// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s +// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s + + .text + .abiversion 2 + .globl _start # -- Begin function _start + .p2align 4 + .type _start,@function +_start: # @_start +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: # %entry + mflr 0 + std 31, -8(1) + std 0, 16(1) + stdu 1, -64(1) + mr 31, 1 + std 30, 48(31) # 8-byte Folded Spill + li 3, 0 + stw 3, 44(31) + addis 3, 2, a@got@tlsgd@ha + addi 3, 3, a@got@tlsgd@l + bl __tls_get_addr(a@tlsgd) + nop + lwz 30, 0(3) + extsw 3, 30 + ld 30, 48(31) # 8-byte Folded Reload + addi 1, 1, 64 + ld 0, 16(1) + ld 31, -8(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size _start, .Lfunc_end0-.Lfunc_begin0 + +.globl __tls_get_addr +.type __tls_get_addr,@function +__tls_get_addr: + + # -- End function + .type a,@object # @a + .section .tdata,"awT",@progbits + .globl a + .p2align 2 +a: + .long 55 # 0x37 + .size a, 4 + +// Verify that the input has general-dynamic tls relocation types +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_GOT_TLSGD16_HA {{0+}} a + 0 +// InputRelocs: R_PPC64_GOT_TLSGD16_LO {{0+}} a + 0 +// InputRelocs: R_PPC64_TLSGD {{0+}} a + 0 + +// Verify that the general-dynamic sequence is relaxed to local exec. +// #ha(a@tprel) --> (0 - 0x7000 + 0x8000) >> 16 = 0 +// #lo(a@tprel)) --> (0 - 0x7000) & 0xFFFF = -0x7000 = -28672 +// Dis: _start: +// Dis: nop +// Dis: addis 3, 13, 0 +// Dis: nop +// Dis: addi 3, 3, -28672 + +// Verify that no general-dynamic relocations exist for the dynamic linker. +// OutputRelocs-NOT: R_PPC64_DTPMOD64 +// OutputRelocs-NOT: R_PPC64_DTPREL64 diff --git a/test/ELF/ppc64-tls-ld-le.s b/test/ELF/ppc64-tls-ld-le.s new file mode 100644 index 000000000000..d42d7b983c84 --- /dev/null +++ b/test/ELF/ppc64-tls-ld-le.s @@ -0,0 +1,84 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s +// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s + +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +// RUN: llvm-readelf -relocations --wide %t.o | FileCheck --check-prefix=InputRelocs %s +// RUN: ld.lld %t.o -o %t +// RUN: llvm-objdump -D %t | FileCheck --check-prefix=Dis %s +// RUN: llvm-readelf -relocations --wide %t | FileCheck --check-prefix=OutputRelocs %s + + .text + .abiversion 2 + .globl _start # -- Begin function _start + .p2align 4 + .type _start,@function +_start: # @_start +.Lfunc_begin0: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 +# %bb.0: # %entry + mflr 0 + std 31, -8(1) + std 0, 16(1) + stdu 1, -64(1) + mr 31, 1 + std 30, 48(31) # 8-byte Folded Spill + li 3, 0 + stw 3, 44(31) + addis 3, 2, a@got@tlsld@ha + addi 3, 3, a@got@tlsld@l + bl __tls_get_addr(a@tlsld) + nop + addis 3, 3, a@dtprel@ha + addi 3, 3, a@dtprel@l + lwz 30, 0(3) + extsw 3, 30 + ld 30, 48(31) # 8-byte Folded Reload + addi 1, 1, 64 + ld 0, 16(1) + ld 31, -8(1) + mtlr 0 + blr + .long 0 + .quad 0 +.Lfunc_end0: + .size _start, .Lfunc_end0-.Lfunc_begin0 + # -- End function +.globl __tls_get_addr +.type __tls_get_addr,@function +__tls_get_addr: + .type a,@object # @a + .section .tdata,"awT",@progbits + .p2align 2 +a: + .long 2 # 0x2 + .size a, 4 + +// Verify that the input has local-dynamic tls relocation types +// InputRelocs: Relocation section '.rela.text' +// InputRelocs: R_PPC64_GOT_TLSLD16_HA {{0+}} a + 0 +// InputRelocs: R_PPC64_GOT_TLSLD16_LO {{0+}} a + 0 +// InputRelocs: R_PPC64_TLSLD {{0+}} a + 0 + +// Verify that the local-dynamic sequence is relaxed to local exec. +// Dis: _start: +// Dis: nop +// Dis: addis 3, 13, 0 +// Dis: nop +// Dis: addi 3, 3, 4096 + +// #ha(a@dtprel) --> (0x0 -0x8000 + 0x8000) >> 16 = 0 +// #lo(a@dtprel) --> (0x0 -0x8000) = -0x8000 = -32768 +// Dis: addis 3, 3, 0 +// Dis: addi 3, 3, -32768 + +// Verify that no local-dynamic relocations exist for the dynamic linker. +// OutputRelocs-NOT: R_PPC64_DTPMOD64 diff --git a/test/ELF/ppc64-toc-rel.s b/test/ELF/ppc64-toc-rel.s new file mode 100644 index 000000000000..ac156c78b3a4 --- /dev/null +++ b/test/ELF/ppc64-toc-rel.s @@ -0,0 +1,90 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS %s +# RUN: ld.lld %t.o -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o +# RUN: llvm-readobj -relocations %t.o | FileCheck -check-prefix=RELOCS-BE %s +# RUN: ld.lld %t.o -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s + +# Make sure we calculate the offset correctly for a toc-relative access to a +# global variable as described by the PPC64 Elf V2 abi. +.abiversion 2 + +# int global_a = 55 + .globl global_a + .section ".data" + .align 2 + .type global_a, @object + .size global_a, 4 + .p2align 2 +global_a: + .long 41 + + + .section ".text" + .align 2 + .global _start + .type _start, @function +_start: +.Lfunc_gep0: + addis 2, 12, .TOC.-.Lfunc_gep0@ha + addi 2, 2, .TOC.-.Lfunc_gep0@l +.Lfunc_lep0: + .localentry _start, .Lfunc_lep0-.Lfunc_gep0 + + addis 3, 2, global_a@toc@ha + addi 3, 3, global_a@toc@l + li 0,1 + lwa 3, 0(3) + sc +.size _start,.-_start + +# Verify the relocations that get emitted for the global variable are the +# expected ones. +# RELOCS: Relocations [ +# RELOCS-NEXT: .rela.text { +# RELOCS: 0x8 R_PPC64_TOC16_HA global_a 0x0 +# RELOCS: 0xC R_PPC64_TOC16_LO global_a 0x0 + +# RELOCS-BE: Relocations [ +# RELOCS-BE-NEXT: .rela.text { +# RELOCS-BE: 0xA R_PPC64_TOC16_HA global_a 0x0 +# RELOCS-NE: 0xE R_PPC64_TOC16_LO global_a 0x0 + +# Want to check _start for the values used to build the offset from the TOC base +# to global_a. The .TOC. symbol is expected at address 0x10030000, and the +# TOC base is address-of(.TOC.) + 0x8000. The expected offset is: +# 0x10020000(global_a) - 0x10038000(Toc base) = -0x18000(Offset) +# which gets materialized into r3 as ((-1 << 16) - 32768). + +# CHECK: Disassembly of section .text: +# CHECK-NEXT: _start: +# CHECK: 10010008: {{.*}} addis 3, 2, -1 +# CHECK-NEXT: 1001000c: {{.*}} addi 3, 3, -32768 + +# CHECK: Disassembly of section .data: +# CHECK-NEXT: global_a: +# CHECK-NEXT: 10020000: {{.*}} + +# CHECK: Disassembly of section .got: +# CHECK-NEXT: .got: +# CHECK-NEXT: 10030000: 00 80 03 10 + + +# CHECK-BE: Disassembly of section .text: +# CHECK-BE-NEXT: _start: +# CHECK-BE: 10010008: {{.*}} addis 3, 2, -1 +# CHECK-BE-NEXT: 1001000c: {{.*}} addi 3, 3, -32768 + +# CHECK-BE: Disassembly of section .data: +# CHECK-BE-NEXT: global_a: +# CHECK-BE-NEXT: 10020000: {{.*}} + +# CHECK-BE: Disassembly of section .got: +# CHECK-BE-NEXT: .got: +# CHECK-BE-NEXT: 10030000: 00 00 00 00 +# CHECK-BE-NEXT: 10030004: 10 03 80 00 diff --git a/test/ELF/ppc64-toc-restore.s b/test/ELF/ppc64-toc-restore.s index 0c3d30b2d31a..9efe0e81f5e5 100644 --- a/test/ELF/ppc64-toc-restore.s +++ b/test/ELF/ppc64-toc-restore.s @@ -1,62 +1,72 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld %t.o %t2.so %t3.o -o %t +// RUN: llvm-objdump -d %t | FileCheck %s + // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func.s -o %t3.o // RUN: ld.lld -shared %t2.o -o %t2.so -// RUN: ld.lld %t.o %t2.so -o %t +// RUN: ld.lld %t.o %t2.so %t3.o -o %t // RUN: llvm-objdump -d %t | FileCheck %s -// REQUIRES: ppc -// CHECK: Disassembly of section .text: + .text + .abiversion 2 +.global bar_local +bar_local: + li 3, 2 + blr +# Calling external function foo in a shared object needs a nop. +# Calling local function bar_local doe snot need a nop. .global _start _start: - bl bar + bl foo nop + bl bar_local -// CHECK: _start: -// CHECK: 10010000: 48 00 00 21 bl .+32 -// CHECK-NOT: 10010004: 60 00 00 00 nop -// CHECK: 10010004: e8 41 00 28 ld 2, 40(1) - -.global noret -noret: - bl bar - li 5, 7 -// CHECK: noret: -// CHECK: 10010008: 48 00 00 19 bl .+24 -// CHECK: 1001000c: 38 a0 00 07 li 5, 7 - -.global noretend -noretend: - bl bar +// CHECK: Disassembly of section .text: +// CHECK: _start: +// CHECK: 1001001c: {{.*}} bl .+67108836 +// CHECK-NOT: 10010020: {{.*}} nop +// CHECK: 10010020: {{.*}} ld 2, 24(1) +// CHECK: 10010024: {{.*}} bl .+67108848 +// CHECK-NOT: 10010028: {{.*}} nop +// CHECK-NOT: 10010028: {{.*}} ld 2, 24(1) -// CHECK: noretend: -// CHECK: 10010010: 48 00 00 11 bl .+16 +# Calling a function in another object file which will have same +# TOC base does not need a nop. If nop present, do not rewrite to +# a toc restore +.global diff_object +_diff_object: + bl foo_not_shared + bl foo_not_shared + nop -.global noretb -noretb: - b bar +// CHECK: _diff_object: +// CHECK-NEXT: 10010028: {{.*}} bl .+24 +// CHECK-NEXT: 1001002c: {{.*}} bl .+20 +// CHECK-NEXT: 10010030: {{.*}} nop -// CHECK: noretb: -// CHECK: 10010014: 48 00 00 0c b .+12 +# Branching to a local function does not need a nop +.global noretbranch +noretbranch: + b bar_local +// CHECK: noretbranch: +// CHECK: 10010034: {{.*}} b .+67108832 +// CHECK-NOT: 10010038: {{.*}} nop +// CHECK-NOT: 1001003c: {{.*}} ld 2, 24(1) // This should come last to check the end-of-buffer condition. .global last last: - bl bar + bl foo nop - // CHECK: last: -// CHECK: 10010018: 48 00 00 09 bl .+8 -// CHECK: 1001001c: e8 41 00 28 ld 2, 40(1) - -// CHECK: Disassembly of section .plt: -// CHECK: .plt: -// CHECK: 10010020: f8 41 00 28 std 2, 40(1) -// CHECK: 10010024: 3d 62 10 02 addis 11, 2, 4098 -// CHECK: 10010028: e9 8b 80 18 ld 12, -32744(11) -// CHECK: 1001002c: e9 6c 00 00 ld 11, 0(12) -// CHECK: 10010030: 7d 69 03 a6 mtctr 11 -// CHECK: 10010034: e8 4c 00 08 ld 2, 8(12) -// CHECK: 10010038: e9 6c 00 10 ld 11, 16(12) -// CHECK: 1001003c: 4e 80 04 20 bctr +// CHECK: 10010038: {{.*}} bl .+67108808 +// CHECK-NEXT: 1001003c: {{.*}} ld 2, 24(1) diff --git a/test/ELF/ppc64-weak-undef-call-shared.s b/test/ELF/ppc64-weak-undef-call-shared.s index 2c27a27c5a10..db4824762a0f 100644 --- a/test/ELF/ppc64-weak-undef-call-shared.s +++ b/test/ELF/ppc64-weak-undef-call-shared.s @@ -1,7 +1,12 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +# RUN: ld.lld -shared %t.o -o %t.so +# RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s + # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o # RUN: ld.lld -shared %t.o -o %t.so # RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s -# REQUIRES: ppc .section ".toc","aw" .quad weakfunc @@ -10,7 +15,7 @@ .text .Lfoo: bl weakfunc + nop // CHECK-NOT: R_PPC64_REL24 .weak weakfunc - diff --git a/test/ELF/ppc64-weak-undef-call.s b/test/ELF/ppc64-weak-undef-call.s index 55443cb55b99..30c168656e20 100644 --- a/test/ELF/ppc64-weak-undef-call.s +++ b/test/ELF/ppc64-weak-undef-call.s @@ -1,17 +1,18 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 +# RUN: llvm-objdump -d %t2 | FileCheck %s + # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-objdump -d %t2 | FileCheck %s -# REQUIRES: ppc # CHECK: Disassembly of section .text: -.section ".opd","aw" +.text .global _start _start: -.quad .Lfoo,.TOC.@tocbase,0 - -.text -.Lfoo: bl weakfunc nop blr @@ -22,6 +23,6 @@ _start: # be unreachable. But, we should link successfully. We should not, however, # generate a .plt entry (this would be wasted space). For now, we do nothing # (leaving the zero relative offset present in the input). -# CHECK: 10010000: 48 00 00 01 bl .+0 -# CHECK: 10010004: 60 00 00 00 nop -# CHECK: 10010008: 4e 80 00 20 blr +# CHECK: 10010000: {{.*}} bl .+0 +# CHECK: 10010004: {{.*}} nop +# CHECK: 10010008: {{.*}} blr diff --git a/test/ELF/ppc64_entry_point.s b/test/ELF/ppc64_entry_point.s new file mode 100644 index 000000000000..a6f426c7eb10 --- /dev/null +++ b/test/ELF/ppc64_entry_point.s @@ -0,0 +1,50 @@ +# REQUIRES: ppc + +# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck %s + +# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t +# RUN: ld.lld %t -o %t2 +# RUN: llvm-objdump -D %t2 | FileCheck -check-prefix=CHECK-BE %s + +.text +.abiversion 2 +.globl _start +.p2align 4 +.type _start,@function + +_start: +.Lfunc_begin0: +.Lfunc_gep0: + lis 4, .Lfunc_gep0@ha + addi 4, 4, .Lfunc_gep0@l + # now r4 should contain the address of _start + + lis 5, .TOC.-.Lfunc_gep0@ha + addi 5, 5, .TOC.-.Lfunc_gep0@l + # now r5 should contain the offset s.t. r4 + r5 = TOC base + + # exit 55 + li 0, 1 + li 3, 55 + sc +.Lfunc_end0: + .size _start, .Lfunc_end0-.Lfunc_begin0 + +// CHECK: 10010000: {{.*}} lis 4, 4097 +// CHECK-NEXT: 10010004: {{.*}} addi 4, 4, 0 +// CHECK-NEXT: 10010008: {{.*}} lis 5, 2 +// CHECK-NEXT: 1001000c: {{.*}} addi 5, 5, -32768 +// CHECK: Disassembly of section .got: +// CHECK-NEXT: .got: +// CHECK-NEXT: 10020000: 00 80 02 10 + +// CHECK-BE: 10010000: {{.*}} lis 4, 4097 +// CHECK-BE-NEXT: 10010004: {{.*}} addi 4, 4, 0 +// CHECK-BE-NEXT: 10010008: {{.*}} lis 5, 2 +// CHECK-BE-NEXT: 1001000c: {{.*}} addi 5, 5, -32768 +// CHECK-BE: Disassembly of section .got: +// CHECK-BE-NEXT: .got: +// CHECK-BE-NEXT: 10020000: 00 00 00 00 {{.*}} +// CHECK-BE-NEXT: 10020004: 10 02 80 00 {{.*}} diff --git a/test/ELF/pr34660.s b/test/ELF/pr34660.s index 7c78bbc11c7b..53998ad0f728 100644 --- a/test/ELF/pr34660.s +++ b/test/ELF/pr34660.s @@ -3,7 +3,7 @@ # RUN: llvm-mc -filetype=obj -triple=aarch64-linux-none %s -o %t.o # RUN: ld.lld --hash-style=sysv -shared %t.o -o %t # RUN: llvm-objdump %t -d | FileCheck %s --check-prefix=DISASM -# RUN: llvm-readobj -elf-output-style=GNU %t -t | FileCheck %s --check-prefix=SYM +# RUN: llvm-readelf %t -t | FileCheck %s --check-prefix=SYM # It would be much easier to understand/read this test if llvm-objdump would print # the immediates in hex. diff --git a/test/ELF/pr34872.s b/test/ELF/pr34872.s index c656be2a9279..c6ca81972096 100644 --- a/test/ELF/pr34872.s +++ b/test/ELF/pr34872.s @@ -1,8 +1,9 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -filetype=obj -triple=x86_64-pc-linux -o %t.o # RUN: llvm-mc %p/Inputs/undefined-error.s -filetype=obj \ # RUN: -triple=x86_64-pc-linux -o %t2.o # RUN: ld.lld -shared %t2.o -o %t2.so -# RUN: not ld.lld %t2.so %t.o 2>&1 | FileCheck %s +# RUN: not ld.lld %t2.so %t.o -o /dev/null 2>&1 | FileCheck %s # CHECK: undefined symbol: fmod # Check we're not emitting other diagnostics for this symbol. diff --git a/test/ELF/pr36475.s b/test/ELF/pr36475.s new file mode 100644 index 000000000000..0228974b1c45 --- /dev/null +++ b/test/ELF/pr36475.s @@ -0,0 +1,30 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "PHDRS {" > %t.script +# RUN: echo " ph_text PT_LOAD FLAGS (0x1 | 0x4);" >> %t.script +# RUN: echo " ph_data PT_LOAD FLAGS (0x2 | 0x4);" >> %t.script +# RUN: echo "}" >> %t.script +# RUN: echo "SECTIONS {" >> %t.script +# RUN: echo " .text : { *(.text*) } : ph_text" >> %t.script +# RUN: echo " . = ALIGN(0x4000);" >> %t.script +# RUN: echo " .got.plt : { BYTE(42); *(.got); } : ph_data" >> %t.script +# RUN: echo "}" >> %t.script +# RUN: ld.lld -T %t.script %t.o -o %t.elf +# RUN: llvm-readobj -l -elf-output-style=GNU %t.elf | FileCheck %s + +# CHECK: Section to Segment mapping: +# CHECK-NEXT: Segment Sections... +# CHECK-NEXT: 00 .text executable +# CHECK-NEXT: 01 .got.plt + +.text +.globl _start +.type _start,@function +_start: + callq custom_func + ret + +.section executable,"ax",@progbits +.type custom_func,@function +custom_func: + ret diff --git a/test/ELF/pr37735.s b/test/ELF/pr37735.s new file mode 100644 index 000000000000..7e25d1b6f4df --- /dev/null +++ b/test/ELF/pr37735.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=i386-pc-linux-gnu %s -o %t.o +# RUN: ld.lld -r %t.o %t.o -o %t1.o +# RUN: llvm-objdump -s -section=.bar %t1.o | FileCheck %s + +.section .foo + .byte 0 + +# CHECK: Contents of section .bar: +# CHECK-NEXT: 0000 00000000 01000000 +.section .bar + .dc.a .foo diff --git a/test/ELF/pre_init_fini_array.s b/test/ELF/pre_init_fini_array.s index 1192fd0dc851..cf716ab681eb 100644 --- a/test/ELF/pre_init_fini_array.s +++ b/test/ELF/pre_init_fini_array.s @@ -1,10 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2 // RUN: ld.lld %t2 -o %t2.so -shared // RUN: ld.lld %t %t2.so -o %t2 // RUN: llvm-readobj -r -symbols -sections -dynamic-table %t2 | FileCheck %s // RUN: llvm-objdump -d %t2 | FileCheck --check-prefix=DISASM %s -// REQUIRES: x86 .globl _start _start: diff --git a/test/ELF/pre_init_fini_array_missing.s b/test/ELF/pre_init_fini_array_missing.s index 7dabfa7a6966..d5b998443a24 100644 --- a/test/ELF/pre_init_fini_array_missing.s +++ b/test/ELF/pre_init_fini_array_missing.s @@ -1,9 +1,9 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-objdump -d %t2 | FileCheck %s // RUN: ld.lld -pie %t -o %t3 // RUN: llvm-objdump -d %t3 | FileCheck --check-prefix=PIE %s -// REQUIRES: x86 .globl _start _start: @@ -14,30 +14,27 @@ _start: call __fini_array_start call __fini_array_end -// With no .init_array section the symbols resolve to 0 -// 0 - (0x201000 + 5) = -2101253 -// 0 - (0x201005 + 5) = -2101258 -// 0 - (0x20100a + 5) = -2101263 -// 0 - (0x20100f + 5) = -2101268 -// 0 - (0x201014 + 5) = -2101273 -// 0 - (0x201019 + 5) = -2101278 +// With no .init_array section the symbols resolve to .text. +// 0x201000 - (0x201000 + 5) = -5 +// 0x201000 - (0x201005 + 5) = -10 +// ... // CHECK: Disassembly of section .text: // CHECK-NEXT: _start: -// CHECK-NEXT: 201000: e8 fb ef df ff callq -2101253 -// CHECK-NEXT: 201005: e8 f6 ef df ff callq -2101258 -// CHECK-NEXT: 20100a: e8 f1 ef df ff callq -2101263 -// CHECK-NEXT: 20100f: e8 ec ef df ff callq -2101268 -// CHECK-NEXT: 201014: e8 e7 ef df ff callq -2101273 -// CHECK-NEXT: 201019: e8 e2 ef df ff callq -2101278 +// CHECK-NEXT: 201000: e8 fb ff ff ff callq -5 +// CHECK-NEXT: 201005: e8 f6 ff ff ff callq -10 +// CHECK-NEXT: 20100a: e8 f1 ff ff ff callq -15 +// CHECK-NEXT: 20100f: e8 ec ff ff ff callq -20 +// CHECK-NEXT: 201014: e8 e7 ff ff ff callq -25 +// CHECK-NEXT: 201019: e8 e2 ff ff ff callq -30 -// In position-independent binaries, they resolve to the image base. +// In position-independent binaries, they resolve to .text too. // PIE: Disassembly of section .text: // PIE-NEXT: _start: -// PIE-NEXT: 1000: e8 fb ef ff ff callq -4101 -// PIE-NEXT: 1005: e8 f6 ef ff ff callq -4106 -// PIE-NEXT: 100a: e8 f1 ef ff ff callq -4111 -// PIE-NEXT: 100f: e8 ec ef ff ff callq -4116 -// PIE-NEXT: 1014: e8 e7 ef ff ff callq -4121 -// PIE-NEXT: 1019: e8 e2 ef ff ff callq -4126 +// PIE-NEXT: 1000: e8 fb ff ff ff callq -5 +// PIE-NEXT: 1005: e8 f6 ff ff ff callq -10 +// PIE-NEXT: 100a: e8 f1 ff ff ff callq -15 +// PIE-NEXT: 100f: e8 ec ff ff ff callq -20 +// PIE-NEXT: 1014: e8 e7 ff ff ff callq -25 +// PIE-NEXT: 1019: e8 e2 ff ff ff callq -30 diff --git a/test/ELF/print-icf.s b/test/ELF/print-icf.s new file mode 100644 index 000000000000..cb6116d51cdc --- /dev/null +++ b/test/ELF/print-icf.s @@ -0,0 +1,48 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/print-icf.s -o %t1 +# RUN: ld.lld %t %t1 -o %t2 --icf=all --print-icf-sections | FileCheck %s +# RUN: ld.lld %t %t1 -o %t2 --icf=all --no-print-icf-sections --print-icf-sections | FileCheck %s +# RUN: ld.lld %t %t1 -o %t2 --icf=all --print-icf-sections --no-print-icf-sections | FileCheck -allow-empty -check-prefix=PRINT %s + +# CHECK: selected section {{.*}}:(.text.f2) +# CHECK: removing identical section {{.*}}:(.text.f4) +# CHECK: removing identical section {{.*}}:(.text.f7) +# CHECK: selected section {{.*}}:(.text.f1) +# CHECK: removing identical section {{.*}}:(.text.f3) +# CHECK: removing identical section {{.*}}:(.text.f5) +# CHECK: removing identical section {{.*}}:(.text.f6) + +# PRINT-NOT: selected +# PRINT-NOT: removing + +.globl _start, f1, f2 +_start: + ret + +.section .text.f1, "ax" +f1: + mov $60, %rax + mov $42, %rdi + syscall + + .section .text.f2, "ax" +f2: + mov $0, %rax + +.section .text.f3, "ax" +f3: + mov $60, %rax + mov $42, %rdi + syscall + +.section .text.f4, "ax" +f4: + mov $0, %rax + +.section .text.f5, "ax" +f5: + mov $60, %rax + mov $42, %rdi + syscall diff --git a/test/ELF/program-header-layout.s b/test/ELF/program-header-layout.s index 57759c946dac..949a96e4f438 100644 --- a/test/ELF/program-header-layout.s +++ b/test/ELF/program-header-layout.s @@ -1,7 +1,7 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: ld.lld %t -o %t2 # RUN: llvm-readobj -sections -program-headers %t2 | FileCheck %s -# REQUIRES: x86 # Check that different output sections with the same flags are merged into a # single Read/Write PT_LOAD. diff --git a/test/ELF/protected-data-access.s b/test/ELF/protected-data-access.s new file mode 100644 index 000000000000..530710751d6b --- /dev/null +++ b/test/ELF/protected-data-access.s @@ -0,0 +1,27 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %p/Inputs/protected-data-access.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %s -o %t.o + +# RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck --check-prefix=ERR %s +# ERR: error: cannot preempt symbol: foo + +# RUN: ld.lld --ignore-data-address-equality %t.o %t2.so -o %t +# RUN: llvm-readobj --dyn-symbols --relocations %t | FileCheck %s + +# Check that we have a copy relocation. + +# CHECK: R_X86_64_COPY foo 0x0 + +# CHECK: Name: foo +# CHECK-NEXT: Value: +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Object +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: .bss.rel.ro + +.global _start +_start: + .quad foo + diff --git a/test/ELF/protected-function-access.s b/test/ELF/protected-function-access.s new file mode 100644 index 000000000000..2fa682b412fd --- /dev/null +++ b/test/ELF/protected-function-access.s @@ -0,0 +1,27 @@ +# REQUIRES: x86 +# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %p/Inputs/protected-function-access.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: llvm-mc -triple x86_64-pc-linux -filetype=obj %s -o %t.o + +# RUN: not ld.lld %t.o %t2.so -o %t 2>&1 | FileCheck --check-prefix=ERR %s +# ERR: error: cannot preempt symbol: foo + +# RUN: ld.lld --ignore-function-address-equality %t.o %t2.so -o %t +# RUN: llvm-readobj --dyn-symbols --relocations %t | FileCheck %s + +# Check that we have a relocation and an undefined symbol with a non zero address + +# CHECK: R_X86_64_JUMP_SLOT foo 0x0 + +# CHECK: Name: foo +# CHECK-NEXT: Value: 0x201020 +# CHECK-NEXT: Size: +# CHECK-NEXT: Binding: Global +# CHECK-NEXT: Type: Function +# CHECK-NEXT: Other: +# CHECK-NEXT: Section: Undefined + +.global _start +_start: + .quad foo + diff --git a/test/ELF/push-state.s b/test/ELF/push-state.s new file mode 100644 index 000000000000..5a01cd2eeedd --- /dev/null +++ b/test/ELF/push-state.s @@ -0,0 +1,36 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ +// RUN: %p/Inputs/whole-archive.s -o %t2.o +// RUN: rm -f %t.a +// RUN: llvm-ar rcs %t.a %t2.o + +// RUN: ld.lld -o %t.exe -push-state -whole-archive %t.a %t1.o -M | \ +// RUN: FileCheck -check-prefix=WHOLE %s +// WHOLE: _bar + +// RUN: ld.lld -o %t.exe -push-state -whole-archive -pop-state %t.a %t1.o -M | \ +// RUN: FileCheck -check-prefix=NO-WHOLE %s +// NO-WHOLE-NOT: _bar + + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t3.o +// RUN: ld.lld -shared %t3.o -soname libfoo -o %t.so + +// RUN: ld.lld -o %t.exe -push-state -as-needed %t.so %t1.o +// RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=AS-NEEDED %s +// AS-NEEDED-NOT: NEEDED Shared library: [libfoo] + +// RUN: ld.lld -o %t.exe -push-state -as-needed -pop-state %t.so %t1.o +// RUN: llvm-readobj -dynamic-table %t.exe | FileCheck -check-prefix=NO-AS-NEEDED %s +// NO-AS-NEEDED: NEEDED Shared library: [libfoo] + + +// RUN: mkdir -p %t.dir +// RUN: cp %t.so %t.dir/libfoo.so +// RUN: ld.lld -o %t.exe -L%t.dir -push-state -static -pop-state %t1.o -lfoo +// RUN: not ld.lld -o %t.exe -L%t.dir -push-state -static %t1.o -lfoo + +.globl _start +_start: diff --git a/test/ELF/rel-addend-with-rela-input.s b/test/ELF/rel-addend-with-rela-input.s new file mode 100644 index 000000000000..11eac97ed519 --- /dev/null +++ b/test/ELF/rel-addend-with-rela-input.s @@ -0,0 +1,43 @@ +# REQUIRES: mips +# Check that we correctly write addends if the output use Elf_Rel but the input +# uses Elf_Rela + +# RUN: llvm-mc -filetype=obj -triple=mips64-unknown-linux %s -o %t-rela.o +# RUN: llvm-readobj -h -s -section-data -relocations %t-rela.o | FileCheck -check-prefix INPUT-RELA %s +# INPUT-RELA: ElfHeader { +# INPUT-RELA: Class: 64-bit +# INPUT-RELA: DataEncoding: BigEndian +# INPUT-RELA: Section { +# INPUT-RELA: Name: .data +# INPUT-RELA: SectionData ( +# INPUT-RELA-NEXT: 0000: 00000000 00000000 ABCDEF00 12345678 |.............4Vx| +# ^--- No addend here since it uses RELA +# INPUT-RELA: Relocations [ +# INPUT-RELA-NEXT: Section ({{.+}}) .rela.data { +# INPUT-RELA-NEXT: 0x0 R_MIPS_64/R_MIPS_NONE/R_MIPS_NONE foo 0x5544 +# INPUT-RELA-NEXT: } +# INPUT-RELA-NEXT: ] + +# Previously the addend to the dynamic relocation in the .data section was not copied if +# the input file used RELA and the output uses REL. Check that it works now: +# RUN: ld.lld -shared -o %t.so %t-rela.o -verbose +# RUN: llvm-readobj -h -s -section-data -relocations %t.so | FileCheck -check-prefix RELA-TO-REL %s +# RELA-TO-REL: ElfHeader { +# RELA-TO-REL: Class: 64-bit +# RELA-TO-REL: DataEncoding: BigEndian +# RELA-TO-REL: Section { +# RELA-TO-REL: Name: .data +# RELA-TO-REL: SectionData ( +# RELA-TO-REL-NEXT: 0000: 00000000 00005544 ABCDEF00 12345678 |......UD.....4Vx| +# ^--- Addend for relocation in .rel.dyn +# RELA-TO-REL: Relocations [ +# RELA-TO-REL-NEXT: Section ({{.+}}) .rel.dyn { +# RELA-TO-REL-NEXT: 0x10000 R_MIPS_REL32/R_MIPS_64/R_MIPS_NONE foo 0x0 +# RELA-TO-REL-NEXT: } +# RELA-TO-REL-NEXT: ] + +.extern foo + +.data +.quad foo + 0x5544 +.quad 0xabcdef0012345678 diff --git a/test/ELF/relative-dynamic-reloc-ppc64.s b/test/ELF/relative-dynamic-reloc-ppc64.s index 65d0e8e83984..83190a270048 100644 --- a/test/ELF/relative-dynamic-reloc-ppc64.s +++ b/test/ELF/relative-dynamic-reloc-ppc64.s @@ -1,7 +1,11 @@ +// REQUIRES: ppc +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: ld.lld -shared %t.o -o %t.so +// RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s + // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o // RUN: ld.lld -shared %t.o -o %t.so // RUN: llvm-readobj -t -r -dyn-symbols %t.so | FileCheck %s -// REQUIRES: ppc // Test that we create R_PPC64_RELATIVE relocations but don't put any // symbols in the dynamic symbol table. diff --git a/test/ELF/relocatable-build-id.s b/test/ELF/relocatable-build-id.s new file mode 100644 index 000000000000..5ac205c2b287 --- /dev/null +++ b/test/ELF/relocatable-build-id.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: ld.lld --build-id=0xcafebabe -o %t2.o %t1.o -r +# RUN: ld.lld --build-id=0xdeadbeef -o %t.exe %t2.o +# RUN: llvm-objdump -s %t.exe | FileCheck %s + +# CHECK-NOT: cafebabe +# CHECK: deadbeef + +.global _start +_start: + ret diff --git a/test/ELF/relocatable-comdat-multiple.s b/test/ELF/relocatable-comdat-multiple.s index 4c3e7ce7f6d4..bb7a78490fdd 100644 --- a/test/ELF/relocatable-comdat-multiple.s +++ b/test/ELF/relocatable-comdat-multiple.s @@ -8,6 +8,8 @@ # CHECK-NEXT: Group { # CHECK-NEXT: Name: .group # CHECK-NEXT: Index: 2 +# CHECK-NEXT: Link: 8 +# CHECK-NEXT: Info: 1 # CHECK-NEXT: Type: COMDAT # CHECK-NEXT: Signature: aaa # CHECK-NEXT: Section(s) in group [ @@ -18,6 +20,8 @@ # CHECK-NEXT: Group { # CHECK-NEXT: Name: .group # CHECK-NEXT: Index: 5 +# CHECK-NEXT: Link: 8 +# CHECK-NEXT: Info: 6 # CHECK-NEXT: Type: COMDAT # CHECK-NEXT: Signature: bbb # CHECK-NEXT: Section(s) in group [ diff --git a/test/ELF/relocatable-comdat.s b/test/ELF/relocatable-comdat.s index 24504d23884f..11aa30c7e6bd 100644 --- a/test/ELF/relocatable-comdat.s +++ b/test/ELF/relocatable-comdat.s @@ -30,6 +30,8 @@ # CHECK-NEXT: Group { # CHECK-NEXT: Name: .group # CHECK-NEXT: Index: 2 +# CHECK-NEXT: Link: 5 +# CHECK-NEXT: Info: 1 # CHECK-NEXT: Type: COMDAT # CHECK-NEXT: Signature: abc # CHECK-NEXT: Section(s) in group [ diff --git a/test/ELF/relocatable-comdat2.s b/test/ELF/relocatable-comdat2.s index 2643e645fda9..27844feae16e 100644 --- a/test/ELF/relocatable-comdat2.s +++ b/test/ELF/relocatable-comdat2.s @@ -13,6 +13,8 @@ # CHECK-NEXT: Group { # CHECK-NEXT: Name: .group # CHECK-NEXT: Index: 2 +# CHECK-NEXT: Link: 7 +# CHECK-NEXT: Info: 1 # CHECK-NEXT: Type: COMDAT # CHECK-NEXT: Signature: bar # CHECK-NEXT: Section(s) in group [ @@ -22,6 +24,8 @@ # CHECK-NEXT: Group { # CHECK-NEXT: Name: .group # CHECK-NEXT: Index: 4 +# CHECK-NEXT: Link: 7 +# CHECK-NEXT: Info: 2 # CHECK-NEXT: Type: COMDAT # CHECK-NEXT: Signature: zed # CHECK-NEXT: Section(s) in group [ diff --git a/test/ELF/relocatable-eh-frame.s b/test/ELF/relocatable-eh-frame.s index c2e5ec63f865..dee906acb87f 100644 --- a/test/ELF/relocatable-eh-frame.s +++ b/test/ELF/relocatable-eh-frame.s @@ -5,7 +5,7 @@ # RUN: ld.lld %t -o %t.so -shared # RUN: llvm-objdump -h %t.so | FileCheck --check-prefix=DSO %s -# DSO: .eh_frame 00000030 +# DSO: .eh_frame 00000034 # CHECK: Relocations [ # CHECK-NEXT: Section ({{.*}}) .rela.eh_frame { diff --git a/test/ELF/relocatable-many-sections.s b/test/ELF/relocatable-many-sections.s new file mode 100644 index 000000000000..df22154d0c9f --- /dev/null +++ b/test/ELF/relocatable-many-sections.s @@ -0,0 +1,92 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o %t.o +# RUN: ld.lld -r %t.o -o %t +# RUN: llvm-readobj -file-headers %t | FileCheck %s + +## Check we are able to emit a valid ELF header when +## sections amount is greater than SHN_LORESERVE. +# CHECK: ElfHeader { +# CHECK: SectionHeaderCount: 0 (65541) +# CHECK-NEXT: StringTableSectionIndex: 65535 (65539) + +## Check that 65539 is really the index of .shstrtab section. +# RUN: llvm-objdump -section-headers -section=.shstrtab %t \ +# RUN: | FileCheck %s --check-prefix=SHSTRTAB +# SHSTRTAB: Sections: +# SHSTRTAB-NEXT: Idx Name +# SHSTRTAB-NEXT: 65539 .shstrtab + +.macro gen_sections4 x + .section a\x + .section b\x + .section c\x + .section d\x +.endm + +.macro gen_sections8 x + gen_sections4 a\x + gen_sections4 b\x +.endm + +.macro gen_sections16 x + gen_sections8 a\x + gen_sections8 b\x +.endm + +.macro gen_sections32 x + gen_sections16 a\x + gen_sections16 b\x +.endm + +.macro gen_sections64 x + gen_sections32 a\x + gen_sections32 b\x +.endm + +.macro gen_sections128 x + gen_sections64 a\x + gen_sections64 b\x +.endm + +.macro gen_sections256 x + gen_sections128 a\x + gen_sections128 b\x +.endm + +.macro gen_sections512 x + gen_sections256 a\x + gen_sections256 b\x +.endm + +.macro gen_sections1024 x + gen_sections512 a\x + gen_sections512 b\x +.endm + +.macro gen_sections2048 x + gen_sections1024 a\x + gen_sections1024 b\x +.endm + +.macro gen_sections4096 x + gen_sections2048 a\x + gen_sections2048 b\x +.endm + +.macro gen_sections8192 x + gen_sections4096 a\x + gen_sections4096 b\x +.endm + +.macro gen_sections16384 x + gen_sections8192 a\x + gen_sections8192 b\x +.endm + +gen_sections16384 a +gen_sections16384 b +gen_sections16384 c +gen_sections16384 d + +.global _start +_start: diff --git a/test/ELF/relocatable-symbols.s b/test/ELF/relocatable-symbols.s index 79608e7b74f0..46d8ab7395fc 100644 --- a/test/ELF/relocatable-symbols.s +++ b/test/ELF/relocatable-symbols.s @@ -174,21 +174,33 @@ .global _start .text _start: - call __start_foo - call __stop_foo + .byte 0xe8 + .long __start_foo - . -4 + .byte 0xe8 + .long __stop_foo - . -4 - call __start_bar - call __stop_bar + .byte 0xe8 + .long __start_bar - . -4 + .byte 0xe8 + .long __stop_bar - . -4 - call __start_doo - call __stop_doo + .byte 0xe8 + .long __start_doo - . -4 + .byte 0xe8 + .long __stop_doo - . -4 - call __preinit_array_start - call __preinit_array_end - call __init_array_start - call __init_array_end - call __fini_array_start - call __fini_array_end + .byte 0xe8 + .long __preinit_array_start - . -4 + .byte 0xe8 + .long __preinit_array_end - . -4 + .byte 0xe8 + .long __init_array_start - . -4 + .byte 0xe8 + .long __init_array_end - . -4 + .byte 0xe8 + .long __fini_array_start - . -4 + .byte 0xe8 + .long __fini_array_end - . -4 .section foo,"ax" nop diff --git a/test/ELF/relocatable-versioned.s b/test/ELF/relocatable-versioned.s new file mode 100644 index 000000000000..2b6c49eb5baa --- /dev/null +++ b/test/ELF/relocatable-versioned.s @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: ld.lld -o %t2.o -r %t1.o +# RUN: llvm-nm %t2.o | FileCheck %s +# CHECK: foo@VERSION + +.global "foo@VERSION" +"foo@VERSION": + ret diff --git a/test/ELF/relocation-absolute.s b/test/ELF/relocation-absolute.s index 20d54eca9205..b882987bb694 100644 --- a/test/ELF/relocation-absolute.s +++ b/test/ELF/relocation-absolute.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/abs.s -o %tabs // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %tabs %t -o %tout // RUN: llvm-objdump -d %tout | FileCheck %s -// REQUIRES: x86 .global _start _start: diff --git a/test/ELF/relocation-common.s b/test/ELF/relocation-common.s index 28276bfe0750..71b1ac0e2e24 100644 --- a/test/ELF/relocation-common.s +++ b/test/ELF/relocation-common.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %t -o %tout // RUN: llvm-objdump -t -d %tout | FileCheck %s -// REQUIRES: x86 .global _start _start: diff --git a/test/ELF/relocation-dtrace.test b/test/ELF/relocation-dtrace.test index ef2cc4956ca6..9007a265bfaa 100644 --- a/test/ELF/relocation-dtrace.test +++ b/test/ELF/relocation-dtrace.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t.o -# RUN: ld.lld -shared %t.o -o %t.so +# RUN: ld.lld -shared %t.o -o /dev/null # Test that we can handle R_X86_64_NONE as produced by dtrace. diff --git a/test/ELF/relocation-i686.s b/test/ELF/relocation-i686.s index 3986357d66f2..fdec7caa33be 100644 --- a/test/ELF/relocation-i686.s +++ b/test/ELF/relocation-i686.s @@ -1,10 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so // RUN: ld.lld --hash-style=sysv %t %t2.so -o %t2 // RUN: llvm-readobj -s %t2 | FileCheck --check-prefix=ADDR %s // RUN: llvm-objdump -d %t2 | FileCheck %s -// REQUIRES: x86 .global _start _start: diff --git a/test/ELF/relocation-local.s b/test/ELF/relocation-local.s index 8173dac0522f..383c5c82f64a 100644 --- a/test/ELF/relocation-local.s +++ b/test/ELF/relocation-local.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // Test that relocation of local symbols is working. // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-objdump -s -d %t2 | FileCheck %s -// REQUIRES: x86 .global _start diff --git a/test/ELF/relocation-nocopy.s b/test/ELF/relocation-nocopy.s index 533277dc8ec3..70e99334796d 100644 --- a/test/ELF/relocation-nocopy.s +++ b/test/ELF/relocation-nocopy.s @@ -2,7 +2,7 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/relocation-copy.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t.so -// RUN: not ld.lld -z nocopyreloc %t.o %t.so -o %t3 2>&1 | FileCheck %s +// RUN: not ld.lld -z nocopyreloc %t.o %t.so -o /dev/null 2>&1 | FileCheck %s // CHECK: unresolvable relocation R_X86_64_32S against symbol 'x' // CHECK: unresolvable relocation R_X86_64_32S against symbol 'y' diff --git a/test/ELF/relocation-non-alloc.s b/test/ELF/relocation-non-alloc.s index 1ad15a4e5787..95166fbe0d4a 100644 --- a/test/ELF/relocation-non-alloc.s +++ b/test/ELF/relocation-non-alloc.s @@ -1,25 +1,47 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +// RUN: ld.lld %t -o %t2 -shared --apply-dynamic-relocs +// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix APPLYDYNREL %s + // RUN: ld.lld %t -o %t2 -shared -// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck %s +// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s +// RUN: ld.lld %t -o %t2 -shared --no-apply-dynamic-relocs +// RUN: llvm-readobj -s -section-data -r %t2 | FileCheck -check-prefix CHECK -check-prefix NOAPPLYDYNREL %s -// CHECK: Name: .data -// CHECK-NEXT: Type: SHT_PROGBITS -// CHECK-NEXT: Flags [ -// CHECK-NEXT: SHF_ALLOC -// CHECK-NEXT: SHF_WRITE -// CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1000 -// CHECK-NEXT: Offset: 0x1000 -// CHECK-NEXT: Size: 16 -// CHECK-NEXT: Link: 0 -// CHECK-NEXT: Info: 0 -// CHECK-NEXT: AddressAlignment: 1 -// CHECK-NEXT: EntrySize: 0 -// CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 00000000 00000000 00000000 00000000 -// CHECK-NEXT: ) +// APPLYDYNREL: Name: .data +// APPLYDYNREL-NEXT: Type: SHT_PROGBITS +// APPLYDYNREL-NEXT: Flags [ +// APPLYDYNREL-NEXT: SHF_ALLOC +// APPLYDYNREL-NEXT: SHF_WRITE +// APPLYDYNREL-NEXT: ] +// APPLYDYNREL-NEXT: Address: 0x1000 +// APPLYDYNREL-NEXT: Offset: 0x1000 +// APPLYDYNREL-NEXT: Size: 16 +// APPLYDYNREL-NEXT: Link: 0 +// APPLYDYNREL-NEXT: Info: 0 +// APPLYDYNREL-NEXT: AddressAlignment: 1 +// APPLYDYNREL-NEXT: EntrySize: 0 +// APPLYDYNREL-NEXT: SectionData ( +// APPLYDYNREL-NEXT: 0000: 00100000 00000000 00000000 00000000 +// APPLYDYNREL-NEXT: ) + +// NOAPPLYDYNREL: Name: .data +// NOAPPLYDYNREL-NEXT: Type: SHT_PROGBITS +// NOAPPLYDYNREL-NEXT: Flags [ +// NOAPPLYDYNREL-NEXT: SHF_ALLOC +// NOAPPLYDYNREL-NEXT: SHF_WRITE +// NOAPPLYDYNREL-NEXT: ] +// NOAPPLYDYNREL-NEXT: Address: 0x1000 +// NOAPPLYDYNREL-NEXT: Offset: 0x1000 +// NOAPPLYDYNREL-NEXT: Size: 16 +// NOAPPLYDYNREL-NEXT: Link: 0 +// NOAPPLYDYNREL-NEXT: Info: 0 +// NOAPPLYDYNREL-NEXT: AddressAlignment: 1 +// NOAPPLYDYNREL-NEXT: EntrySize: 0 +// NOAPPLYDYNREL-NEXT: SectionData ( +// NOAPPLYDYNREL-NEXT: 0000: 00000000 00000000 00000000 00000000 +// NOAPPLYDYNREL-NEXT: ) // CHECK: Name: foo // CHECK-NEXT: Type: SHT_PROGBITS diff --git a/test/ELF/relocation-none-aarch64.test b/test/ELF/relocation-none-aarch64.test index dd67c8c0fb2e..e77989a54a83 100644 --- a/test/ELF/relocation-none-aarch64.test +++ b/test/ELF/relocation-none-aarch64.test @@ -1,7 +1,7 @@ # REQUIRES: aarch64 # RUN: yaml2obj %s -o %t.o -# RUN: ld.lld %t.o -o %t.out +# RUN: ld.lld %t.o -o /dev/null !ELF FileHeader: diff --git a/test/ELF/relocation-none-i686.test b/test/ELF/relocation-none-i686.test index d8eed8f7a129..82dc4e608c03 100644 --- a/test/ELF/relocation-none-i686.test +++ b/test/ELF/relocation-none-i686.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t.o -# RUN: ld.lld %t.o -o %t.out +# RUN: ld.lld %t.o -o /dev/null # Test that we can handle R_386_NONE. diff --git a/test/ELF/relocation-past-merge-end.s b/test/ELF/relocation-past-merge-end.s index d08bde7b9f6c..a3e7b59a415a 100644 --- a/test/ELF/relocation-past-merge-end.s +++ b/test/ELF/relocation-past-merge-end.s @@ -1,6 +1,6 @@ // REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux -// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s // CHECK: relocation-past-merge-end.s.tmp.o:(.foo): entry is past the end of the section .data diff --git a/test/ELF/relocation-relative-absolute.s b/test/ELF/relocation-relative-absolute.s index 2a343fddca76..21f50025e92b 100644 --- a/test/ELF/relocation-relative-absolute.s +++ b/test/ELF/relocation-relative-absolute.s @@ -2,7 +2,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %tinput1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux \ # RUN: %S/Inputs/relocation-relative-absolute.s -o %tinput2.o -# RUN: not ld.lld %tinput1.o %tinput2.o -o %t -pie 2>&1 | FileCheck %s +# RUN: not ld.lld %tinput1.o %tinput2.o -o /dev/null -pie 2>&1 | FileCheck %s .globl _start _start: diff --git a/test/ELF/relocation-shared.s b/test/ELF/relocation-shared.s index 4fba7a5683b0..81537cec1ef5 100644 --- a/test/ELF/relocation-shared.s +++ b/test/ELF/relocation-shared.s @@ -8,7 +8,7 @@ // CHECK-NEXT: Flags [ // CHECK-NEXT: SHF_ALLOC // CHECK-NEXT: ] -// CHECK-NEXT: Address: 0x1C8 +// CHECK-NEXT: Address: 0x20D // CHECK-NEXT: Offset: // CHECK-NEXT: Size: 8 // CHECK-NEXT: Link: 0 @@ -16,8 +16,8 @@ // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 // CHECK-NEXT: SectionData ( -// CHECK-NEXT: 0000: 380E0000 00000000 -// 0x1000 - 0x1C8 = 0xE38 +// CHECK-NEXT: 0000: F30D0000 00000000 +// 0x1000 - 0x20D = 0xDF3 // CHECK-NEXT: ) // CHECK: Name: .text diff --git a/test/ELF/relocation-size-err.s b/test/ELF/relocation-size-err.s new file mode 100644 index 000000000000..8783fe9568da --- /dev/null +++ b/test/ELF/relocation-size-err.s @@ -0,0 +1,12 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s + +// CHECK: error: can't create dynamic relocation R_X86_64_SIZE64 against symbol: foo in readonly segment; recompile object files with -fPIC or pass '-Wl,-z,notext' to allow text relocations in the output + + .global foo +foo: + .quad 42 + .size foo, 8 + + .quad foo@SIZE diff --git a/test/ELF/relocation-size-shared.s b/test/ELF/relocation-size-shared.s index cea9e64d58ed..f60f0929e705 100644 --- a/test/ELF/relocation-size-shared.s +++ b/test/ELF/relocation-size-shared.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/relocation-size-shared.s -o %tso.o // RUN: ld.lld -shared %tso.o -o %tso diff --git a/test/ELF/relocation-size.s b/test/ELF/relocation-size.s index 419b8a17fad9..525b1e1d1331 100644 --- a/test/ELF/relocation-size.s +++ b/test/ELF/relocation-size.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: ld.lld %t.o -o %t1 // RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s diff --git a/test/ELF/relocation-undefined-weak.s b/test/ELF/relocation-undefined-weak.s index 6aa84ec483f4..7ea247fd5d6e 100644 --- a/test/ELF/relocation-undefined-weak.s +++ b/test/ELF/relocation-undefined-weak.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %t -o %tout // RUN: llvm-readobj -sections %tout | FileCheck %s // RUN: llvm-objdump -d %tout | FileCheck %s --check-prefix DISASM -// REQUIRES: x86 // Check that undefined weak symbols are treated as having a VA of 0. diff --git a/test/ELF/relocation.s b/test/ELF/relocation.s index 3359a8badda6..00b75d25f968 100644 --- a/test/ELF/relocation.s +++ b/test/ELF/relocation.s @@ -1,10 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2 -// RUN: ld.lld %t2 -o %t2.so -shared +// RUN: ld.lld %t2 -soname fixed-length-string.so -o %t2.so -shared // RUN: ld.lld --hash-style=sysv %t %t2.so -o %t3 // RUN: llvm-readobj -s %t3 | FileCheck --check-prefix=SEC %s // RUN: llvm-objdump -s -d %t3 | FileCheck %s -// REQUIRES: x86 // SEC: Name: .plt // SEC-NEXT: Type: SHT_PROGBITS @@ -113,17 +113,16 @@ R_X86_64_64: .quad R_X86_64_64 // CHECK: Contents of section .R_X86_64_64: -// CHECK-NEXT: 2001c8 c8012000 00000000 +// CHECK-NEXT: 2002c0 c0022000 00000000 .section .R_X86_64_GOTPCREL,"a",@progbits .global R_X86_64_GOTPCREL R_X86_64_GOTPCREL: .long zed@gotpcrel -// 0x2020F8 - 0x2001D8 = 7952 -// 7952 = 0x101f0000 in little endian +// 0x2030F0(.got) - 0x2002c8(.R_X86_64_GOTPCREL) = 0x2e28 // CHECK: Contents of section .R_X86_64_GOTPCREL -// CHECK-NEXT: 2001d0 202f0000 +// CHECK-NEXT: 2002c8 282e0000 .section .R_X86_64_GOT32,"a",@progbits .global R_X86_64_GOT32 diff --git a/test/ELF/relro-non-contiguous.s b/test/ELF/relro-non-contiguous.s index ce6680860edf..8fdf64a37456 100644 --- a/test/ELF/relro-non-contiguous.s +++ b/test/ELF/relro-non-contiguous.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/copy-in-shared.s -o %t2.o // RUN: ld.lld -shared %t.o %t2.o -o %t.so @@ -15,7 +16,6 @@ // RUN: not ld.lld %t3.o %t.so -z relro -o %t --script=%t.script 2>&1 | FileCheck %s // No error when we do not request relro. // RUN: ld.lld %t3.o %t.so -z norelro -o %t --script=%t.script -// REQUIRES: x86 // CHECK: error: section: .bss.rel.ro is not contiguous with other relro sections .section .text, "ax", @progbits diff --git a/test/ELF/relro-omagic.s b/test/ELF/relro-omagic.s index 97c3a812406d..ba0ca72e219b 100644 --- a/test/ELF/relro-omagic.s +++ b/test/ELF/relro-omagic.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o # RUN: ld.lld -shared %t2.o -o %t2.so -soname relro-omagic.s.tmp2.so @@ -13,8 +14,8 @@ # NORELRO-NEXT: 3 .dynstr 00000021 0000000000200188 # NORELRO-NEXT: 4 .rela.dyn 00000018 00000000002001b0 # NORELRO-NEXT: 5 .rela.plt 00000018 00000000002001c8 -# NORELRO-NEXT: 6 .text 0000000a 00000000002001e0 TEXT DATA -# NORELRO-NEXT: 7 .plt 00000020 00000000002001f0 TEXT DATA +# NORELRO-NEXT: 6 .text 0000000a 00000000002001e0 TEXT +# NORELRO-NEXT: 7 .plt 00000020 00000000002001f0 TEXT # NORELRO-NEXT: 8 .data 00000008 0000000000200210 DATA # NORELRO-NEXT: 9 .foo 00000004 0000000000200218 DATA # NORELRO-NEXT: 10 .dynamic 000000f0 0000000000200220 diff --git a/test/ELF/relro-script.s b/test/ELF/relro-script.s index f0dca67a3422..c71c8e5decdc 100644 --- a/test/ELF/relro-script.s +++ b/test/ELF/relro-script.s @@ -16,7 +16,7 @@ // RUN: .got.plt : { *(.got.plt) } \ // RUN: } " > %t.script // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t3.o -// RUN: ld.lld %t3.o %t.so -o %t --script=%t.script --print-map | FileCheck %s +// RUN: ld.lld %t3.o %t.so -o /dev/null --script=%t.script --print-map | FileCheck %s // CHECK: .data.rel.ro // CHECK-NEXT: <internal>:(.bss.rel.ro) diff --git a/test/ELF/relro.s b/test/ELF/relro.s index b21e514303ab..0f721318c784 100644 --- a/test/ELF/relro.s +++ b/test/ELF/relro.s @@ -1,13 +1,17 @@ +// REQUIRES: x86 + // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so -// RUN: ld.lld %t.o %t2.so -z now -z relro -o %t + +// RUN: ld.lld %t.o %t2.so -z now -z norelro -z relro -o %t // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=FULLRELRO %s -// RUN: ld.lld %t.o %t2.so -z relro -o %t + +// RUN: ld.lld %t.o %t2.so -z norelro -z relro -o %t // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=CHECK --check-prefix=PARTRELRO %s + // RUN: ld.lld %t.o %t2.so -z norelro -o %t // RUN: llvm-readobj -l --elf-output-style=GNU %t | FileCheck --check-prefix=NORELRO %s -// REQUIRES: x86 // CHECK: Program Headers: // CHECK-NEXT: Type diff --git a/test/ELF/reproduce-backslash.s b/test/ELF/reproduce-backslash.s index 53feb5ff3223..7a9964db62aa 100644 --- a/test/ELF/reproduce-backslash.s +++ b/test/ELF/reproduce-backslash.s @@ -2,8 +2,8 @@ # Test that we don't erroneously replace \ with / on UNIX, as it's # legal for a filename to contain backslashes. -# RUN: llvm-mc %s -o foo\\.o -filetype=obj -triple=x86_64-pc-linux -# RUN: ld.lld foo\\.o --reproduce repro.tar -# RUN: tar tf repro.tar | FileCheck %s +# RUN: llvm-mc %s -o %T/foo\\.o -filetype=obj -triple=x86_64-pc-linux +# RUN: ld.lld %T/foo\\.o --reproduce %T/repro.tar -o /dev/null +# RUN: tar tf %T/repro.tar | FileCheck %s # CHECK: repro/{{.*}}/foo\\.o diff --git a/test/ELF/reproduce-error.s b/test/ELF/reproduce-error.s index e2de8a4feeba..3a99815d7708 100644 --- a/test/ELF/reproduce-error.s +++ b/test/ELF/reproduce-error.s @@ -1,5 +1,5 @@ -# Extracting the tar archive can get over the path limit on windows. # REQUIRES: shell +# Extracting the tar archive can get over the path limit on windows. # RUN: rm -rf %t.dir # RUN: mkdir -p %t.dir diff --git a/test/ELF/reproduce.s b/test/ELF/reproduce.s index 69671a088473..bfab2e87e80b 100644 --- a/test/ELF/reproduce.s +++ b/test/ELF/reproduce.s @@ -1,7 +1,7 @@ # REQUIRES: x86 +# REQUIRES: shell # Extracting the tar archive can get over the path limit on windows. -# REQUIRES: shell # RUN: rm -rf %t.dir # RUN: mkdir -p %t.dir/build1 diff --git a/test/ELF/resolution-end.s b/test/ELF/resolution-end.s index 26858372ce09..c8c5a044e602 100644 --- a/test/ELF/resolution-end.s +++ b/test/ELF/resolution-end.s @@ -1,9 +1,9 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-end.s -o %t2.o # RUN: ld.lld -shared -o %t2.so %t2.o # RUN: ld.lld --hash-style=sysv %t1.o %t2.so -o %t # RUN: llvm-readobj -t -s -section-data %t | FileCheck %s -# REQUIRES: x86 # Test that we resolve _end to the this executable. diff --git a/test/ELF/resolution-shared.s b/test/ELF/resolution-shared.s index e1eac070e5af..2d61d268c6f9 100644 --- a/test/ELF/resolution-shared.s +++ b/test/ELF/resolution-shared.s @@ -1,9 +1,9 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution-shared.s -o %t2.o // RUN: ld.lld %t2.o -o %t2.so -shared // RUN: ld.lld %t.o %t2.so -o %t3 -shared // RUN: llvm-readobj -t %t3 | FileCheck %s -// REQUIRES: x86 .weak foo foo: diff --git a/test/ELF/resolution.s b/test/ELF/resolution.s index 4a42d941eab6..f72f487e68ea 100644 --- a/test/ELF/resolution.s +++ b/test/ELF/resolution.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/resolution.s -o %t2 // RUN: ld.lld -discard-all %t %t2 -o %t3 // RUN: llvm-readobj -t %t3 | FileCheck %s -// REQUIRES: x86 // This is an exhaustive test for checking which symbol is kept when two // have the same name. Each symbol has a different size which is used diff --git a/test/ELF/rodynamic.s b/test/ELF/rodynamic.s index 441e5c395e7c..49d59cec4a6a 100644 --- a/test/ELF/rodynamic.s +++ b/test/ELF/rodynamic.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux # RUN: llvm-mc %p/Inputs/rodynamic.s -o %t.so.o -filetype=obj -triple=x86_64-pc-linux diff --git a/test/ELF/section-align-0.test b/test/ELF/section-align-0.test index 35783f5a894b..8827ecf740b3 100644 --- a/test/ELF/section-align-0.test +++ b/test/ELF/section-align-0.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: ld.lld %t -o %tout +# RUN: ld.lld %t -o /dev/null # Verify that lld can handle sections with an alignment of zero. diff --git a/test/ELF/section-layout.s b/test/ELF/section-layout.s index 7febec85a629..0832109fa898 100644 --- a/test/ELF/section-layout.s +++ b/test/ELF/section-layout.s @@ -1,7 +1,7 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: ld.lld %t -o %tout # RUN: llvm-readobj -sections %tout | FileCheck %s -# REQUIRES: x86 # Check that sections are laid out in the correct order. @@ -26,9 +26,10 @@ _start: .section e,"awT" .section d,"ax",@nobits .section c,"ax" -.section b,"a",@nobits -.section a,"a" +.section a,"a",@nobits +.section b,"a" +// For non-executable and non-writable sections, PROGBITS appear after others. // CHECK: Name: a // CHECK: Name: b // CHECK: Name: c diff --git a/test/ELF/section-metadata-err.s b/test/ELF/section-metadata-err.s index 1bcbedfbab71..c9104303e434 100644 --- a/test/ELF/section-metadata-err.s +++ b/test/ELF/section-metadata-err.s @@ -1,9 +1,9 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s -# CHECK: error: a section with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err.s.tmp.o:(.foo) +# CHECK: error: a section .bar with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err.s.tmp.o:(.foo) .global _start _start: @@ -12,4 +12,4 @@ _start: .section .foo,"aM",@progbits,8 .quad 0 -.section bar,"ao",@progbits,.foo +.section .bar,"ao",@progbits,.foo diff --git a/test/ELF/section-metadata-err2.s b/test/ELF/section-metadata-err2.s new file mode 100644 index 000000000000..3191c1f4d3b6 --- /dev/null +++ b/test/ELF/section-metadata-err2.s @@ -0,0 +1,17 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +## Check we do not crash and report proper errors. +# CHECK: error: a section .bar with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err2.s.tmp.o:(.foo) +# CHECK: error: a section .bar with SHF_LINK_ORDER should not refer a non-regular section: {{.*}}section-metadata-err2.s.tmp.o:(.foo) + +.section .foo,"aM",@progbits,8 +.quad 0 + +.section .bar,"ao",@progbits,.foo,unique,1 +.quad 0 + +.section .bar,"ao",@progbits,.foo,unique,2 +.quad 1 diff --git a/test/ELF/section-metadata-err3.s b/test/ELF/section-metadata-err3.s new file mode 100644 index 000000000000..5c4875b9da5e --- /dev/null +++ b/test/ELF/section-metadata-err3.s @@ -0,0 +1,17 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: error: incompatible section flags for .bar +# CHECK-NEXT: >>> {{.*}}section-metadata-err3.s.tmp.o:(.bar): 0x2 +# CHECK-NEXT: >>> output section .bar: 0x82 + +.section .foo,"a",@progbits +.quad 0 + +.section .bar,"ao",@progbits,.foo,unique,1 +.quad 0 + +.section .bar,"a",@progbits,unique,2 +.quad 1 diff --git a/test/ELF/section-name.s b/test/ELF/section-name.s index caf574f2c106..4f010c81963c 100644 --- a/test/ELF/section-name.s +++ b/test/ELF/section-name.s @@ -1,7 +1,7 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t # RUN: ld.lld %t -o %tout # RUN: llvm-objdump --section-headers %tout | FileCheck %s -# REQUIRES: x86 .global _start .text diff --git a/test/ELF/section-symbol.s b/test/ELF/section-symbol.s index 5cf71aceec72..495c38db5da9 100644 --- a/test/ELF/section-symbol.s +++ b/test/ELF/section-symbol.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: ld.lld %t -o %t.so -shared -discard-none // RUN: llvm-readobj -t %t.so | FileCheck %s diff --git a/test/ELF/section-symbols.test b/test/ELF/section-symbols.test index 2ef77a828b65..973b1102fdf3 100644 --- a/test/ELF/section-symbols.test +++ b/test/ELF/section-symbols.test @@ -1,5 +1,5 @@ # RUN: yaml2obj %s -o %t -# RUN: ld.lld -shared %t -o %tout +# RUN: ld.lld -shared %t -o /dev/null # Verify that lld can handle STT_SECTION symbols associated # with SHT_REL[A]/SHT_SYMTAB/SHT_STRTAB sections. diff --git a/test/ELF/sectionstart-noallochdr.s b/test/ELF/sectionstart-noallochdr.s index e9267a5372a5..be8e0c568e1e 100644 --- a/test/ELF/sectionstart-noallochdr.s +++ b/test/ELF/sectionstart-noallochdr.s @@ -7,7 +7,7 @@ # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .text 00000001 0000000000000010 TEXT DATA +# CHECK-NEXT: 1 .text 00000001 0000000000000010 TEXT # CHECK-NEXT: 2 .data 00000004 0000000000000020 DATA # CHECK-NEXT: 3 .bss 00000004 0000000000000030 BSS diff --git a/test/ELF/sectionstart.s b/test/ELF/sectionstart.s index 23574c14748a..be8b5f0cfb40 100644 --- a/test/ELF/sectionstart.s +++ b/test/ELF/sectionstart.s @@ -1,13 +1,13 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: ld.lld %t.o --section-start .text=0x100000 \ -# RUN: --section-start .data=0x110000 --section-start .bss=0x200000 -o %t +# RUN: --section-start=.data=0x110000 --section-start .bss=0x200000 -o %t # RUN: llvm-objdump -section-headers %t | FileCheck %s # CHECK: Sections: # CHECK-NEXT: Idx Name Size Address Type # CHECK-NEXT: 0 00000000 0000000000000000 -# CHECK-NEXT: 1 .text 00000001 0000000000100000 TEXT DATA +# CHECK-NEXT: 1 .text 00000001 0000000000100000 TEXT # CHECK-NEXT: 2 .data 00000004 0000000000110000 DATA # CHECK-NEXT: 3 .bss 00000004 0000000000200000 BSS @@ -35,11 +35,11 @@ # RUN: llvm-objdump -section-headers %t4 | FileCheck %s ## Errors: -# RUN: not ld.lld %t.o --section-start .text100000 -o %t2 2>&1 \ +# RUN: not ld.lld %t.o --section-start .text100000 -o /dev/null 2>&1 \ # RUN: | FileCheck -check-prefix=ERR1 %s # ERR1: invalid argument: --section-start .text100000 -# RUN: not ld.lld %t.o --section-start .text=1Q0000 -o %t3 2>&1 \ +# RUN: not ld.lld %t.o --section-start .text=1Q0000 -o /dev/null 2>&1 \ # RUN: | FileCheck -check-prefix=ERR2 %s # ERR2: invalid argument: --section-start .text=1Q0000 diff --git a/test/ELF/shared-lazy.s b/test/ELF/shared-lazy.s index bc1e61c3c949..36b8f16e1794 100644 --- a/test/ELF/shared-lazy.s +++ b/test/ELF/shared-lazy.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o // RUN: rm -f %t1.a // RUN: llvm-ar rc %t1.a %t1.o diff --git a/test/ELF/shared-be.s b/test/ELF/shared-ppc64.s index 0b941d373720..f2280a1e8c1c 100644 --- a/test/ELF/shared-be.s +++ b/test/ELF/shared-ppc64.s @@ -1,9 +1,16 @@ +// REQUIRES: ppc + +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o +// RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so +// RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t +// RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s + // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so // RUN: ld.lld -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t // RUN: llvm-readobj --dynamic-table -s %t | FileCheck %s -// REQUIRES: ppc // CHECK: Name: .rela.dyn // CHECK-NEXT: Type: SHT_REL diff --git a/test/ELF/shared.s b/test/ELF/shared.s index 65ad2c61359b..3a8fedec9240 100644 --- a/test/ELF/shared.s +++ b/test/ELF/shared.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=i686-unknown-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld --hash-style=sysv -shared %t2.o -o %t2.so @@ -6,7 +7,6 @@ // RUN: llvm-readobj --program-headers --dynamic-table -t -s -dyn-symbols -section-data -hash-table %t | FileCheck %s // RUN: ld.lld --hash-style=sysv %t.o %t2.so %t2.so -o %t2 // RUN: llvm-readobj -dyn-symbols %t2 | FileCheck --check-prefix=DONT_EXPORT %s -// REQUIRES: x86 // Make sure .symtab is properly aligned. // SO: Name: .symtab @@ -73,8 +73,8 @@ // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 4 // CHECK-NEXT: EntrySize: 4 - -// CHECK: Index: [[DYNSTR]] +// CHECK: Section { +// CHECK-NEXT: Index: [[DYNSTR]] // CHECK-NEXT: Name: .dynstr // CHECK-NEXT: Type: SHT_STRTAB // CHECK-NEXT: Flags [ @@ -87,9 +87,6 @@ // CHECK-NEXT: Info: 0 // CHECK-NEXT: AddressAlignment: 1 // CHECK-NEXT: EntrySize: 0 -// CHECK-NEXT: SectionData ( -// CHECK: ) -// CHECK-NEXT: } // CHECK: Name: .rel.dyn // CHECK-NEXT: Type: SHT_REL diff --git a/test/ELF/shlib-undefined-archive.s b/test/ELF/shlib-undefined-archive.s new file mode 100644 index 000000000000..940d8d7bc0c5 --- /dev/null +++ b/test/ELF/shlib-undefined-archive.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# Undefined symbols in a DSO should pull out object files from archives +# to resolve them. + +# RUN: echo '.globl foo' | llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t1.o - +# RUN: ld.lld -shared -o %t.so %t1.o + +# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t2.o %s +# RUN: rm -f %t.a +# RUN: llvm-ar cru %t.a %t2.o +# RUN: ld.lld -o %t.exe %t.so %t.a +# RUN: llvm-nm -D %t.exe | FileCheck %s + +# CHECK: T foo + +.globl foo +foo: + ret diff --git a/test/ELF/shlib-undefined-local.s b/test/ELF/shlib-undefined-local.s new file mode 100644 index 000000000000..8fceec1bf60f --- /dev/null +++ b/test/ELF/shlib-undefined-local.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t1.o %S/Inputs/shlib-undefined-ref.s +# RUN: ld.lld -shared -o %t.so %t1.o + +# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t2.o %s +# RUN: echo "{ local: *; };" > %t.script +# RUN: ld.lld -version-script %t.script -o %t %t2.o %t.so +# RUN: llvm-nm -g %t | FileCheck -allow-empty %s + +# CHECK-NOT: should_not_be_exported + +.globl should_not_be_exported +should_not_be_exported: + ret + +.globl _start +_start: + ret diff --git a/test/ELF/shlib-undefined-shared.s b/test/ELF/shlib-undefined-shared.s new file mode 100644 index 000000000000..6d60d01bfabe --- /dev/null +++ b/test/ELF/shlib-undefined-shared.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t1.o %S/Inputs/shlib-undefined-ref.s +# RUN: ld.lld -shared -o %t1.so %t1.o + +# RUN: llvm-mc -filetype=obj -triple=x86_64-linux-gnu -o %t2.o %s +# RUN: echo "{ local: *; };" > %t.script +# RUN: ld.lld -shared -version-script %t.script -o %t2.so %t2.o %t1.so +# RUN: llvm-nm -g %t2.so | FileCheck -allow-empty %s + +# CHECK-NOT: should_not_be_exported + +.globl should_not_be_exported +should_not_be_exported: + ret diff --git a/test/ELF/sht-group-gold-r.test b/test/ELF/sht-group-gold-r.test index 3a3889eabd81..d1757eee6e7d 100644 --- a/test/ELF/sht-group-gold-r.test +++ b/test/ELF/sht-group-gold-r.test @@ -1,3 +1,4 @@ +# REQUIRES: x86 # GNU gold 1.14 (the newest version as of July 2017) seems to create # non-standard-compliant SHT_GROUP sections when the -r option is given. # diff --git a/test/ELF/silent-ignore.test b/test/ELF/silent-ignore.test index 6655754ace58..adfc2442d4ed 100644 --- a/test/ELF/silent-ignore.test +++ b/test/ELF/silent-ignore.test @@ -1,6 +1,5 @@ RUN: ld.lld --version \ RUN: -allow-shlib-undefined \ -RUN: -cref \ RUN: -g \ RUN: -no-add-needed \ RUN: -no-allow-shlib-undefined \ diff --git a/test/ELF/soname.s b/test/ELF/soname.s index a26bb30f7a17..25c969dab745 100644 --- a/test/ELF/soname.s +++ b/test/ELF/soname.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -shared -soname=bar -o %t.so // RUN: ld.lld %t.o -shared --soname=bar -o %t2.so diff --git a/test/ELF/soname2.s b/test/ELF/soname2.s index 9fb8da519bfb..67a9c24af5cd 100644 --- a/test/ELF/soname2.s +++ b/test/ELF/soname2.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -shared -soname=foo.so -o %t // RUN: llvm-readobj --dynamic-table %t | FileCheck %s diff --git a/test/ELF/sort-norosegment.s b/test/ELF/sort-norosegment.s index bd74f2eb330a..cd4fc9ebae16 100644 --- a/test/ELF/sort-norosegment.s +++ b/test/ELF/sort-norosegment.s @@ -1,13 +1,13 @@ # REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: ld.lld --hash-style=sysv -no-rosegment -o %t1 %t -shared -# RUN: llvm-readobj -elf-output-style=GNU -s %t1 | FileCheck %s +# RUN: ld.lld --hash-style=sysv -no-rosegment -o %t %t.o -shared +# RUN: llvm-readelf -s %t | FileCheck %s -# CHECK: .text {{.*}} AX -# CHECK-NEXT: .dynsym {{.*}} A +# CHECK: .dynsym {{.*}} A # CHECK-NEXT: .hash {{.*}} A # CHECK-NEXT: .dynstr {{.*}} A +# CHECK-NEXT: .text {{.*}} AX # CHECK-NEXT: foo {{.*}} WA # CHECK-NEXT: .dynamic {{.*}} WA diff --git a/test/ELF/splitstacks.s b/test/ELF/splitstacks.s deleted file mode 100644 index 3b7e67e5c2b0..000000000000 --- a/test/ELF/splitstacks.s +++ /dev/null @@ -1,11 +0,0 @@ -# REQUIRES: x86 -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o - -# RUN: not ld.lld %t1.o -o %t 2>&1 | FileCheck %s -# CHECK: .o: object file compiled with -fsplit-stack is not supported - -.globl _start -_start: - nop - -.section .note.GNU-split-stack,"",@progbits diff --git a/test/ELF/start-lib.s b/test/ELF/start-lib.s index 013a2b206a1f..b79d9efc325a 100644 --- a/test/ELF/start-lib.s +++ b/test/ELF/start-lib.s @@ -21,5 +21,14 @@ // TEST3-NOT: Name: bar // TEST3-NOT: Name: foo +// RUN: not ld.lld %t1.o --start-lib --start-lib 2>&1 | FileCheck -check-prefix=NESTED-LIB %s +// NESTED-LIB: nested --start-lib + +// RUN: not ld.lld %t1.o --start-group --start-lib 2>&1 | FileCheck -check-prefix=LIB-IN-GROUP %s +// LIB-IN-GROUP: may not nest --start-lib in --start-group + +// RUN: not ld.lld --end-lib 2>&1 | FileCheck -check-prefix=END %s +// END: stray --end-lib + .globl _start _start: diff --git a/test/ELF/startstop-shared.s b/test/ELF/startstop-shared.s index 80ccf3df0aad..4d3192a35734 100644 --- a/test/ELF/startstop-shared.s +++ b/test/ELF/startstop-shared.s @@ -11,18 +11,30 @@ .quad __start_bar .section bar,"a" -// Test that we are able to hide the symbol. -// CHECK: R_X86_64_RELATIVE - 0x[[ADDR:.*]] +// CHECK: Relocations [ +// CHECK-NEXT: Section {{.*}} .rela.dyn { +// CHECK-NEXT: R_X86_64_RELATIVE +// CHECK-NEXT: R_X86_64_RELATIVE +// CHECK-NEXT: } +// CHECK-NEXT: ] -// By default the symbol is visible and we need a dynamic reloc. -// CHECK: R_X86_64_64 __start_foo 0x0 +// Test that we are able to hide the symbol. +// By default the symbol is protected. // CHECK: Name: __start_bar -// CHECK-NEXT: Value: 0x[[ADDR]] +// CHECK-NEXT: Value: // CHECK-NEXT: Size: // CHECK-NEXT: Binding: Local +// CHECK-NEXT: Type: None +// CHECK-NEXT: Other [ +// CHECK-NEXT: STV_HIDDEN +// CHECK-NEXT: ] // CHECK: Name: __start_foo // CHECK-NEXT: Value: // CHECK-NEXT: Size: // CHECK-NEXT: Binding: Global +// CHECK-NEXT: Type: None +// CHECK-NEXT: Other [ +// CHECK-NEXT: STV_PROTECTED +// CHECK-NEXT: ] diff --git a/test/ELF/startstop.s b/test/ELF/startstop.s index 1e75042a0c8c..470298eee37d 100644 --- a/test/ELF/startstop.s +++ b/test/ELF/startstop.s @@ -19,13 +19,12 @@ // DISASM: 1013: 90 nop // DISASM: 1014: 90 nop - // SYMBOL: Relocations [ // SYMBOL-NEXT: Section ({{.*}}) .rela.dyn { -// SYMBOL-NEXT: 0x2010 R_X86_64_64 __stop_zed1 0x0 -// SYMBOL-NEXT: 0x2018 R_X86_64_64 __stop_zed1 0x1 -// SYMBOL-NEXT: 0x2000 R_X86_64_64 __stop_zed2 0x0 -// SYMBOL-NEXT: 0x2008 R_X86_64_64 __stop_zed2 0x1 +// SYMBOL-NEXT: R_X86_64_RELATIVE +// SYMBOL-NEXT: R_X86_64_RELATIVE +// SYMBOL-NEXT: R_X86_64_RELATIVE +// SYMBOL-NEXT: R_X86_64_RELATIVE // SYMBOL-NEXT: } // SYMBOL-NEXT: ] @@ -45,20 +44,20 @@ // SYMBOL: Symbol { // SYMBOL: Name: __stop_foo // SYMBOL: Value: 0x1012 -// STMBOL: STV_HIDDEN +// SYMBOL: STV_HIDDEN // SYMBOL: Section: foo // SYMBOL: } // SYMBOL: Symbol { // SYMBOL: Name: __stop_zed1 // SYMBOL: Value: 0x2010 -// STMBOL: Other: 0 +// SYMBOL: STV_PROTECTED // SYMBOL: Section: zed1 // SYMBOL: } // SYMBOL: Symbol { // SYMBOL: Name: __stop_zed2 // SYMBOL: Value: 0x2020 -// STMBOL: Other: 0 +// SYMBOL: STV_PROTECTED // SYMBOL: Section: zed2 // SYMBOL: } diff --git a/test/ELF/static-with-export-dynamic.s b/test/ELF/static-with-export-dynamic.s index 8634835d9aa7..f0c67df22623 100644 --- a/test/ELF/static-with-export-dynamic.s +++ b/test/ELF/static-with-export-dynamic.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-unknown-cloudabi %s -o %t.o // RUN: ld.lld --export-dynamic %t.o -o %t // RUN: llvm-readobj -dyn-symbols %t | FileCheck %s -// REQUIRES: x86 // Ensure that a dynamic symbol table is present when --export-dynamic // is passed in, even when creating statically linked executables. diff --git a/test/ELF/string-gc.s b/test/ELF/string-gc.s index 96c75e9236f4..8e4ee14e0f47 100644 --- a/test/ELF/string-gc.s +++ b/test/ELF/string-gc.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: ld.lld %t.o -o %t --gc-sections // RUN: llvm-readobj -symbols %t | FileCheck %s diff --git a/test/ELF/string-table.s b/test/ELF/string-table.s index 490c4d574cf1..2a975501d951 100644 --- a/test/ELF/string-table.s +++ b/test/ELF/string-table.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-readobj -sections %t2 | FileCheck %s -// REQUIRES: x86 .global _start _start: diff --git a/test/ELF/symbol-ordering-file-icf.s b/test/ELF/symbol-ordering-file-icf.s new file mode 100644 index 000000000000..93e377cb53b0 --- /dev/null +++ b/test/ELF/symbol-ordering-file-icf.s @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "zed" > %t.order +# RUN: echo "bar" >> %t.order +# RUN: echo "foo" >> %t.order +# RUN: ld.lld --icf=all --symbol-ordering-file %t.order -shared %t.o -o %t.so +# RUN: llvm-nm %t.so | FileCheck %s + +## Check that after ICF merges 'foo' and 'zed' we still +## place them before 'bar', in according to ordering file. +# CHECK-DAG: 0000000000001000 T foo +# CHECK-DAG: 0000000000001000 T zed +# CHECK-DAG: 0000000000001004 T bar + +.section .text.foo,"ax",@progbits +.align 4 +.global foo +foo: + retq + +.section .text.bar,"ax",@progbits +.align 4 +.global bar +bar: + nop + retq + +.section .text.zed,"ax",@progbits +.align 4 +.global zed +zed: + retq diff --git a/test/ELF/symbol-ordering-file-warnings.s b/test/ELF/symbol-ordering-file-warnings.s new file mode 100644 index 000000000000..71414bf58098 --- /dev/null +++ b/test/ELF/symbol-ordering-file-warnings.s @@ -0,0 +1,165 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symbol-ordering-file-warnings1.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symbol-ordering-file-warnings2.s -o %t3.o +# RUN: ld.lld -shared %t2.o -o %t.so + +# Check that a warning is emitted for entries in the file that are not present in any used input. +# RUN: echo "missing" > %t-order-missing.txt +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-missing.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,MISSING + +# Check that the warning can be disabled. +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-missing.txt \ +# RUN: --unresolved-symbols=ignore-all --no-warn-symbol-ordering 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN --allow-empty + +# Check that the warning can be re-enabled +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-missing.txt \ +# RUN: --unresolved-symbols=ignore-all --no-warn-symbol-ordering --warn-symbol-ordering 2>&1 | \ +# RUN: FileCheck %s --check-prefixes=WARN,MISSING + +# Check that a warning is emitted for undefined symbols. +# RUN: echo "undefined" > %t-order-undef.txt +# RUN: ld.lld %t1.o %t3.o -o %t --symbol-ordering-file %t-order-undef.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,UNDEFINED + +# Check that a warning is emitted for imported shared symbols. +# RUN: echo "shared" > %t-order-shared.txt +# RUN: ld.lld %t1.o %t.so -o %t --symbol-ordering-file %t-order-shared.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SHARED + +# Check that a warning is emitted for absolute symbols. +# RUN: echo "absolute" > %t-order-absolute.txt +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-absolute.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,ABSOLUTE + +# Check that a warning is emitted for symbols discarded due to --gc-sections. +# RUN: echo "gc" > %t-order-gc.txt +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-gc.txt --gc-sections \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,GC + +# Check that a warning is not emitted for the symbol removed due to --icf. +# RUN: echo "icf1" > %t-order-icf.txt +# RUN: echo "icf2" >> %t-order-icf.txt +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-icf.txt --icf=all \ +# RUN: --unresolved-symbols=ignore-all --fatal-warnings + +# RUN: echo "_GLOBAL_OFFSET_TABLE_" > %t-order-synthetic.txt +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-synthetic.txt --icf=all \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SYNTHETIC + +# Check that a warning is emitted for symbols discarded due to a linker script /DISCARD/ section. +# RUN: echo "discard" > %t-order-discard.txt +# RUN: echo "SECTIONS { /DISCARD/ : { *(.text.discard) } }" > %t.script +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-discard.txt -T %t.script \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,DISCARD + +# Check that LLD does not warn for discarded COMDAT symbols, if they are present in the kept instance. +# RUN: echo "comdat" > %t-order-comdat.txt +# RUN: ld.lld %t1.o %t2.o -o %t --symbol-ordering-file %t-order-comdat.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN --allow-empty + +# Check that if a COMDAT was unused and discarded via --gc-sections, warn for each instance. +# RUN: ld.lld %t1.o %t2.o -o %t --symbol-ordering-file %t-order-comdat.txt --gc-sections \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,COMDAT + +# Check that if a weak symbol is not kept, because of an equivalent global symbol, no warning is emitted. +# RUN: echo "glob_or_wk" > %t-order-weak.txt +# RUN: ld.lld %t1.o %t2.o -o %t --symbol-ordering-file %t-order-weak.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN --allow-empty + +# Check that symbols only in unused archive members result in a warning. +# RUN: rm -f %t.a +# RUN: llvm-ar rc %t.a %t3.o +# RUN: ld.lld %t1.o %t.a -o %t --symbol-ordering-file %t-order-missing.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,MISSING --allow-empty + +# Check that a warning for each same-named symbol with an issue. +# RUN: echo "multi" > %t-order-same-name.txt +# RUN: ld.lld %t1.o %t2.o %t3.o -o %t --symbol-ordering-file %t-order-same-name.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,MULTI + +# Check that a warning is emitted if the same symbol is mentioned multiple times in the ordering file. +# RUN: echo "_start" > %t-order-multiple-same.txt +# RUN: echo "_start" >> %t-order-multiple-same.txt +# RUN: ld.lld %t1.o -o %t --symbol-ordering-file %t-order-multiple-same.txt \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SAMESYM + +# Check that all warnings can be emitted from the same input. +# RUN: echo "missing_sym" > %t-order-multi.txt +# RUN: echo "undefined" >> %t-order-multi.txt +# RUN: echo "_start" >> %t-order-multi.txt +# RUN: echo "shared" >> %t-order-multi.txt +# RUN: echo "absolute" >> %t-order-multi.txt +# RUN: echo "gc" >> %t-order-multi.txt +# RUN: echo "discard" >> %t-order-multi.txt +# RUN: echo "_GLOBAL_OFFSET_TABLE_" >> %t-order-multi.txt +# RUN: echo "_start" >> %t-order-multi.txt +# RUN: ld.lld %t1.o %t3.o %t.so -o %t --symbol-ordering-file %t-order-multi.txt --gc-sections -T %t.script \ +# RUN: --unresolved-symbols=ignore-all 2>&1 | FileCheck %s --check-prefixes=WARN,SAMESYM,ABSOLUTE,SHARED,UNDEFINED,GC,DISCARD,MISSING2,SYNTHETIC + +# WARN-NOT: warning: +# SAMESYM: warning: {{.*}}.txt: duplicate ordered symbol: _start +# WARN-NOT: warning: +# SYNTHETIC: warning: <internal>: unable to order synthetic symbol: _GLOBAL_OFFSET_TABLE_ +# WARN-NOT: warning: +# DISCARD: warning: {{.*}}1.o: unable to order discarded symbol: discard +# WARN-NOT: warning: +# GC: warning: {{.*}}1.o: unable to order discarded symbol: gc +# WARN-NOT: warning: +# SHARED: warning: {{.*}}.so: unable to order shared symbol: shared +# WARN-NOT: warning: +# UNDEFINED: warning: {{.*}}3.o: unable to order undefined symbol: undefined +# WARN-NOT: warning: +# ABSOLUTE: warning: {{.*}}1.o: unable to order absolute symbol: absolute +# WARN-NOT: warning: +# MISSING: warning: symbol ordering file: no such symbol: missing +# MISSING2: warning: symbol ordering file: no such symbol: missing_sym +# COMDAT: warning: {{.*}}1.o: unable to order discarded symbol: comdat +# MULTI: warning: {{.*}}3.o: unable to order undefined symbol: multi +# MULTI-NEXT: warning: {{.*}}2.o: unable to order absolute symbol: multi +# WARN-NOT: warning: + +absolute = 0x1234 + +.section .text.gc,"ax",@progbits +.global gc +gc: + nop + +.section .text.discard,"ax",@progbits +.global discard +discard: + nop + +.section .text.comdat,"axG",@progbits,comdat,comdat +.weak comdat +comdat: + nop + +.section .text.glob_or_wk,"ax",@progbits +.weak glob_or_wk +glob_or_wk: + nop + +.section .text._start,"ax",@progbits +.global _start +_start: + movq %rax, absolute + callq shared + +.section .text.icf1,"ax",@progbits +.global icf1 +icf1: + ret + +.section .text.icf2,"ax",@progbits +.global icf2 +icf2: + ret + +# This is a "good" instance of the symbol +.section .text.multi,"ax",@progbits +multi: + .quad _GLOBAL_OFFSET_TABLE_ diff --git a/test/ELF/symbol-ordering-file.s b/test/ELF/symbol-ordering-file.s index 5a88b8c0827f..34d67701933e 100644 --- a/test/ELF/symbol-ordering-file.s +++ b/test/ELF/symbol-ordering-file.s @@ -5,6 +5,8 @@ # BEFORE: Contents of section .foo: # BEFORE-NEXT: 201000 11223344 5566 +# BEFORE: Contents of section .init: +# BEFORE-NEXT: 201006 1122 # RUN: echo "_foo4 " > %t_order.txt # RUN: echo " _foo3" >> %t_order.txt @@ -14,12 +16,18 @@ # RUN: echo "_foo4" >> %t_order.txt # RUN: echo "_bar1" >> %t_order.txt # RUN: echo "_foo1" >> %t_order.txt +# RUN: echo "_init2" >> %t_order.txt +# RUN: echo "_init1" >> %t_order.txt # RUN: ld.lld --symbol-ordering-file %t_order.txt %t.o -o %t2.out # RUN: llvm-objdump -s %t2.out| FileCheck %s --check-prefix=AFTER +# RUN: ld.lld --symbol-ordering-file=%t_order.txt %t.o -o %t2.out +# RUN: llvm-objdump -s %t2.out| FileCheck %s --check-prefix=AFTER # AFTER: Contents of section .foo: # AFTER-NEXT: 201000 44335566 2211 +# AFTER: Contents of section .init: +# AFTER-NEXT: 201006 1122 .section .foo,"ax",@progbits,unique,1 _foo1: @@ -42,3 +50,11 @@ _foo5: .byte 0x55 _bar1: .byte 0x66 + +.section .init,"ax",@progbits,unique,1 +_init1: + .byte 0x11 + +.section .init,"ax",@progbits,unique,2 +_init2: + .byte 0x22 diff --git a/test/ELF/symbol-override.s b/test/ELF/symbol-override.s index 8b62d8749aa0..2c3573381c1c 100644 --- a/test/ELF/symbol-override.s +++ b/test/ELF/symbol-override.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/symbol-override.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so diff --git a/test/ELF/symbols.s b/test/ELF/symbols.s index 54dfcbd087cd..e87b6438494a 100644 --- a/test/ELF/symbols.s +++ b/test/ELF/symbols.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t // RUN: ld.lld %t -o %t2 // RUN: llvm-readobj -symbols -sections %t2 | FileCheck %s -// REQUIRES: x86 .type _start, @function .globl _start diff --git a/test/ELF/symver-archive.s b/test/ELF/symver-archive.s index be50503a3f5d..3e22dd24b66d 100644 --- a/test/ELF/symver-archive.s +++ b/test/ELF/symver-archive.s @@ -4,7 +4,7 @@ # RUN: llvm-ar rcs %t.a %t1 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive1.s -o %t2.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/symver-archive2.s -o %t3.o -# RUN: ld.lld -o %t.out %t2.o %t3.o %t.a +# RUN: ld.lld -o /dev/null %t2.o %t3.o %t.a .text .globl x diff --git a/test/ELF/sysroot.s b/test/ELF/sysroot.s index 6b40c7d3952a..e9d6862b7a32 100644 --- a/test/ELF/sysroot.s +++ b/test/ELF/sysroot.s @@ -1,10 +1,10 @@ +// REQUIRES: x86 // RUN: mkdir -p %t/lib // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t/m.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ // RUN: %p/Inputs/libsearch-st.s -o %t/st.o // RUN: rm -f %t/lib/libls.a // RUN: llvm-ar rcs %t/lib/libls.a %t/st.o -// REQUIRES: x86 // Should not link because of undefined symbol _bar // RUN: not ld.lld -o %t/r %t/m.o 2>&1 \ diff --git a/test/ELF/sysv-hash-no-rosegment.s b/test/ELF/sysv-hash-no-rosegment.s new file mode 100644 index 000000000000..31b9d2fbec05 --- /dev/null +++ b/test/ELF/sysv-hash-no-rosegment.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld -shared --no-rosegment -o %t %t.o +# RUN: llvm-readobj -hash-table %t | FileCheck %s + +# CHECK: HashTable { +# CHECK-NEXT: Num Buckets: 2 +# CHECK-NEXT: Num Chains: 2 +# CHECK-NEXT: Buckets: [1, 0] +# CHECK-NEXT: Chains: [0, 0] +# CHECK-NEXT: } + +callq undef@PLT diff --git a/test/ELF/text-section-prefix.s b/test/ELF/text-section-prefix.s new file mode 100644 index 000000000000..e39536da387d --- /dev/null +++ b/test/ELF/text-section-prefix.s @@ -0,0 +1,39 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t +# RUN: ld.lld -z keep-text-section-prefix %t -o %t2 +# RUN: llvm-readelf -l %t2 | FileCheck %s +# RUN: ld.lld %t -o %t3 +# RUN: llvm-readelf -l %t3 | FileCheck --check-prefix=CHECKNO %s +# RUN: ld.lld -z nokeep-text-section-prefix %t -o %t4 +# RUN: llvm-readelf -l %t4 | FileCheck --check-prefix=CHECKNO %s + +# CHECK: .text +# CHECK: .text.hot +# CHECK: .text.startup +# CHECK: .text.exit +# CHECK: .text.unlikely +# CHECKNO: .text +# CHECKNO-NOT: .text.hot + +_start: + ret + +.section .text.f,"ax" +f: + nop + +.section .text.hot.f_hot,"ax" +f_hot: + nop + +.section .text.startup.f_startup,"ax" +f_startup: + nop + +.section .text.exit.f_exit,"ax" +f_exit: + nop + +.section .text.unlikely.f_unlikely,"ax" +f_unlikely: + nop diff --git a/test/ELF/tls-archive.s b/test/ELF/tls-archive.s index 9a88fddffd36..640e68ac3a7f 100644 --- a/test/ELF/tls-archive.s +++ b/test/ELF/tls-archive.s @@ -3,7 +3,7 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-mismatch.s -o %t2 // RUN: rm -f %t.a // RUN: llvm-ar cru %t.a %t2 -// RUN: ld.lld %t.a %t -o %t3 +// RUN: ld.lld %t.a %t -o /dev/null .globl _start,tlsvar _start: diff --git a/test/ELF/tls-error.s b/test/ELF/tls-error.s index b61789901049..989a63eb709b 100644 --- a/test/ELF/tls-error.s +++ b/test/ELF/tls-error.s @@ -1,6 +1,6 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -// RUN: not ld.lld %t -o %tout 2>&1 | FileCheck %s +// RUN: not ld.lld %t -o /dev/null 2>&1 | FileCheck %s // CHECK: R_X86_64_TPOFF32 out of range .global _start diff --git a/test/ELF/tls-got.s b/test/ELF/tls-got.s index b1686cd6d5f4..bedaaebeeb3c 100644 --- a/test/ELF/tls-got.s +++ b/test/ELF/tls-got.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-got.s -o %t2.o // RUN: ld.lld -shared %t2.o -o %t2.so @@ -25,13 +26,13 @@ // CHECK: Relocations [ // CHECK-NEXT: Section (4) .rela.dyn { // CHECK-NEXT: 0x2020B8 R_X86_64_TPOFF64 tls0 0x0 -// CHECK-NEXT: [[ADDR]] R_X86_64_TPOFF64 tls1 0x0 +// CHECK-NEXT: 0x2020B0 R_X86_64_TPOFF64 tls1 0x0 // CHECK-NEXT: } // CHECK-NEXT: ] -//0x201000 + 4249 + 7 = 0x2020B0 -//0x20100A + 4247 + 7 = 0x2020B8 -//0x201014 + 4237 + 7 = 0x2020B8 +//0x201000 + 4265 + 7 = 0x2020B0 +//0x20100A + 4263 + 7 = 0x2020B8 +//0x201014 + 4253 + 7 = 0x2020B8 //DISASM: Disassembly of section .text: //DISASM-NEXT: main: //DISASM-NEXT: 201000: 48 8b 05 a9 10 00 00 movq 4265(%rip), %rax diff --git a/test/ELF/tls-in-archive.s b/test/ELF/tls-in-archive.s index 71f60e380f33..ac1b4cc11ea4 100644 --- a/test/ELF/tls-in-archive.s +++ b/test/ELF/tls-in-archive.s @@ -2,7 +2,7 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-in-archive.s -o %t1.o // RUN: llvm-ar cru %t.a %t1.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o -// RUN: ld.lld %t2.o %t.a -o %tout +// RUN: ld.lld %t2.o %t.a -o /dev/null .globl _start _start: diff --git a/test/ELF/tls-mismatch.s b/test/ELF/tls-mismatch.s index 21994d19af32..d7ce224c1fbb 100644 --- a/test/ELF/tls-mismatch.s +++ b/test/ELF/tls-mismatch.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-mismatch.s -o %t2 -// RUN: not ld.lld %t %t2 -o %t3 2>&1 | FileCheck %s +// RUN: not ld.lld %t %t2 -o /dev/null 2>&1 | FileCheck %s // CHECK: TLS attribute mismatch: tlsvar // CHECK: >>> defined in diff --git a/test/ELF/tls-opt-gdie.s b/test/ELF/tls-opt-gdie.s index 6e8531257714..6d0eb979149a 100644 --- a/test/ELF/tls-opt-gdie.s +++ b/test/ELF/tls-opt-gdie.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/tls-opt-gdie.s -o %tso.o // RUN: ld.lld -shared %tso.o -o %t.so diff --git a/test/ELF/tls-opt-gdiele-i686.s b/test/ELF/tls-opt-gdiele-i686.s index 2dc3731eba57..b39f933e2fdb 100644 --- a/test/ELF/tls-opt-gdiele-i686.s +++ b/test/ELF/tls-opt-gdiele-i686.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-gdiele-i686.s -o %tso.o // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o // RUN: ld.lld -shared %tso.o -o %tso diff --git a/test/ELF/tls-opt-i686.s b/test/ELF/tls-opt-i686.s index dec45b4e5c41..d8b1d0eca0b7 100644 --- a/test/ELF/tls-opt-i686.s +++ b/test/ELF/tls-opt-i686.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o // RUN: ld.lld %t.o -o %t1 // RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s @@ -11,11 +12,11 @@ // LD -> LE: // DISASM-NEXT: 11000: 65 a1 00 00 00 00 movl %gs:0, %eax // DISASM-NEXT: 11006: 90 nop -// DISASM-NEXT: 11007: 8d 74 26 00 leal (%esi), %esi +// DISASM-NEXT: 11007: 8d 74 26 00 leal (%esi,%eiz), %esi // DISASM-NEXT: 1100b: 8d 90 f8 ff ff ff leal -8(%eax), %edx // DISASM-NEXT: 11011: 65 a1 00 00 00 00 movl %gs:0, %eax // DISASM-NEXT: 11017: 90 nop -// DISASM-NEXT: 11018: 8d 74 26 00 leal (%esi), %esi +// DISASM-NEXT: 11018: 8d 74 26 00 leal (%esi,%eiz), %esi // DISASM-NEXT: 1101c: 8d 90 fc ff ff ff leal -4(%eax), %edx // IE -> LE: // 4294967288 == 0xFFFFFFF8 diff --git a/test/ELF/tls-opt-iele-i686-nopic.s b/test/ELF/tls-opt-iele-i686-nopic.s index 02148b5dbff9..50655e34a4ff 100644 --- a/test/ELF/tls-opt-iele-i686-nopic.s +++ b/test/ELF/tls-opt-iele-i686-nopic.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=i686-pc-linux %p/Inputs/tls-opt-iele-i686-nopic.s -o %tso.o // RUN: ld.lld -shared %tso.o -o %tso diff --git a/test/ELF/tls-opt-local.s b/test/ELF/tls-opt-local.s index 633c22b0611c..e937d4d5d972 100644 --- a/test/ELF/tls-opt-local.s +++ b/test/ELF/tls-opt-local.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: ld.lld %t.o -o %t1 // RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s diff --git a/test/ELF/tls-opt-no-plt.s b/test/ELF/tls-opt-no-plt.s index 53655d0934d5..c61388648fb1 100644 --- a/test/ELF/tls-opt-no-plt.s +++ b/test/ELF/tls-opt-no-plt.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/tls-opt-gdie.s -o %t2.o // RUN: ld.lld %t2.o -o %t2.so -shared diff --git a/test/ELF/tls-opt.s b/test/ELF/tls-opt.s index 6835e06f3402..856e82c4b323 100644 --- a/test/ELF/tls-opt.s +++ b/test/ELF/tls-opt.s @@ -1,3 +1,4 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o // RUN: ld.lld %t.o -o %t1 // RUN: llvm-readobj -r %t1 | FileCheck --check-prefix=NORELOC %s diff --git a/test/ELF/tls-static.s b/test/ELF/tls-static.s index 338d95c817ee..3e1aead01a30 100644 --- a/test/ELF/tls-static.s +++ b/test/ELF/tls-static.s @@ -1,10 +1,10 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/shared.s -o %tso // RUN: ld.lld -static %t -o %tout // RUN: ld.lld %t -o %tout // RUN: ld.lld -shared %tso -o %tshared // RUN: ld.lld -static %t %tshared -o %tout -// REQUIRES: x86 .global _start _start: diff --git a/test/ELF/trace-symbols.s b/test/ELF/trace-symbols.s index c8ba9b21bcdb..b5c1ddc2a558 100644 --- a/test/ELF/trace-symbols.s +++ b/test/ELF/trace-symbols.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # Test -y symbol and -trace-symbol=symbol # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t @@ -28,7 +29,7 @@ # RUN: ld.lld -y foo -trace-symbol=common -trace-symbol=hsymbol \ # RUN: %t %t1 %t2 -o %t3 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s # RUN: ld.lld -y foo -y common --trace-symbol=hsymbol \ -# RUN: %t %t2 %t1 -o %t4 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s +# RUN: %t %t2 %t1 -o /dev/null 2>&1 | FileCheck -check-prefix=OBJECTD2FOO %s # RUN: ld.lld -y foo -y common %t %t1.so %t2 -o %t3 2>&1 | \ # RUN: FileCheck -check-prefix=OBJECTD2FOO %s # OBJECTD2FOO: trace-symbols.s.tmp2: definition of foo @@ -69,12 +70,15 @@ # RUN: ld.lld -y foo -y bar %t %t1.so %t2.so -o %t3 | \ # RUN: FileCheck -check-prefix=SHLIBRBAR %s -# SHLIBRBAR-NOT: trace-symbols.s.tmp1.so: reference to bar +# SHLIBRBAR: trace-symbols.s.tmp1.so: reference to bar # RUN: ld.lld -y foo -y bar %t -u bar --start-lib %t1 %t2 --end-lib -o %t3 | \ # RUN: FileCheck -check-prefix=STARTLIB %s # STARTLIB: trace-symbols.s.tmp1: reference to bar +## Check we do not crash when trying to trace special symbol. +# RUN: not ld.lld -trace-symbol=_end %t -o /dev/null + .hidden hsymbol .globl _start .type _start, @function diff --git a/test/ELF/typed-undef.s b/test/ELF/typed-undef.s index d00e07f82518..879a80975bc8 100644 --- a/test/ELF/typed-undef.s +++ b/test/ELF/typed-undef.s @@ -3,7 +3,7 @@ # We used to crash on this, check that we don't # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: ld.lld %t.o -o %t -pie --unresolved-symbols=ignore-all +# RUN: ld.lld %t.o -o /dev/null -pie --unresolved-symbols=ignore-all .global _start _start: diff --git a/test/ELF/undef-broken-debug.test b/test/ELF/undef-broken-debug.test index 1238ebe70aca..b93d399f36c2 100644 --- a/test/ELF/undef-broken-debug.test +++ b/test/ELF/undef-broken-debug.test @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: yaml2obj %s -o %t.o -# RUN: not ld.lld %t.o -o %t.exe 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s # The debug info has a broken relocation. Check that we don't crash # and still report the undefined symbol. @@ -40,6 +40,27 @@ Sections: - Offset: 0x0000000000000029 Symbol: bar Type: R_X86_64_64 + - Name: .debug_info + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: 0C000000040000000000080100000000 + - Name: .rela.debug_info + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .debug_info + Relocations: + - Offset: 0x0000000000000006 + Symbol: .debug_abbrev + Type: R_X86_64_32 + - Offset: 0x000000000000000C + Symbol: .debug_line + Type: R_X86_64_32 + - Name: .debug_abbrev + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + Content: '0111001017000000' + Symbols: Global: - Name: _start diff --git a/test/ELF/undef-shared.s b/test/ELF/undef-shared.s index bc38b6082765..701f70ea94e6 100644 --- a/test/ELF/undef-shared.s +++ b/test/ELF/undef-shared.s @@ -1,5 +1,6 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s # CHECK: error: undefined symbol: hidden # CHECK: >>> referenced by {{.*}}:(.data+0x0) diff --git a/test/ELF/undef-shared2.s b/test/ELF/undef-shared2.s new file mode 100644 index 000000000000..cae5ea45642d --- /dev/null +++ b/test/ELF/undef-shared2.s @@ -0,0 +1,11 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-shared2.s -o %t2.o +# RUN: not ld.lld %t.o %t2.o -o %t.so -shared 2>&1 | FileCheck %s +# RUN: not ld.lld %t2.o %t.o -o %t.so -shared 2>&1 | FileCheck %s + +# CHECK: error: undefined symbol: foo + +.data +.quad foo +.protected foo diff --git a/test/ELF/undef-start.s b/test/ELF/undef-start.s index 590d0a80096b..5c591bf70d52 100644 --- a/test/ELF/undef-start.s +++ b/test/ELF/undef-start.s @@ -1,3 +1,5 @@ -# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t -# RUN: ld.lld %t -o %t2 2>&1 # REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +# CHECK: warning: cannot find entry symbol _start diff --git a/test/ELF/undef-version-script.s b/test/ELF/undef-version-script.s index 024ac1dc0727..712589e2444f 100644 --- a/test/ELF/undef-version-script.s +++ b/test/ELF/undef-version-script.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: echo "{ local: *; };" > %t.script # RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so diff --git a/test/ELF/undef.s b/test/ELF/undef.s index 49f84108f64a..07e3b689a236 100644 --- a/test/ELF/undef.s +++ b/test/ELF/undef.s @@ -2,9 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef.s -o %t2.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-debug.s -o %t3.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/undef-bad-debug.s -o %t4.o # RUN: llvm-ar rc %t2.a %t2.o -# RUN: not ld.lld %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s -# RUN: not ld.lld -pie %t.o %t2.a %t3.o -o %t.exe 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o %t2.a %t3.o %t4.o -o %t.exe 2>&1 | FileCheck %s +# RUN: not ld.lld -pie %t.o %t2.a %t3.o %t4.o -o %t.exe 2>&1 | FileCheck %s # CHECK: error: undefined symbol: foo # CHECK: >>> referenced by undef.s @@ -33,6 +34,19 @@ # CHECK: >>> referenced by undef-debug.s:11 (dir{{/|\\}}undef-debug.s:11) # CHECK: >>> {{.*}}.o:(.text.2+0x0) +# Show that all line table problems are mentioned as soon as the object's line information +# is requested, even if that particular part of the line information is not currently required. +# CHECK: warning: parsing line table prologue at 0x00000000 should have ended at 0x00000038 but it ended at 0x00000037 +# CHECK: warning: last sequence in debug line table is not terminated! +# CHECK: error: undefined symbol: zed6 +# CHECK: >>> referenced by {{.*}}tmp4.o:(.text+0x0) + +# Show that a problem with one line table's information doesn't affect getting information from +# a different one in the same object. +# CHECK: error: undefined symbol: zed7 +# CHECK: >>> referenced by undef-bad-debug2.s:11 (dir2{{/|\\}}undef-bad-debug2.s:11) +# CHECK: >>> {{.*}}tmp4.o:(.text+0x8) + # RUN: not ld.lld %t.o %t2.a -o %t.exe -no-demangle 2>&1 | \ # RUN: FileCheck -check-prefix=NO-DEMANGLE %s # NO-DEMANGLE: error: undefined symbol: _Z3fooi diff --git a/test/ELF/undefined-opt.s b/test/ELF/undefined-opt.s index d8b793d7bab4..9e93e0fdce4d 100644 --- a/test/ELF/undefined-opt.s +++ b/test/ELF/undefined-opt.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux \ # RUN: %p/Inputs/abs.s -o %tabs.o @@ -5,7 +6,6 @@ # RUN: %p/Inputs/shared.s -o %tshared.o # RUN: rm -f %tar.a # RUN: llvm-ar rcs %tar.a %tabs.o %tshared.o -# REQUIRES: x86 # Symbols from the archive are not in if not needed # RUN: ld.lld -o %t1 %t.o %tar.a diff --git a/test/ELF/unresolved-symbols.s b/test/ELF/unresolved-symbols.s index 97ecd5014b12..69da3e63c6d4 100644 --- a/test/ELF/unresolved-symbols.s +++ b/test/ELF/unresolved-symbols.s @@ -21,7 +21,7 @@ ## case when --no-undefined specified. # RUN: ld.lld %t2.o -o %t1_1 --unresolved-symbols=ignore-all # RUN: llvm-readobj %t1_1 > /dev/null 2>&1 -# RUN: not ld.lld %t2.o -o %t1_2 --unresolved-symbols=ignore-all --no-undefined 2>&1 | \ +# RUN: not ld.lld %t2.o -o /dev/null --unresolved-symbols=ignore-all --no-undefined 2>&1 | \ # RUN: FileCheck -check-prefix=ERRUND %s # ERRUND: error: undefined symbol: undef # ERRUND: >>> referenced by {{.*}}:(.text+0x1) @@ -34,11 +34,11 @@ # RUN: ld.lld %t1.o %t2.o -o %t2 --unresolved-symbols=ignore-in-object-files # RUN: llvm-readobj %t2 > /dev/null 2>&1 ## And still should not should produce for undefines from DSOs. -# RUN: ld.lld %t1.o %t.so -o %t2_1 --unresolved-symbols=ignore-in-object-files +# RUN: ld.lld %t1.o %t.so -o /dev/null --unresolved-symbols=ignore-in-object-files # RUN: llvm-readobj %t2 > /dev/null 2>&1 ## Ignoring undefines in shared should produce error for symbol from object. -# RUN: not ld.lld %t2.o -o %t3 --unresolved-symbols=ignore-in-shared-libs 2>&1 | \ +# RUN: not ld.lld %t2.o -o /dev/null --unresolved-symbols=ignore-in-shared-libs 2>&1 | \ # RUN: FileCheck -check-prefix=ERRUND %s ## And should not produce errors for symbols from DSO. # RUN: ld.lld %t1.o %t.so -o %t3_1 --unresolved-symbols=ignore-in-shared-libs @@ -60,9 +60,9 @@ # RUN: llvm-readobj %t6 > /dev/null 2>&1 # RUN: ld.lld -shared %t1.o %t.so -o %t6_1 # RUN: llvm-readobj %t6_1 > /dev/null 2>&1 -# RUN: not ld.lld %t2.o -o %t7 --unresolved-symbols=report-all 2>&1 | \ +# RUN: not ld.lld %t2.o -o /dev/null --unresolved-symbols=report-all 2>&1 | \ # RUN: FileCheck -check-prefix=ERRUND %s -# RUN: not ld.lld %t2.o -o %t7_1 2>&1 | FileCheck -check-prefix=ERRUND %s +# RUN: not ld.lld %t2.o -o /dev/null 2>&1 | FileCheck -check-prefix=ERRUND %s .globl _start _start: diff --git a/test/ELF/user_def_init_array_start.s b/test/ELF/user_def_init_array_start.s index 6c33166d1d4e..a06dbd84ea43 100644 --- a/test/ELF/user_def_init_array_start.s +++ b/test/ELF/user_def_init_array_start.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -// RUN: ld.lld %t.o -o %t2.so -shared +// RUN: ld.lld %t.o -o /dev/null -shared // Allow user defined __init_array_start. This is used by musl because of the // the bfd linker not handling these properly. We always create them as // hidden, musl should not have problems with lld. diff --git a/test/ELF/verdef-defaultver.s b/test/ELF/verdef-defaultver.s index 496a29e3db5a..c8444c4e0663 100644 --- a/test/ELF/verdef-defaultver.s +++ b/test/ELF/verdef-defaultver.s @@ -196,6 +196,6 @@ .globl _start _start: - callq a - callq b - callq c + .long a - . + .long b - . + .long c - . diff --git a/test/ELF/verneed-local.s b/test/ELF/verneed-local.s index 208d8ecf8f62..d779a48c024d 100644 --- a/test/ELF/verneed-local.s +++ b/test/ELF/verneed-local.s @@ -4,7 +4,7 @@ # RUN: ld.lld -shared %t1.o --version-script %t.script -o %t.so # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: not ld.lld %t.o %t.so -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o %t.so -o /dev/null 2>&1 | FileCheck %s # CHECK: error: undefined symbol: f3 # CHECK: >>> referenced by {{.*}}:(.text+0x1) diff --git a/test/ELF/verneed.s b/test/ELF/verneed.s index 27ab047e8222..6e87f046e304 100644 --- a/test/ELF/verneed.s +++ b/test/ELF/verneed.s @@ -10,67 +10,69 @@ # RUN: llvm-readobj -V -sections -section-data -dyn-symbols -dynamic-table %t | FileCheck %s # CHECK: Section { -# CHECK: Index: 1 -# CHECK-NEXT: Name: .dynsym -# CHECK-NEXT: Type: SHT_DYNSYM (0xB) +# CHECK: Index: 1 +# CHECK-NEXT: Name: .dynsym +# CHECK-NEXT: Type: SHT_DYNSYM (0xB) +# CHECK-NEXT: Flags [ (0x2) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2001C8 +# CHECK-NEXT: Offset: 0x1C8 +# CHECK-NEXT: Size: 96 +# CHECK-NEXT: Link: [[DYNSTR:.*]] +# CHECK-NEXT: Info: 1 +# CHECK-NEXT: AddressAlignment: 8 +# CHECK-NEXT: EntrySize: 24 + +# CHECK: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .gnu.version +# CHECK-NEXT: Type: SHT_GNU_versym (0x6FFFFFFF) # CHECK-NEXT: Flags [ (0x2) # CHECK-NEXT: SHF_ALLOC (0x2) # CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x2001C8 -# CHECK-NEXT: Offset: 0x1C8 -# CHECK-NEXT: Size: 96 -# CHECK-NEXT: Link: 5 -# CHECK-NEXT: Info: 1 -# CHECK-NEXT: AddressAlignment: 8 -# CHECK-NEXT: EntrySize: 24 -# CHECK: Section { -# CHECK-NEXT: Index: 2 -# CHECK-NEXT: Name: .gnu.version -# CHECK-NEXT: Type: SHT_GNU_versym (0x6FFFFFFF) -# CHECK-NEXT: Flags [ (0x2) -# CHECK-NEXT: SHF_ALLOC (0x2) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x200228 -# CHECK-NEXT: Offset: 0x228 -# CHECK-NEXT: Size: 8 -# CHECK-NEXT: Link: 1 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 2 -# CHECK-NEXT: EntrySize: 2 +# CHECK-NEXT: Address: [[VERSYM:.*]] +# CHECK-NEXT: Offset: [[VERSYM_OFFSET:.*]] +# CHECK-NEXT: Size: 8 +# CHECK-NEXT: Link: 1 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 2 +# CHECK-NEXT: EntrySize: 2 + # CHECK: Section { -# CHECK-NEXT: Index: 3 -# CHECK-NEXT: Name: .gnu.version_r -# CHECK-NEXT: Type: SHT_GNU_verneed (0x6FFFFFFE) -# CHECK-NEXT: Flags [ (0x2) -# CHECK-NEXT: SHF_ALLOC (0x2) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x200230 -# CHECK-NEXT: Offset: 0x230 -# CHECK-NEXT: Size: 80 -# CHECK-NEXT: Link: 5 -# CHECK-NEXT: Info: 2 -# CHECK-NEXT: AddressAlignment: 4 -# CHECK-NEXT: EntrySize: 0 -# CHECK: Section { -# CHECK: Index: 5 -# CHECK-NEXT: Name: .dynstr -# CHECK-NEXT: Type: SHT_STRTAB -# CHECK-NEXT: Flags [ (0x2) -# CHECK-NEXT: SHF_ALLOC (0x2) -# CHECK-NEXT: ] -# CHECK-NEXT: Address: 0x2002A8 -# CHECK-NEXT: Offset: 0x2A8 -# CHECK-NEXT: Size: 47 -# CHECK-NEXT: Link: 0 -# CHECK-NEXT: Info: 0 -# CHECK-NEXT: AddressAlignment: 1 -# CHECK-NEXT: EntrySize: 0 -# CHECK-NEXT: SectionData ( -# CHECK-NEXT: 0000: 00766572 6E656564 312E736F 2E300076 |.verneed1.so.0.v| -# CHECK-NEXT: 0010: 65726E65 6564322E 736F2E30 00663100 |erneed2.so.0.f1.| -# CHECK-NEXT: 0020: 76330066 32007632 00673100 763100 |v3.f2.v2.g1.v1.| -# CHECK-NEXT: ) -# CHECK-NEXT: } +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .gnu.version_r +# CHECK-NEXT: Type: SHT_GNU_verneed (0x6FFFFFFE) +# CHECK-NEXT: Flags [ (0x2) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: [[VERNEED:.*]] +# CHECK-NEXT: Offset: 0x230 +# CHECK-NEXT: Size: 80 +# CHECK-NEXT: Link: 5 +# CHECK-NEXT: Info: 2 +# CHECK-NEXT: AddressAlignment: 4 +# CHECK-NEXT: EntrySize: 0 + +# CHECK: Index: [[DYNSTR]] +# CHECK-NEXT: Name: .dynstr +# CHECK-NEXT: Type: SHT_STRTAB (0x3) +# CHECK-NEXT: Flags [ (0x2) +# CHECK-NEXT: SHF_ALLOC (0x2) +# CHECK-NEXT: ] +# CHECK-NEXT: Address: 0x2002A8 +# CHECK-NEXT: Offset: 0x2A8 +# CHECK-NEXT: Size: 47 +# CHECK-NEXT: Link: 0 +# CHECK-NEXT: Info: 0 +# CHECK-NEXT: AddressAlignment: 1 +# CHECK-NEXT: EntrySize: 0 +# CHECK-NEXT: SectionData ( +# CHECK-NEXT: 0000: 00766572 6E656564 312E736F 2E300076 |.verneed1.so.0.v| +# CHECK-NEXT: 0010: 65726E65 6564322E 736F2E30 00663100 |erneed2.so.0.f1.| +# CHECK-NEXT: 0020: 76330066 32007632 00673100 763100 |v3.f2.v2.g1.v1.| +# CHECK-NEXT: ) +# CHECK-NEXT: } # CHECK: DynamicSymbols [ # CHECK-NEXT: Symbol { @@ -111,14 +113,14 @@ # CHECK-NEXT: } # CHECK-NEXT: ] -# CHECK: 0x000000006FFFFFF0 VERSYM 0x200228 -# CHECK-NEXT: 0x000000006FFFFFFE VERNEED 0x200230 +# CHECK: 0x000000006FFFFFF0 VERSYM [[VERSYM]] +# CHECK-NEXT: 0x000000006FFFFFFE VERNEED [[VERNEED]] # CHECK-NEXT: 0x000000006FFFFFFF VERNEEDNUM 2 # CHECK: Version symbols { # CHECK-NEXT: Section Name: .gnu.version -# CHECK-NEXT: Address: 0x200228 -# CHECK-NEXT: Offset: 0x228 +# CHECK-NEXT: Address: [[VERSYM]] +# CHECK-NEXT: Offset: [[VERSYM_OFFSET]] # CHECK-NEXT: Link: 1 # CHECK-NEXT: Symbols [ # CHECK-NEXT: Symbol { diff --git a/test/ELF/version-exclude-libs.s b/test/ELF/version-exclude-libs.s new file mode 100644 index 000000000000..7335c2315eba --- /dev/null +++ b/test/ELF/version-exclude-libs.s @@ -0,0 +1,30 @@ +// REQUIRES: x86 +// RUN: llvm-mc %p/Inputs/versiondef.s -o %t.o -filetype=obj -triple=x86_64-pc-linux +// RUN: llvm-ar -r %t.a %t.o +// RUN: llvm-mc %s -o %t2.o -filetype=obj -triple=x86_64-pc-linux +// RUN: ld.lld %t2.o %t.a --shared --exclude-libs ALL -o %t.so +// RUN: llvm-readobj -symbols %t.so | FileCheck %s +// RUN: llvm-readobj -dyn-symbols %t.so | FileCheck -check-prefix CHECK-DYN %s +// RUN: not ld.lld %t2.o %t.a --shared -o %t.so 2>&1 | FileCheck -check-prefix=CHECK-ERR %s + +// Test that we do not give an error message for undefined versions when the +// symbol is not exported to the dynamic symbol table. + +// CHECK: Name: func +// CHECK-NEXT: Value: +// CHECK-NEXT: Size: +// CHECK-NEXT: Binding: Local (0x0) + +// CHECK-DYN-NOT: func + +// CHECK-ERR: symbol func@@VER2 has undefined version VER2 +// CHECK-ERR-NEXT: symbol func@VER has undefined version VER + + .text + .globl _start + .globl func +_start: + ret + + .data + .quad func diff --git a/test/ELF/version-script-complex-wildcards.s b/test/ELF/version-script-complex-wildcards.s index 61e1069e2eac..ce001d0b76c3 100644 --- a/test/ELF/version-script-complex-wildcards.s +++ b/test/ELF/version-script-complex-wildcards.s @@ -46,7 +46,7 @@ # RUN: llvm-readobj -V %t8.so | FileCheck %s --check-prefix=ABBABC # RUN: echo "FOO { global: extern \"C++\" { a[; }; };" > %t9.script -# RUN: not ld.lld --version-script %t9.script -shared %t.o -o %t9.so 2>&1 \ +# RUN: not ld.lld --version-script %t9.script -shared %t.o -o /dev/null 2>&1 \ # RUN: | FileCheck %s --check-prefix=ERROR # ERROR: invalid glob pattern: a[ diff --git a/test/ELF/version-script-extern-undefined.s b/test/ELF/version-script-extern-undefined.s new file mode 100644 index 000000000000..518b122ce7cd --- /dev/null +++ b/test/ELF/version-script-extern-undefined.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "FOO { global: extern \"C++\" { \"abb(int)\"; }; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: @ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 1 +# CHECK-NEXT: Name: _Z3abbi@ +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.globl _Z3abbi diff --git a/test/ELF/version-script-extern.s b/test/ELF/version-script-extern.s index c63ff817fb40..16f400354356 100644 --- a/test/ELF/version-script-extern.s +++ b/test/ELF/version-script-extern.s @@ -7,7 +7,7 @@ # RUN: echo "LIBSAMPLE_2.0 { global:" >> %t.script # RUN: echo ' extern "C" { _Z3bari; };' >> %t.script # RUN: echo "};" >> %t.script -# RUN: ld.lld --hash-style=sysv --version-script %t.script -shared %t.o -o %t.so +# RUN: ld.lld --hash-style=sysv --version-script %t.script -soname fixed-length-string -shared %t.o -o %t.so # RUN: llvm-readobj -V -dyn-symbols %t.so | FileCheck --check-prefix=DSO %s # DSO: DynamicSymbols [ diff --git a/test/ELF/version-script-extern2.s b/test/ELF/version-script-extern2.s new file mode 100644 index 000000000000..834bbe1122e5 --- /dev/null +++ b/test/ELF/version-script-extern2.s @@ -0,0 +1,22 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: echo "FOO { global: extern \"C++\" { \"bar\"; }; };" > %t.script +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: llvm-readobj -V %t.so | FileCheck %s + +# CHECK: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 0 +# CHECK-NEXT: Name: @ +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: bar@@FOO +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.globl bar +.type bar,@function +bar: +retq diff --git a/test/ELF/version-script-glob.s b/test/ELF/version-script-glob.s index 8149ead8292f..d9ead0503d64 100644 --- a/test/ELF/version-script-glob.s +++ b/test/ELF/version-script-glob.s @@ -48,7 +48,7 @@ local: # CHECK-NEXT: ] # RUN: echo "{ global : local; local: *; };" > %t1.script -# RUN: ld.lld -shared --version-script %t1.script %t.o -o %t1.so +# RUN: ld.lld -shared --version-script %t1.script %t.o -o /dev/null # LOCAL: DynamicSymbols [ # LOCAL-NEXT: Symbol { diff --git a/test/ELF/version-script-in-search-path.s b/test/ELF/version-script-in-search-path.s new file mode 100644 index 000000000000..948f33792a9c --- /dev/null +++ b/test/ELF/version-script-in-search-path.s @@ -0,0 +1,10 @@ +# REQUIRES: x86 +# Check that we fall back to search paths if a version script was not found +# This behaviour matches ld.bfd. + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: mkdir -p %T/searchpath +# RUN: echo '{};' > %T/searchpath/%basename_t.script +# RUN: ld.lld -L%T/searchpath --version-script=%basename_t.script %t.o -o /dev/null +# RUN: not ld.lld --version-script=%basename_t.script %t.o 2>&1 | FileCheck -check-prefix ERROR %s +# ERROR: error: cannot find version script diff --git a/test/ELF/version-script-missing.s b/test/ELF/version-script-missing.s index ad4786e70cc5..a82a37e41271 100644 --- a/test/ELF/version-script-missing.s +++ b/test/ELF/version-script-missing.s @@ -4,4 +4,4 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: echo "{ foobar; };" > %t.script -# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: ld.lld --version-script %t.script -shared %t.o -o /dev/null diff --git a/test/ELF/version-script-no-warn.s b/test/ELF/version-script-no-warn.s index 6a897159d2d0..d99b87bf937b 100644 --- a/test/ELF/version-script-no-warn.s +++ b/test/ELF/version-script-no-warn.s @@ -5,7 +5,7 @@ # RUN: ld.lld -shared %t2.o -soname shared -o %t2.so # RUN: echo "foo { global: bar; local: *; };" > %t.script -# RUN: ld.lld --fatal-warnings --shared --version-script %t.script %t.o %t2.so +# RUN: ld.lld --fatal-warnings --shared --version-script %t.script %t.o %t2.so -o /dev/null .global bar bar: diff --git a/test/ELF/version-script-no-warn2.s b/test/ELF/version-script-no-warn2.s index 52beff366bb7..795fbb0b4f28 100644 --- a/test/ELF/version-script-no-warn2.s +++ b/test/ELF/version-script-no-warn2.s @@ -1,8 +1,9 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/version-script-no-warn2.s -o %t1.o # RUN: ld.lld %t1.o -o %t1.so -shared # RUN: echo "{ global: foo; local: *; };" > %t.script # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t2.o -# RUN: ld.lld -shared --version-script %t.script %t2.o %t1.so -o %t2.so --fatal-warnings +# RUN: ld.lld -shared --version-script %t.script %t2.o %t1.so -o /dev/null --fatal-warnings .global foo foo: diff --git a/test/ELF/version-script-noundef.s b/test/ELF/version-script-noundef.s index 247752cac844..0eae1fcdb05a 100644 --- a/test/ELF/version-script-noundef.s +++ b/test/ELF/version-script-noundef.s @@ -2,6 +2,8 @@ # RUN: echo "VERSION_1.0 { global: bar; };" > %t.script # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld --version-script %t.script -shared %t.o -o %t.so +# RUN: ld.lld --version-script %t.script -shared --undefined-version %t.o -o %t.so # RUN: not ld.lld --version-script %t.script -shared --no-undefined-version \ # RUN: %t.o -o %t.so 2>&1 | FileCheck -check-prefix=ERR1 %s # ERR1: version script assignment of 'VERSION_1.0' to symbol 'bar' failed: symbol not defined diff --git a/test/ELF/version-script-symver.s b/test/ELF/version-script-symver.s index 0a4eddd46cec..b6355949fad0 100644 --- a/test/ELF/version-script-symver.s +++ b/test/ELF/version-script-symver.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: ld.lld %t.o -o %t +# RUN: ld.lld %t.o -o /dev/null .global _start .global bar diff --git a/test/ELF/version-script.s b/test/ELF/version-script.s index abc716250eba..75083ac9a767 100644 --- a/test/ELF/version-script.s +++ b/test/ELF/version-script.s @@ -34,9 +34,9 @@ # RUN: echo "VERSION_1.0 { global: foo1; local: *; };" > %t6.script # RUN: echo "VERSION_2.0 { global: foo1; local: *; };" >> %t6.script -# RUN: ld.lld --version-script %t6.script -shared %t.o %t2.so -o %t6.so 2>&1 | \ -# RUN: FileCheck -check-prefix=WARN2 %s -# WARN2: duplicate symbol 'foo1' in version script +# RUN: not ld.lld --version-script %t6.script -shared %t.o %t2.so -o /dev/null 2>&1 | \ +# RUN: FileCheck -check-prefix=ERR3 %s +# ERR3: duplicate symbol 'foo1' in version script # RUN: echo "{ foo1; foo2; };" > %t.list # RUN: ld.lld --version-script %t.script --dynamic-list %t.list %t.o %t2.so -o %t2 @@ -213,6 +213,9 @@ # ALL-NEXT: } # ALL-NEXT: ] +# RUN: echo "VERSION_1.0 { global: foo1; foo1; local: *; };" > %t8.script +# RUN: ld.lld --version-script %t8.script -shared %t.o -o /dev/null --fatal-warnings + .globl foo1 foo1: call bar@PLT diff --git a/test/ELF/version-symbol-error.s b/test/ELF/version-symbol-error.s index fb83b359485b..f916fe7b34f8 100644 --- a/test/ELF/version-symbol-error.s +++ b/test/ELF/version-symbol-error.s @@ -1,7 +1,7 @@ // REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux // RUN: echo "V1 {};" > %t.script -// RUN: not ld.lld -shared -version-script=%t.script %t.o -o %t.so 2>&1 \ +// RUN: not ld.lld -shared -version-script=%t.script %t.o -o /dev/null 2>&1 \ // RUN: | FileCheck %s // CHECK: .o: symbol foo@V2 has undefined version V2 diff --git a/test/ELF/version-undef-sym.s b/test/ELF/version-undef-sym.s index 20e92e61f647..13a6dc41fd10 100644 --- a/test/ELF/version-undef-sym.s +++ b/test/ELF/version-undef-sym.s @@ -35,7 +35,7 @@ // CHECK: Name: bar // But now we can successfully find bar. -// RUN: ld.lld %t.o %p/Inputs/version-undef-sym.so -o %t.exe +// RUN: ld.lld %t.o %p/Inputs/version-undef-sym.so -o /dev/null .global _start _start: diff --git a/test/ELF/visibility.s b/test/ELF/visibility.s index 7af29c957b52..0582d718e8ee 100644 --- a/test/ELF/visibility.s +++ b/test/ELF/visibility.s @@ -1,8 +1,8 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/visibility.s -o %t2 // RUN: ld.lld -shared %t %t2 -o %t3 // RUN: llvm-readobj -t -dyn-symbols %t3 | FileCheck %s -// REQUIRES: x86 // CHECK: Symbols [ // CHECK-NEXT: Symbol { diff --git a/test/ELF/warn-backrefs.s b/test/ELF/warn-backrefs.s new file mode 100644 index 000000000000..28937e199cae --- /dev/null +++ b/test/ELF/warn-backrefs.s @@ -0,0 +1,48 @@ +# REQUIRES: x86 + +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: echo ".globl foo; foo:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t2.o +# RUN: rm -f %t2.a +# RUN: llvm-ar rcs %t2.a %t2.o + +# RUN: ld.lld --fatal-warnings -o %t.exe %t1.o %t2.a +# RUN: ld.lld --fatal-warnings -o %t.exe %t2.a %t1.o +# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.o %t2.a +# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.o --start-lib %t2.o --end-lib + +# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe --start-group %t2.a %t1.o --end-group +# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe "-(" %t2.a %t1.o "-)" + +# RUN: echo "INPUT(\"%t1.o\" \"%t2.a\")" > %t1.script +# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t1.script + +# RUN: echo "GROUP(\"%t2.a\" \"%t1.o\")" > %t2.script +# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.script + +# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.a %t1.o 2>&1 | FileCheck %s +# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t2.a "-(" %t1.o "-)" 2>&1 | FileCheck %s +# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe --start-group %t2.a --end-group %t1.o 2>&1 | FileCheck %s + +# RUN: echo "GROUP(\"%t2.a\")" > %t3.script +# RUN: not ld.lld --fatal-warnings --warn-backrefs -o %t.exe %t3.script %t1.o 2>&1 | FileCheck %s +# RUN: ld.lld --fatal-warnings --warn-backrefs -o %t.exe "-(" %t3.script %t1.o "-)" + +# CHECK: backward reference detected: foo in {{.*}}1.o refers to {{.*}}2.a + +# RUN: not ld.lld --fatal-warnings --start-group --start-group 2>&1 | FileCheck -check-prefix=START %s +# START: nested --start-group + +# RUN: not ld.lld --fatal-warnings --end-group 2>&1 | FileCheck -check-prefix=END %s +# END: stray --end-group + +# RUN: echo ".globl bar; bar:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t3.o +# RUN: echo ".globl foo; foo: call bar" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t4.o +# RUN: ld.lld --fatal-warnings --warn-backrefs %t1.o --start-lib %t3.o %t4.o --end-lib -o /dev/null + +# We don't report backward references to weak symbols as they can be overriden later. +# RUN: echo ".weak foo; foo:" | llvm-mc -filetype=obj -triple=x86_64-unknown-linux - -o %t5.o +# RUN: ld.lld --fatal-warnings --warn-backrefs --start-lib %t5.o --end-lib %t1.o %t2.o -o /dev/null + +.globl _start, foo +_start: + call foo diff --git a/test/ELF/warn-common.s b/test/ELF/warn-common.s index 783a9ab77b56..ddb4b687a5aa 100644 --- a/test/ELF/warn-common.s +++ b/test/ELF/warn-common.s @@ -7,9 +7,7 @@ # RUN: ld.lld --warn-common %t1.o %t2.o -o %t.out 2>&1 | FileCheck %s --check-prefix=WARN # WARN: multiple common of arr -## no-warn-common is ignored -# RUN: ld.lld --no-warn-common %t1.o %t2.o -o %t.out -# RUN: llvm-readobj %t.out > /dev/null +# RUN: ld.lld --fatal-warnings --warn-common --no-warn-common %t1.o %t2.o -o %t.out ## Report if common is overridden # RUN: ld.lld --warn-common %t1.o %t3.o -o %t.out 2>&1 | FileCheck %s --check-prefix=OVER diff --git a/test/ELF/warn-unresolved-symbols-hidden.s b/test/ELF/warn-unresolved-symbols-hidden.s index 04691f9af948..9e3d9e152104 100644 --- a/test/ELF/warn-unresolved-symbols-hidden.s +++ b/test/ELF/warn-unresolved-symbols-hidden.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: not ld.lld -shared %t.o -o %t.so -z defs --warn-unresolved-symbols 2>&1| FileCheck %s +# RUN: not ld.lld -shared %t.o -o /dev/null -z defs --warn-unresolved-symbols 2>&1| FileCheck %s # CHECK: warning: undefined symbol: foo # CHECK: error: undefined symbol: bar diff --git a/test/ELF/warn-unresolved-symbols.s b/test/ELF/warn-unresolved-symbols.s index 3342c6ce50a2..608b35580291 100644 --- a/test/ELF/warn-unresolved-symbols.s +++ b/test/ELF/warn-unresolved-symbols.s @@ -2,11 +2,11 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o ## The link should fail with an undef error by default -# RUN: not ld.lld %t1.o -o %t3 2>&1 | \ +# RUN: not ld.lld %t1.o -o /dev/null 2>&1 | \ # RUN: FileCheck -check-prefix=ERRUND %s ## --error-unresolved-symbols should generate an error -# RUN: not ld.lld %t1.o -o %t4 --error-unresolved-symbols 2>&1 | \ +# RUN: not ld.lld %t1.o -o /dev/null --error-unresolved-symbols 2>&1 | \ # RUN: FileCheck -check-prefix=ERRUND %s ## --warn-unresolved-symbols should generate a warning @@ -16,19 +16,19 @@ ## Test that the last option wins # RUN: ld.lld %t1.o -o %t5 --error-unresolved-symbols --warn-unresolved-symbols 2>&1 | \ # RUN: FileCheck -check-prefix=WARNUND %s -# RUN: not ld.lld %t1.o -o %t6 --warn-unresolved-symbols --error-unresolved-symbols 2>&1 | \ +# RUN: not ld.lld %t1.o -o /dev/null --warn-unresolved-symbols --error-unresolved-symbols 2>&1 | \ # RUN: FileCheck -check-prefix=ERRUND %s ## Do not report undefines if linking relocatable or shared. ## And while we're at it, check that we can accept single - ## variants of these options. -# RUN: ld.lld -r %t1.o -o %t7 -error-unresolved-symbols 2>&1 | \ +# RUN: ld.lld -r %t1.o -o /dev/null -error-unresolved-symbols 2>&1 | \ # RUN: FileCheck -allow-empty -check-prefix=NOERR %s -# RUN: ld.lld -shared %t1.o -o %t8.so --error-unresolved-symbols 2>&1 | \ +# RUN: ld.lld -shared %t1.o -o /dev/null --error-unresolved-symbols 2>&1 | \ # RUN: FileCheck -allow-empty -check-prefix=NOERR %s -# RUN: ld.lld -r %t1.o -o %t9 -warn-unresolved-symbols 2>&1 | \ +# RUN: ld.lld -r %t1.o -o /dev/null -warn-unresolved-symbols 2>&1 | \ # RUN: FileCheck -allow-empty -check-prefix=NOWARN %s -# RUN: ld.lld -shared %t1.o -o %t10.so --warn-unresolved-symbols 2>&1 | \ +# RUN: ld.lld -shared %t1.o -o /dev/null --warn-unresolved-symbols 2>&1 | \ # RUN: FileCheck -allow-empty -check-prefix=NOWARN %s # ERRUND: error: undefined symbol: undef diff --git a/test/ELF/weak-and-strong-undef.s b/test/ELF/weak-and-strong-undef.s index db93470636df..32ce649bb147 100644 --- a/test/ELF/weak-and-strong-undef.s +++ b/test/ELF/weak-and-strong-undef.s @@ -1,6 +1,6 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/weak-and-strong-undef.s -o %t2.o +# RUN: echo ".weak foo" | llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o # RUN: not ld.lld %t1.o %t2.o -o %t 2>&1 | FileCheck %s # RUN: not ld.lld %t2.o %t1.o -o %t 2>&1 | FileCheck %s diff --git a/test/ELF/weak-shared-gc.s b/test/ELF/weak-shared-gc.s new file mode 100644 index 000000000000..2cafbe8dbb08 --- /dev/null +++ b/test/ELF/weak-shared-gc.s @@ -0,0 +1,21 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: echo -e '.globl __cxa_finalize\n__cxa_finalize:' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: ld.lld %t1.o --as-needed --gc-sections %t2.so -o %t +# RUN: llvm-readelf -dynamic-table -dyn-symbols %t | FileCheck %s + +# The crt files on linux have a weak reference to __cxa_finalize. It +# is important that a weak undefined reference is produced. Like +# other weak undefined references, the shared library is not marked as +# needed. + +# CHECK-NOT: NEEDED +# CHECK: WEAK DEFAULT UND __cxa_finalize +# CHECK-NOT: NEEDED + + .global _start +_start: + .weak __cxa_finalize + call __cxa_finalize@PLT diff --git a/test/ELF/weak-undef-lazy.s b/test/ELF/weak-undef-lazy.s index 113013ea2e0f..0a4188fca271 100644 --- a/test/ELF/weak-undef-lazy.s +++ b/test/ELF/weak-undef-lazy.s @@ -3,7 +3,7 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/weak-undef-lazy.s -o %t2.o # RUN: rm -f %t2.a # RUN: llvm-ar rc %t2.a %t2.o -# RUN: ld.lld %t.o %t2.a -o %t --export-dynamic +# RUN: ld.lld %t.o %t2.a -o /dev/null --export-dynamic .global _start _start: diff --git a/test/ELF/weak-undef-lib.s b/test/ELF/weak-undef-lib.s new file mode 100644 index 000000000000..e4e7f46ebaa9 --- /dev/null +++ b/test/ELF/weak-undef-lib.s @@ -0,0 +1,19 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1.o +# RUN: echo -e '.globl foo\nfoo: ret' | \ +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux - -o %t2.o + +# RUN: ld.lld -shared -o %t.so %t1.o --start-lib %t2.o +# RUN: llvm-readobj -dyn-symbols %t.so | FileCheck %s + +# CHECK: Name: foo +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Size: 0 +# CHECK-NEXT: Binding: Weak +# CHECK-NEXT: Type: None +# CHECK-NEXT: Other: 0 +# CHECK-NEXT: Section: Undefined + +.weak foo +.data +.quad foo diff --git a/test/ELF/weak-undef-rw.s b/test/ELF/weak-undef-rw.s new file mode 100644 index 000000000000..c75e7d67db3d --- /dev/null +++ b/test/ELF/weak-undef-rw.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t --export-dynamic +# RUN: llvm-readobj -r %t | FileCheck %s + +# CHECK: R_X86_64_64 foobar 0x0 + + .global _start +_start: + .data + .weak foobar + .quad foobar diff --git a/test/ELF/whole-archive-name.s b/test/ELF/whole-archive-name.s new file mode 100644 index 000000000000..1cf7962e62fd --- /dev/null +++ b/test/ELF/whole-archive-name.s @@ -0,0 +1,15 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +// RUN: mkdir -p %t.dir +// RUN: rm -f %t.dir/liba.a +// RUN: llvm-ar rcs %t.dir/liba.a %t.o +// RUN: ld.lld -L%t.dir --whole-archive -la -o /dev/null -Map=- | FileCheck %s + +.globl _start +_start: + nop + +// There was a use after free of an archive name. +// Valgrind/asan would detect it. +// CHECK: liba.a(whole-archive-name.s.tmp.o):(.text) +// CHECK-NEXT: _start diff --git a/test/ELF/wrap.s b/test/ELF/wrap.s index b96917b7be49..a02592e24ebd 100644 --- a/test/ELF/wrap.s +++ b/test/ELF/wrap.s @@ -6,6 +6,8 @@ // RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s // RUN: ld.lld -o %t3 %t %t2 --wrap foo -wrap=nosuchsym // RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s +// RUN: ld.lld -o %t3 %t %t2 --wrap foo --wrap foo -wrap=nosuchsym +// RUN: llvm-objdump -d -print-imm-hex %t3 | FileCheck %s // CHECK: _start: // CHECK-NEXT: movl $0x11010, %edx diff --git a/test/ELF/writable-merge.s b/test/ELF/writable-merge.s index 3006fa387fb5..91a7e07d7ce5 100644 --- a/test/ELF/writable-merge.s +++ b/test/ELF/writable-merge.s @@ -1,6 +1,6 @@ // REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux -// RUN: not ld.lld %t.o -o %t 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s // CHECK: writable SHF_MERGE section is not supported .section .foo,"awM",@progbits,4 diff --git a/test/ELF/writable-sec-plt-reloc.s b/test/ELF/writable-sec-plt-reloc.s index 97a21b5fac02..c44ca6a696c5 100644 --- a/test/ELF/writable-sec-plt-reloc.s +++ b/test/ELF/writable-sec-plt-reloc.s @@ -11,4 +11,4 @@ .section .bar,"awx" .global _start _start: - call foo + .long foo - . diff --git a/test/ELF/x86-64-dyn-rel-error.s b/test/ELF/x86-64-dyn-rel-error.s index 7a705eb54177..7753a4dc4aec 100644 --- a/test/ELF/x86-64-dyn-rel-error.s +++ b/test/ELF/x86-64-dyn-rel-error.s @@ -9,6 +9,8 @@ _start: .data .long zed -// CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC +// CHECK: relocation R_X86_64_32 cannot be used against symbol zed; recompile with -fPIC -// RUN: ld.lld --noinhibit-exec %t.o %t2.so -o %t 2>&1 | FileCheck %s +// RUN: ld.lld --noinhibit-exec %t.o %t2.so -o %t 2>&1 | FileCheck --check-prefix=WARN %s + +// WARN: symbol 'zed' has no type diff --git a/test/ELF/x86-64-dyn-rel-error2.s b/test/ELF/x86-64-dyn-rel-error2.s index 9b731e268875..b3259395d245 100644 --- a/test/ELF/x86-64-dyn-rel-error2.s +++ b/test/ELF/x86-64-dyn-rel-error2.s @@ -2,9 +2,9 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/shared.s -o %t2.o // RUN: ld.lld %t2.o -shared -o %t2.so -// RUN: not ld.lld -shared %t.o %t2.so -o %t 2>&1 | FileCheck %s +// RUN: not ld.lld -shared %t.o %t2.so -o /dev/null 2>&1 | FileCheck %s -// CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC +// CHECK: relocation R_X86_64_PC32 cannot be used against symbol zed; recompile with -fPIC // CHECK: >>> defined in {{.*}}.so // CHECK: >>> referenced by {{.*}}.o:(.data+0x0) diff --git a/test/ELF/x86-64-dyn-rel-error3.s b/test/ELF/x86-64-dyn-rel-error3.s new file mode 100644 index 000000000000..86cef1426df9 --- /dev/null +++ b/test/ELF/x86-64-dyn-rel-error3.s @@ -0,0 +1,16 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -shared -o /dev/null 2>&1 | FileCheck %s + +# CHECK: relocation R_X86_64_8 cannot be used against symbol foo; recompile with -fPIC +# CHECK: relocation R_X86_64_16 cannot be used against symbol foo; recompile with -fPIC +# CHECK: relocation R_X86_64_PC8 cannot be used against symbol foo; recompile with -fPIC +# CHECK: relocation R_X86_64_PC16 cannot be used against symbol foo; recompile with -fPIC + +.global foo + +.data +.byte foo # R_X86_64_8 +.short foo # R_X86_64_16 +.byte foo - . # R_X86_64_PC8 +.short foo - . # R_X86_64_PC16 diff --git a/test/ELF/x86-64-plt-high-addr.s b/test/ELF/x86-64-plt-high-addr.s new file mode 100644 index 000000000000..4acccb63f4a7 --- /dev/null +++ b/test/ELF/x86-64-plt-high-addr.s @@ -0,0 +1,24 @@ +// REQUIRES: x86 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t1.o +// RUN: ld.lld -o %t.so -shared %t1.o + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o +// RUN: ld.lld -o %t1.exe %t2.o %t.so -image-base=0xcafe00000000 +// RUN: llvm-objdump -s -j .got.plt %t1.exe | FileCheck %s + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: cafe00002000 00300000 feca0000 00000000 00000000 +// CHECK-NEXT: cafe00002010 00000000 00000000 26100000 feca0000 + +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t2.o +// RUN: ld.lld -o %t2.exe %t2.o %t.so -image-base=0xcafe00000000 -z retpolineplt +// RUN: llvm-objdump -s -j .got.plt %t2.exe | FileCheck -check-prefix=RETPOLINE %s + +// RETPOLINE: Contents of section .got.plt: +// RETPOLINE-NEXT: cafe00002000 00300000 feca0000 00000000 00000000 +// RETPOLINE-NEXT: cafe00002010 00000000 00000000 51100000 feca0000 + +.global _start +_start: + jmp bar@PLT diff --git a/test/ELF/x86-64-reloc-16.s b/test/ELF/x86-64-reloc-16.s index 4822ec71757b..5157c3706fef 100644 --- a/test/ELF/x86-64-reloc-16.s +++ b/test/ELF/x86-64-reloc-16.s @@ -3,12 +3,12 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16.s -o %t1 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-16-error.s -o %t2 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: ld.lld -shared %t %t1 -o %t3 +// RUN: ld.lld -shared %t %t1 -o /dev/null // CHECK: Contents of section .text: // CHECK-NEXT: 200000 42 -// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s +// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s // ERROR: relocation R_X86_64_16 out of range: 65536 is not in [0, 65535] .short foo diff --git a/test/ELF/x86-64-reloc-32-fpic.s b/test/ELF/x86-64-reloc-32-fpic.s index e3e7c6834d21..1c4754f1e2c6 100644 --- a/test/ELF/x86-64-reloc-32-fpic.s +++ b/test/ELF/x86-64-reloc-32-fpic.s @@ -1,8 +1,8 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s +# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s -# CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC +# CHECK: relocation R_X86_64_32 cannot be used against symbol _shared; recompile with -fPIC # CHECK: >>> defined in {{.*}} # CHECK: >>> referenced by {{.*}}:(.data+0x0) diff --git a/test/ELF/x86-64-reloc-8.s b/test/ELF/x86-64-reloc-8.s index 8f6ba5aa14bb..f71bafb7ffb1 100644 --- a/test/ELF/x86-64-reloc-8.s +++ b/test/ELF/x86-64-reloc-8.s @@ -3,12 +3,12 @@ // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8.s -o %t1 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-8-error.s -o %t2 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: ld.lld -shared %t %t1 -o %t3 +// RUN: ld.lld -shared %t %t1 -o /dev/null // CHECK: Contents of section .text: // CHECK-NEXT: 200000 42 -// RUN: not ld.lld -shared %t %t2 -o %t4 2>&1 | FileCheck --check-prefix=ERROR %s +// RUN: not ld.lld -shared %t %t2 -o /dev/null 2>&1 | FileCheck --check-prefix=ERROR %s // ERROR: relocation R_X86_64_8 out of range: 256 is not in [0, 255] .byte foo diff --git a/test/ELF/x86-64-reloc-debug-overflow.s b/test/ELF/x86-64-reloc-debug-overflow.s new file mode 100644 index 000000000000..d6e6650acd3e --- /dev/null +++ b/test/ELF/x86-64-reloc-debug-overflow.s @@ -0,0 +1,9 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-error.s -o %tabs +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t +# RUN: not ld.lld -shared %tabs %t -o /dev/null 2>&1 | FileCheck %s + +# CHECK: (.debug_info+0x0): relocation R_X86_64_32 out of range: 281474976710656 is not in [0, 4294967295]; consider recompiling with -fdebug-types-section to reduce size of debug sections + +.section .debug_info,"",@progbits + .long .debug_info + 0x1000000000000 diff --git a/test/ELF/x86-64-reloc-error-reporting.s b/test/ELF/x86-64-reloc-error-reporting.s new file mode 100644 index 000000000000..bb9c8be8accb --- /dev/null +++ b/test/ELF/x86-64-reloc-error-reporting.s @@ -0,0 +1,19 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-error.s -o %tabs +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t + +// We have some code in error reporting to check that +// section belongs to the output section. Without that +// check, the linker would crash, so it is useful to test it. +// And the easy way to do that is to trigger GC. That way .text.dumb +// be collected and mentioned check will execute. + +// RUN: not ld.lld -gc-sections -shared %tabs %t -o /dev/null + +.section .text.dumb,"ax" + nop + +.section .text,"ax" +.globl _start +_start: + movl $big, %edx diff --git a/test/ELF/x86-64-reloc-error.s b/test/ELF/x86-64-reloc-error.s index cb600d9bf1e3..0c3bebef04b5 100644 --- a/test/ELF/x86-64-reloc-error.s +++ b/test/ELF/x86-64-reloc-error.s @@ -1,7 +1,7 @@ +// REQUIRES: x86 // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-error.s -o %tabs // RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t -// RUN: not ld.lld -shared %tabs %t -o %t2 2>&1 | FileCheck %s -// REQUIRES: x86 +// RUN: not ld.lld -shared %tabs %t -o /dev/null 2>&1 | FileCheck %s movl $big, %edx movq $foo - 0x1000000000000, %rdx diff --git a/test/ELF/x86-64-reloc-error2.s b/test/ELF/x86-64-reloc-error2.s new file mode 100644 index 000000000000..d49b67522654 --- /dev/null +++ b/test/ELF/x86-64-reloc-error2.s @@ -0,0 +1,14 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s + +## Check we are able to find a function symbol that encloses +## a given location when reporting error messages. +# CHECK: {{.*}}.o:(function func): relocation R_X86_64_32S out of range: -281474974609408 is not in [-2147483648, 2147483647] + +.section .text.func, "ax", %progbits +.globl func +.type func,@function +.size func, 0x10 +func: + movq func - 0x1000000000000, %rdx diff --git a/test/ELF/x86-64-reloc-gotoff64.s b/test/ELF/x86-64-reloc-gotoff64.s new file mode 100644 index 000000000000..697ac17917a2 --- /dev/null +++ b/test/ELF/x86-64-reloc-gotoff64.s @@ -0,0 +1,32 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -shared -o %t.so +// RUN: llvm-readelf -s %t.so | FileCheck %s -check-prefix=SECTION +// RUN: llvm-objdump -d %t.so | FileCheck %s + +// SECTION: .dynamic DYNAMIC 0000000000003000 +// SECTION: .got PROGBITS 0000000000003070 003070 000000 + +// All the _GLOBAL_OFFSET_TABLE_ occurrences below refer to the address +// of GOT base, not the address of the symbol _GLOBAL_OFFSET_TABLE_. These +// instructions are special and produce GOT base relative relocations. We +// currently use .got end as the GOT base, which is not equal to +// the address of the special symbol _GLOBAL_OFFSET_TABLE_. + +// The assembly is generated by +// gcc -O2 -S -mcmodel=medium -fPIC a.c +// This computes the pc-relative address (runtime address) of _DYNAMIC. +// +// extern long _DYNAMIC[] __attribute__((visibility("hidden"))); +// long* dynamic() { return _DYNAMIC; } + +// 0x3070 (.got end) - 0x1007 = 8297 +// 0x3000 (_DYNAMIC) - 0x3070 (.got end) = -112 +// CHECK: 1000: {{.*}} leaq 8297(%rip), %rdx +// CHECK-NEXT: 1007: {{.*}} movabsq $-112, %rax +.global dynamic +dynamic: + leaq _GLOBAL_OFFSET_TABLE_(%rip), %rdx + movabsq $_DYNAMIC@GOTOFF, %rax + addq %rdx, %rax + ret diff --git a/test/ELF/x86-64-reloc-gotpc64.s b/test/ELF/x86-64-reloc-gotpc64.s new file mode 100644 index 000000000000..f07376f41218 --- /dev/null +++ b/test/ELF/x86-64-reloc-gotpc64.s @@ -0,0 +1,14 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o +// RUN: ld.lld %t.o -shared -o %t.so +// RUN: llvm-readelf -s %t.so | FileCheck %s -check-prefix=SECTION +// RUN: llvm-objdump -d %t.so | FileCheck %s + +// SECTION: .got PROGBITS 0000000000003070 003070 000000 + +// 0x3070 (.got end) - 0x1000 = 8304 +// CHECK: gotpc64: +// CHECK-NEXT: 1000: {{.*}} movabsq $8304, %r11 +.global gotpc64 +gotpc64: + movabsq $_GLOBAL_OFFSET_TABLE_-., %r11 diff --git a/test/ELF/x86-64-reloc-pc32-fpic.s b/test/ELF/x86-64-reloc-pc32-fpic.s index 399bf604f806..2dfd1bfb444c 100644 --- a/test/ELF/x86-64-reloc-pc32-fpic.s +++ b/test/ELF/x86-64-reloc-pc32-fpic.s @@ -1,10 +1,11 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: not ld.lld -shared %t.o -o %t.so 2>&1 | FileCheck %s +# RUN: not ld.lld -shared %t.o -o /dev/null 2>&1 | FileCheck %s -# CHECK: relocation R_X86_64_PC32 cannot be used against shared object; recompile with -fPIC +# CHECK: relocation R_X86_64_PC32 cannot be used against symbol _shared; recompile with -fPIC # CHECK: >>> defined in {{.*}} # CHECK: >>> referenced by {{.*}}:(.data+0x1) .data -call _shared + .byte 0xe8 + .long _shared - . diff --git a/test/ELF/x86-64-reloc-range-debug-loc.s b/test/ELF/x86-64-reloc-range-debug-loc.s new file mode 100644 index 000000000000..8be4df3c5202 --- /dev/null +++ b/test/ELF/x86-64-reloc-range-debug-loc.s @@ -0,0 +1,36 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/x86-64-reloc-error.s -o %tabs +# RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj +# RUN: not ld.lld %tabs %t.o -o /dev/null -shared 2>&1 | FileCheck %s + +## Check we are able to report file and location from debug information +## when reporting such kind of errors. +# CHECK: error: test.s:3: relocation R_X86_64_32 out of range: 68719476736 is not in [0, 4294967295] + +.section .text,"ax",@progbits +foo: +.file 1 "test.s" +.loc 1 3 + movl $big, %edx + +.section .debug_abbrev,"",@progbits +.byte 1 # Abbreviation Code +.byte 17 # DW_TAG_compile_unit +.byte 0 # DW_CHILDREN_no +.byte 16 # DW_AT_stmt_list +.byte 23 # DW_FORM_sec_offset +.byte 0 # EOM(1) +.byte 0 # EOM(2) +.byte 0 # EOM(3) + +.section .debug_info,"",@progbits +.long .Lend0 - .Lbegin0 # Length of Unit +.Lbegin0: +.short 4 # DWARF version number +.long .debug_abbrev # Offset Into Abbrev. Section +.byte 8 # Address Size (in bytes) +.byte 1 # Abbrev [1] 0xb:0x1f DW_TAG_compile_unit +.long .debug_line # DW_AT_stmt_list +.Lend0: + +.section .debug_line,"",@progbits diff --git a/test/ELF/x86-64-reloc-range.s b/test/ELF/x86-64-reloc-range.s index 2913458ab5cb..c58a692821ec 100644 --- a/test/ELF/x86-64-reloc-range.s +++ b/test/ELF/x86-64-reloc-range.s @@ -1,5 +1,6 @@ +// REQUIRES: x86 // RUN: llvm-mc %s -o %t.o -triple x86_64-pc-linux -filetype=obj -// RUN: not ld.lld %t.o -o %t.so -shared 2>&1 | FileCheck %s +// RUN: not ld.lld %t.o -o /dev/null -shared 2>&1 | FileCheck %s // CHECK: {{.*}}:(.text+0x3): relocation R_X86_64_PC32 out of range: 2147483648 is not in [-2147483648, 2147483647] // CHECK-NOT: relocation diff --git a/test/ELF/x86-64-reloc-tpoff32-fpic.s b/test/ELF/x86-64-reloc-tpoff32-fpic.s index 5be3dc317012..edb04c1d4487 100644 --- a/test/ELF/x86-64-reloc-tpoff32-fpic.s +++ b/test/ELF/x86-64-reloc-tpoff32-fpic.s @@ -1,8 +1,8 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: not ld.lld %t.o -shared -o %t.so 2>&1 | FileCheck %s +# RUN: not ld.lld %t.o -shared -o /dev/null 2>&1 | FileCheck %s -# CHECK: relocation R_X86_64_TPOFF32 cannot be used against shared object; recompile with -fPIC +# CHECK: relocation R_X86_64_TPOFF32 cannot be used against symbol var; recompile with -fPIC # CHECK: >>> defined in {{.*}}.o # CHECK: >>> referenced by {{.*}}.o:(.tdata+0xC) diff --git a/test/ELF/x86-64-retpoline-linkerscript.s b/test/ELF/x86-64-retpoline-linkerscript.s new file mode 100644 index 000000000000..82d2ca6374c1 --- /dev/null +++ b/test/ELF/x86-64-retpoline-linkerscript.s @@ -0,0 +1,67 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: echo "SECTIONS { \ +// RUN: .text : { *(.text) } \ +// RUN: .plt : { *(.plt) } \ +// RUN: .got.plt : { *(.got.plt) } \ +// RUN: .dynstr : { *(.dynstr) } \ +// RUN: }" > %t.script +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt --script %t.script +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 10: ff 35 72 00 00 00 pushq 114(%rip) +// CHECK-NEXT: 16: 4c 8b 1d 73 00 00 00 movq 115(%rip), %r11 +// CHECK-NEXT: 1d: e8 0e 00 00 00 callq 14 <.plt+0x20> +// CHECK-NEXT: 22: f3 90 pause +// CHECK-NEXT: 24: 0f ae e8 lfence +// CHECK-NEXT: 27: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 29: cc int3 +// CHECK-NEXT: 2a: cc int3 +// CHECK-NEXT: 2b: cc int3 +// CHECK-NEXT: 2c: cc int3 +// CHECK-NEXT: 2d: cc int3 +// CHECK-NEXT: 2e: cc int3 +// CHECK-NEXT: 2f: cc int3 +// CHECK-NEXT: 30: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 34: c3 retq +// CHECK-NEXT: 35: cc int3 +// CHECK-NEXT: 36: cc int3 +// CHECK-NEXT: 37: cc int3 +// CHECK-NEXT: 38: cc int3 +// CHECK-NEXT: 39: cc int3 +// CHECK-NEXT: 3a: cc int3 +// CHECK-NEXT: 3b: cc int3 +// CHECK-NEXT: 3c: cc int3 +// CHECK-NEXT: 3d: cc int3 +// CHECK-NEXT: 3e: cc int3 +// CHECK-NEXT: 3f: cc int3 +// CHECK-NEXT: 40: 4c 8b 1d 51 00 00 00 movq 81(%rip), %r11 +// CHECK-NEXT: 47: e8 e4 ff ff ff callq -28 <.plt+0x20> +// CHECK-NEXT: 4c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 51: 68 00 00 00 00 pushq $0 +// CHECK-NEXT: 56: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 5b: cc int3 +// CHECK-NEXT: 5c: cc int3 +// CHECK-NEXT: 5d: cc int3 +// CHECK-NEXT: 5e: cc int3 +// CHECK-NEXT: 5f: cc int3 +// CHECK-NEXT: 60: 4c 8b 1d 39 00 00 00 movq 57(%rip), %r11 +// CHECK-NEXT: 67: e8 c4 ff ff ff callq -60 <.plt+0x20> +// CHECK-NEXT: 6c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 71: 68 01 00 00 00 pushq $1 +// CHECK-NEXT: 76: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 7b: cc int3 +// CHECK-NEXT: 7c: cc int3 +// CHECK-NEXT: 7d: cc int3 +// CHECK-NEXT: 7e: cc int3 +// CHECK-NEXT: 7f: cc int3 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/x86-64-retpoline-znow-linkerscript.s b/test/ELF/x86-64-retpoline-znow-linkerscript.s new file mode 100644 index 000000000000..20196058d251 --- /dev/null +++ b/test/ELF/x86-64-retpoline-znow-linkerscript.s @@ -0,0 +1,54 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: echo "SECTIONS { \ +// RUN: .text : { *(.text) } \ +// RUN: .plt : { *(.plt) } \ +// RUN: .got.plt : { *(.got.plt) } \ +// RUN: .dynstr : { *(.dynstr) } \ +// RUN: }" > %t.script +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt -z now --script %t.script +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 10: e8 0b 00 00 00 callq 11 <.plt+0x10> +// CHECK-NEXT: 15: f3 90 pause +// CHECK-NEXT: 17: 0f ae e8 lfence +// CHECK-NEXT: 1a: eb f9 jmp -7 <.plt+0x5> +// CHECK-NEXT: 1c: cc int3 +// CHECK-NEXT: 1d: cc int3 +// CHECK-NEXT: 1e: cc int3 +// CHECK-NEXT: 1f: cc int3 +// CHECK-NEXT: 20: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 24: c3 retq +// CHECK-NEXT: 25: cc int3 +// CHECK-NEXT: 26: cc int3 +// CHECK-NEXT: 27: cc int3 +// CHECK-NEXT: 28: cc int3 +// CHECK-NEXT: 29: cc int3 +// CHECK-NEXT: 2a: cc int3 +// CHECK-NEXT: 2b: cc int3 +// CHECK-NEXT: 2c: cc int3 +// CHECK-NEXT: 2d: cc int3 +// CHECK-NEXT: 2e: cc int3 +// CHECK-NEXT: 2f: cc int3 +// CHECK-NEXT: 30: 4c 8b 1d 31 00 00 00 movq 49(%rip), %r11 +// CHECK-NEXT: 37: e9 d4 ff ff ff jmp -44 <.plt> +// CHECK-NEXT: 3c: cc int3 +// CHECK-NEXT: 3d: cc int3 +// CHECK-NEXT: 3e: cc int3 +// CHECK-NEXT: 3f: cc int3 +// CHECK-NEXT: 40: 4c 8b 1d 29 00 00 00 movq 41(%rip), %r11 +// CHECK-NEXT: 47: e9 c4 ff ff ff jmp -60 <.plt> +// CHECK-NEXT: 4c: cc int3 +// CHECK-NEXT: 4d: cc int3 +// CHECK-NEXT: 4e: cc int3 +// CHECK-NEXT: 4f: cc int3 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/x86-64-retpoline-znow.s b/test/ELF/x86-64-retpoline-znow.s new file mode 100644 index 000000000000..6464e2c0971f --- /dev/null +++ b/test/ELF/x86-64-retpoline-znow.s @@ -0,0 +1,53 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt -z now +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: e8 0b 00 00 00 callq 11 <.plt+0x10> +// CHECK-NEXT: 1015: f3 90 pause +// CHECK-NEXT: 1017: 0f ae e8 lfence +// CHECK-NEXT: 101a: eb f9 jmp -7 <.plt+0x5> +// CHECK-NEXT: 101c: cc int3 +// CHECK-NEXT: 101d: cc int3 +// CHECK-NEXT: 101e: cc int3 +// CHECK-NEXT: 101f: cc int3 +// CHECK-NEXT: 1020: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 1024: c3 retq +// CHECK-NEXT: 1025: cc int3 +// CHECK-NEXT: 1026: cc int3 +// CHECK-NEXT: 1027: cc int3 +// CHECK-NEXT: 1028: cc int3 +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 4c 8b 1d c1 10 00 00 movq 4289(%rip), %r11 +// CHECK-NEXT: 1037: e9 d4 ff ff ff jmp -44 <.plt> +// CHECK-NEXT: 103c: cc int3 +// CHECK-NEXT: 103d: cc int3 +// CHECK-NEXT: 103e: cc int3 +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 4c 8b 1d b9 10 00 00 movq 4281(%rip), %r11 +// CHECK-NEXT: 1047: e9 c4 ff ff ff jmp -60 <.plt> +// CHECK-NEXT: 104c: cc int3 +// CHECK-NEXT: 104d: cc int3 +// CHECK-NEXT: 104e: cc int3 +// CHECK-NEXT: 104f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 20e0 00200000 00000000 00000000 00000000 +// CHECK-NEXT: 20f0 00000000 00000000 00000000 00000000 +// CHECK-NEXT: 2100 00000000 00000000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/x86-64-retpoline.s b/test/ELF/x86-64-retpoline.s new file mode 100644 index 000000000000..535f56533193 --- /dev/null +++ b/test/ELF/x86-64-retpoline.s @@ -0,0 +1,66 @@ +// REQUIRES: x86 +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o +// RUN: ld.lld -shared %t2.o -o %t2.so + +// RUN: ld.lld -shared %t1.o %t2.so -o %t.exe -z retpolineplt +// RUN: llvm-objdump -d -s %t.exe | FileCheck %s + +// CHECK: Disassembly of section .plt: +// CHECK-NEXT: .plt: +// CHECK-NEXT: 1010: ff 35 f2 0f 00 00 pushq 4082(%rip) +// CHECK-NEXT: 1016: 4c 8b 1d f3 0f 00 00 movq 4083(%rip), %r11 +// CHECK-NEXT: 101d: e8 0e 00 00 00 callq 14 <.plt+0x20> +// CHECK-NEXT: 1022: f3 90 pause +// CHECK-NEXT: 1024: 0f ae e8 lfence +// CHECK-NEXT: 1027: eb f9 jmp -7 <.plt+0x12> +// CHECK-NEXT: 1029: cc int3 +// CHECK-NEXT: 102a: cc int3 +// CHECK-NEXT: 102b: cc int3 +// CHECK-NEXT: 102c: cc int3 +// CHECK-NEXT: 102d: cc int3 +// CHECK-NEXT: 102e: cc int3 +// CHECK-NEXT: 102f: cc int3 +// CHECK-NEXT: 1030: 4c 89 1c 24 movq %r11, (%rsp) +// CHECK-NEXT: 1034: c3 retq +// CHECK-NEXT: 1035: cc int3 +// CHECK-NEXT: 1036: cc int3 +// CHECK-NEXT: 1037: cc int3 +// CHECK-NEXT: 1038: cc int3 +// CHECK-NEXT: 1039: cc int3 +// CHECK-NEXT: 103a: cc int3 +// CHECK-NEXT: 103b: cc int3 +// CHECK-NEXT: 103c: cc int3 +// CHECK-NEXT: 103d: cc int3 +// CHECK-NEXT: 103e: cc int3 +// CHECK-NEXT: 103f: cc int3 +// CHECK-NEXT: 1040: 4c 8b 1d d1 0f 00 00 movq 4049(%rip), %r11 +// CHECK-NEXT: 1047: e8 e4 ff ff ff callq -28 <.plt+0x20> +// CHECK-NEXT: 104c: e9 d1 ff ff ff jmp -47 <.plt+0x12> +// CHECK-NEXT: 1051: 68 00 00 00 00 pushq $0 +// CHECK-NEXT: 1056: e9 b5 ff ff ff jmp -75 <.plt> +// CHECK-NEXT: 105b: cc int3 +// CHECK-NEXT: 105c: cc int3 +// CHECK-NEXT: 105d: cc int3 +// CHECK-NEXT: 105e: cc int3 +// CHECK-NEXT: 105f: cc int3 +// CHECK-NEXT: 1060: 4c 8b 1d b9 0f 00 00 movq 4025(%rip), %r11 +// CHECK-NEXT: 1067: e8 c4 ff ff ff callq -60 <.plt+0x20> +// CHECK-NEXT: 106c: e9 b1 ff ff ff jmp -79 <.plt+0x12> +// CHECK-NEXT: 1071: 68 01 00 00 00 pushq $1 +// CHECK-NEXT: 1076: e9 95 ff ff ff jmp -107 <.plt> +// CHECK-NEXT: 107b: cc int3 +// CHECK-NEXT: 107c: cc int3 +// CHECK-NEXT: 107d: cc int3 +// CHECK-NEXT: 107e: cc int3 +// CHECK-NEXT: 107f: cc int3 + +// CHECK: Contents of section .got.plt: +// CHECK-NEXT: 2000 00300000 00000000 00000000 00000000 +// CHECK-NEXT: 2010 00000000 00000000 51100000 00000000 +// CHECK-NEXT: 2020 71100000 00000000 + +.global _start +_start: + jmp bar@PLT + jmp zed@PLT diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-fail.s b/test/ELF/x86-64-split-stack-prologue-adjust-fail.s new file mode 100644 index 000000000000..0ae3de5ea611 --- /dev/null +++ b/test/ELF/x86-64-split-stack-prologue-adjust-fail.s @@ -0,0 +1,31 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o + +# RUN: not ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s + +# An unknown prologue gives a match failure +# CHECK: unable to adjust the enclosing function's + +# RUN: not ld.lld -r --defsym __morestack=0x100 %t1.o %t2.o -o %t 2>&1 | FileCheck %s -check-prefix=RELOCATABLE +# RELOCATABLE: Cannot mix split-stack and non-split-stack in a relocatable link + + .text + + .global unknown_prologue + .type unknown_prologue,@function +unknown_prologue: + push %rbp + mov %rsp,%rbp + cmp %fs:0x70,%rsp + jae 1f + callq __morestack + retq +1: + callq non_split + leaveq + retq + + .size unknown_prologue,. - unknown_prologue + + .section .note.GNU-split-stack,"",@progbits diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-silent.s b/test/ELF/x86-64-split-stack-prologue-adjust-silent.s new file mode 100644 index 000000000000..353eabef0de7 --- /dev/null +++ b/test/ELF/x86-64-split-stack-prologue-adjust-silent.s @@ -0,0 +1,32 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o + +# RUN: ld.lld --defsym __morestack=0x100 %t1.o %t2.o -o %t +# RUN: llvm-objdump -d %t 2>&1 | FileCheck %s + +# An unknown prologue ordinarily gives a match failure, except that this +# object file includes a .note.GNU-no-split-stack section, which tells the +# linker to expect such prologues, and therefore not error. + +# CHECK: __morestack + + .text + + .global unknown_prologue + .type unknown_prologue,@function +unknown_prologue: + push %rbp + mov %rsp,%rbp + cmp %fs:0x70,%rsp + jae 1f + callq __morestack + retq +1: + callq non_split + leaveq + retq + + .size unknown_prologue,. - unknown_prologue + .section .note.GNU-split-stack,"",@progbits + .section .note.GNU-no-split-stack,"",@progbits diff --git a/test/ELF/x86-64-split-stack-prologue-adjust-success.s b/test/ELF/x86-64-split-stack-prologue-adjust-success.s new file mode 100644 index 000000000000..bad26677f3fd --- /dev/null +++ b/test/ELF/x86-64-split-stack-prologue-adjust-success.s @@ -0,0 +1,124 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t1.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/x86-64-split-stack-main.s -o %t2.o + +# RUN: ld.lld --defsym __morestack=0x100 --defsym __morestack_non_split=0x200 %t1.o %t2.o -o %t -z notext +# RUN: llvm-objdump -d %t | FileCheck %s + +# Avoid duplicating the prologue for every test via macros. + +.macro prologue1 function_to_call + .global prologue1_calls_\function_to_call + .type prologue1_calls_\function_to_call,@function +prologue1_calls_\function_to_call: + cmp %fs:0x70,%rsp + jae 1f + callq __morestack + retq +1: + # Various and duplicate calls to ensure every code path is taken. + callq \function_to_call + callq \function_to_call + callq 1b + callq non_function_text_symbol + retq + .size prologue1_calls_\function_to_call,. - prologue1_calls_\function_to_call +.endm + +.macro prologue2 function_to_call register + .global prologue2_calls_\function_to_call\register + .type prologue2_calls_\function_to_call\register,@function +prologue2_calls_\function_to_call\register: + lea -0x200(%rsp),%\register + cmp %fs:0x70,%\register + jae 1f + callq __morestack + retq +1: + # Various and duplicate calls to ensure every code path is taken. + callq \function_to_call + callq \function_to_call + callq 1b + callq non_function_text_symbol + retq + .size prologue2_calls_\function_to_call\register,. - prologue2_calls_\function_to_call\register +.endm + + .local foo +foo: + .section .text,"ax",@progbits + .quad foo + + .text + +# For split-stack code calling split-stack code, ensure prologue v1 still +# calls plain __morestack, and that any raw bytes written to the prologue +# make sense. +# CHECK: prologue1_calls_split: +# CHECK-NEXT: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%rsp +# CHECK: jae{{.*$}} +# CHECK-NEXT: callq{{.*}}<__morestack> + +prologue1 split + +# For split-stack code calling split-stack code, ensure prologue v2 still +# calls plain __morestack, that any raw bytes written to the prologue +# make sense, and that the register number is preserved. +# CHECK: prologue2_calls_splitr10: +# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r10 +# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}} +# CHECK: jae{{.*}} +# CHECK-NEXT: callq{{.*}}<__morestack> + +prologue2 split r10 + +# CHECK: prologue2_calls_splitr11: +# CHECK-NEXT: lea{{.*}} -{{[0-9]+}}(%rsp),{{.*}}%r11 +# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r{{[0-9]+}} +# CHECK: jae{{.*}} +# CHECK-NEXT: callq{{.*}}<__morestack> + +prologue2 split r11 + +# For split-stack code calling non-split-stack code, ensure prologue v1 +# calls __morestack_non_split, and that any raw bytes written to the prologue +# make sense. +# CHECK: prologue1_calls_non_split: +# CHECK-NEXT: stc{{.*$}} +# CHECK-NEXT: nopl{{.*$}} +# CHECK: jae{{.*$}} +# CHECK-NEXT: callq{{.*}}<__morestack_non_split> + +prologue1 non_split + +# For split-stack code calling non-split-stack code, ensure prologue v2 +# calls __morestack_non_split, that any raw bytes written to the prologue +# make sense, and that the register number is preserved +# CHECK: prologue2_calls_non_splitr10: +# CHECK-NEXT: lea{{.*$}} +# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r10 +# CHECK: jae{{.*$}} +# CHECK-NEXT: callq{{.*}}<__morestack_non_split> + +prologue2 non_split r10 + +# CHECK: prologue2_calls_non_splitr11: +# CHECK-NEXT: lea{{.*$}} +# CHECK: cmp{{.*}}%fs:{{[^,]*}},{{.*}}%r11 +# CHECK: jae{{.*$}} +# CHECK-NEXT: callq{{.*}}<__morestack_non_split> + +prologue2 non_split r11 +# call foo@plt # for code-coverage. + + + + .global split + .type split,@function +split: + retq + + .size split,. - split + + .section .note.GNU-stack,"",@progbits + .section .note.GNU-split-stack,"",@progbits diff --git a/test/ELF/x86-64-tls-ld-local.s b/test/ELF/x86-64-tls-ld-local.s new file mode 100644 index 000000000000..6daba638367f --- /dev/null +++ b/test/ELF/x86-64-tls-ld-local.s @@ -0,0 +1,29 @@ +// REQUIRES: x86 +// RUN: llvm-mc %s -o %t.o -filetype=obj -triple=x86_64-pc-linux +// RUN: ld.lld %t.o -o %t.so -shared +// RUN: llvm-readobj -r -s %t.so | FileCheck %s + +// CHECK: Relocations [ +// CHECK-NEXT: Section ({{.*}}) .rela.dyn { +// CHECK-NEXT: R_X86_64_DTPMOD64 - 0x0 +// CHECK-NEXT: R_X86_64_DTPMOD64 - 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: Section ({{.*}}) .rela.plt { +// CHECK-NEXT: R_X86_64_JUMP_SLOT __tls_get_addr 0x0 +// CHECK-NEXT: } +// CHECK-NEXT: ] + + data16 + leaq bar@TLSGD(%rip), %rdi + data16 + data16 + rex64 + callq __tls_get_addr@PLT + + leaq bar@TLSLD(%rip), %rdi + callq __tls_get_addr@PLT + leaq bar@DTPOFF(%rax), %rax + + .section .tdata,"awT",@progbits +bar: + .long 42 diff --git a/test/ELF/zdefs.s b/test/ELF/zdefs.s index 93c61e14ccb6..21bec77b3bfb 100644 --- a/test/ELF/zdefs.s +++ b/test/ELF/zdefs.s @@ -1,3 +1,4 @@ +# REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o # RUN: ld.lld -shared %t.o -o %t1.so diff --git a/test/ELF/znotext-plt-relocations-protected.s b/test/ELF/znotext-plt-relocations-protected.s index 03d20b12e352..4fd8065a2873 100644 --- a/test/ELF/znotext-plt-relocations-protected.s +++ b/test/ELF/znotext-plt-relocations-protected.s @@ -2,10 +2,10 @@ # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/znotext-plt-relocations-protected.s -o %t2.o # RUN: ld.lld %t2.o -o %t2.so -shared -# RUN: not ld.lld -z notext %t.o %t2.so -o %t 2>&1 | FileCheck %s +# RUN: not ld.lld -z notext %t.o %t2.so -o /dev/null 2>&1 | FileCheck %s # CHECK: error: cannot preempt symbol: foo .global _start _start: -callq foo + .long foo - . diff --git a/test/ELF/znotext-weak-undef.s b/test/ELF/znotext-weak-undef.s index d606d872bc4f..72bb6e2d5e18 100644 --- a/test/ELF/znotext-weak-undef.s +++ b/test/ELF/znotext-weak-undef.s @@ -1,7 +1,7 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o # RUN: not ld.lld -z notext -shared %t.o -o %t 2>&1 | FileCheck %s -# CHECK: relocation R_X86_64_32 cannot be used against shared object; recompile with -fPIC +# CHECK: relocation R_X86_64_32 cannot be used against symbol foo; recompile with -fPIC # RUN: ld.lld -z notext %t.o -o %t # RUN: llvm-readobj -r %t | FileCheck %s --check-prefix=EXE diff --git a/test/ELF/ztext-text-notext.s b/test/ELF/ztext.s index 964ffe1fa6d8..1757769b29a2 100644 --- a/test/ELF/ztext-text-notext.s +++ b/test/ELF/ztext.s @@ -1,7 +1,8 @@ # REQUIRES: x86 # RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t.o -# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/ztext-text-notext.s -o %t2.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %p/Inputs/ztext.s -o %t2.o # RUN: ld.lld %t2.o -o %t2.so -shared + # RUN: ld.lld -z notext %t.o %t2.so -o %t -shared # RUN: llvm-readobj -dynamic-table -r %t | FileCheck %s # RUN: ld.lld -z notext %t.o %t2.so -o %t2 -pie @@ -9,26 +10,34 @@ # RUN: ld.lld -z notext %t.o %t2.so -o %t3 # RUN: llvm-readobj -dynamic-table -r %t3 | FileCheck --check-prefix=STATIC %s +# RUN: not ld.lld %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s +# RUN: not ld.lld -z text %t.o %t2.so -o %t -shared 2>&1 | FileCheck --check-prefix=ERR %s +# ERR: error: can't create dynamic relocation + # If the preference is to have text relocations, don't create plt of copy relocations. # CHECK: Relocations [ -# CHECK-NEXT: Section {{.*}} .rela.dyn { -# CHECK-NEXT: 0x1000 R_X86_64_RELATIVE - 0x1000 -# CHECK-NEXT: 0x1008 R_X86_64_64 bar 0x0 -# CHECK-NEXT: 0x1010 R_X86_64_PC64 zed 0x0 -# CHECK-NEXT: } -# CHECK-NEXT: ] +# CHECK-NEXT: Section {{.*}} .rela.dyn { +# CHECK-NEXT: 0x1000 R_X86_64_RELATIVE - 0x1000 +# CHECK-NEXT: 0x1008 R_X86_64_64 bar 0x0 +# CHECK-NEXT: 0x1010 R_X86_64_PC64 zed 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: ] + # CHECK: DynamicSection [ -# CHECK: 0x0000000000000016 TEXTREL 0x0 +# CHECK: FLAGS TEXTREL +# CHECK: TEXTREL 0x0 # STATIC: Relocations [ -# STATIC-NEXT: Section {{.*}} .rela.dyn { -# STATIC-NEXT: 0x201008 R_X86_64_64 bar 0x0 -# STATIC-NEXT: 0x201010 R_X86_64_PC64 zed 0x0 -# STATIC-NEXT: } -# STATIC-NEXT: ] +# STATIC-NEXT: Section {{.*}} .rela.dyn { +# STATIC-NEXT: 0x201008 R_X86_64_64 bar 0x0 +# STATIC-NEXT: 0x201010 R_X86_64_PC64 zed 0x0 +# STATIC-NEXT: } +# STATIC-NEXT: ] + # STATIC: DynamicSection [ -# STATIC: 0x0000000000000016 TEXTREL 0x0 +# STATIC: FLAGS TEXTREL +# STATIC: TEXTREL 0x0 foo: .quad foo diff --git a/test/MinGW/driver.test b/test/MinGW/driver.test index 8bf70a9b24fa..35d3ccf97ccd 100644 --- a/test/MinGW/driver.test +++ b/test/MinGW/driver.test @@ -90,6 +90,15 @@ RUN: ld.lld -### -m i386pep foo.o -s | FileCheck -check-prefix STRIP %s RUN: ld.lld -### -m i386pep foo.o --strip-all | FileCheck -check-prefix STRIP %s STRIP-NOT: -debug:dwarf +RUN: ld.lld -### -m i386pep foo.o -S | FileCheck -check-prefix STRIP-DEBUG %s +RUN: ld.lld -### -m i386pep foo.o --strip-debug | FileCheck -check-prefix STRIP-DEBUG %s +STRIP-DEBUG: -debug:symtab +STRIP-DEBUG-NOT: -debug:dwarf + +RUN: ld.lld -### -m i386pep foo.o -pdb out.pdb | FileCheck -check-prefix PDB %s +PDB: -debug -pdb:out.pdb +PDB-NOT: -debug:dwarf + RUN: ld.lld -### -m i386pep foo.o --large-address-aware | FileCheck -check-prefix LARGE-ADDRESS-AWARE %s LARGE-ADDRESS-AWARE: -largeaddressaware @@ -124,3 +133,15 @@ ICF-NONE: -opt:noicf RUN: ld.lld -### -m i386pep foo.o --icf=all | FileCheck -check-prefix ICF %s RUN: ld.lld -### -m i386pep foo.o -icf=all | FileCheck -check-prefix ICF %s ICF: -opt:icf + +RUN: ld.lld -### -m i386pep --start-group foo.o --end-group + +RUN: ld.lld -### foo.o -m i386pe -shared --kill-at | FileCheck -check-prefix=KILL-AT %s +RUN: ld.lld -### foo.o -m i386pe -shared -kill-at | FileCheck -check-prefix=KILL-AT %s +KILL-AT: -kill-at + +RUN: ld.lld -### foo.o -m i386pep -Map bar.map | FileCheck -check-prefix=MAP %s +RUN: ld.lld -### foo.o -m i386pep --Map bar.map | FileCheck -check-prefix=MAP %s +RUN: ld.lld -### foo.o -m i386pep -Map=bar.map | FileCheck -check-prefix=MAP %s +RUN: ld.lld -### foo.o -m i386pep --Map=bar.map | FileCheck -check-prefix=MAP %s +MAP: -lldmap:bar.map diff --git a/test/darwin/cmdline-lto_library.objtxt b/test/darwin/cmdline-lto_library.objtxt new file mode 100644 index 000000000000..6b91235560b4 --- /dev/null +++ b/test/darwin/cmdline-lto_library.objtxt @@ -0,0 +1,11 @@ +# RUN: ld64.lld -arch x86_64 -lto_library %t -print-atoms -r %s 2>&1 | FileCheck %s +# +# Test that the -lto_library option does not result in an error. +# + +# CHECK-NOT: -lto_library + +--- !native +defined-atoms: + - name: _foo +... diff --git a/test/darwin/cmdline-objc_gc.objtxt b/test/darwin/cmdline-objc_gc.objtxt index b5225a1d184e..4fff925234a0 100644 --- a/test/darwin/cmdline-objc_gc.objtxt +++ b/test/darwin/cmdline-objc_gc.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -objc_gc %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -objc_gc %s 2>&1 | FileCheck %s # # Test that the -objc_gc is rejected. # diff --git a/test/darwin/cmdline-objc_gc_compaction.objtxt b/test/darwin/cmdline-objc_gc_compaction.objtxt index acf7183d95eb..7cb7e8277368 100644 --- a/test/darwin/cmdline-objc_gc_compaction.objtxt +++ b/test/darwin/cmdline-objc_gc_compaction.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_compaction %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -objc_gc_compaction %s 2>&1 | FileCheck %s # # Test that the -objc_gc_compaction is rejected. # diff --git a/test/darwin/cmdline-objc_gc_only.objtxt b/test/darwin/cmdline-objc_gc_only.objtxt index db1cef94ea59..eb9f13145915 100644 --- a/test/darwin/cmdline-objc_gc_only.objtxt +++ b/test/darwin/cmdline-objc_gc_only.objtxt @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -objc_gc_only %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -objc_gc_only %s 2>&1 | FileCheck %s # # Test that the -objc_gc_only is rejected. # diff --git a/test/darwin/native-and-mach-o.objtxt b/test/darwin/native-and-mach-o.objtxt index 1dee76d6d8cd..b4c0a4066a19 100644 --- a/test/darwin/native-and-mach-o.objtxt +++ b/test/darwin/native-and-mach-o.objtxt @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: %p/Inputs/native-and-mach-o.objtxt \ # RUN: %p/Inputs/native-and-mach-o2.objtxt -o %t && \ # RUN: llvm-nm %t | FileCheck %s diff --git a/test/lit.cfg.py b/test/lit.cfg.py index ae0dd187c607..26880383d354 100644 --- a/test/lit.cfg.py +++ b/test/lit.cfg.py @@ -39,8 +39,9 @@ llvm_config.use_default_substitutions() llvm_config.use_lld() tool_patterns = [ - 'llc', 'llvm-as', 'llvm-mc', 'llvm-nm', - 'llvm-objdump', 'llvm-pdbutil', 'llvm-readobj', 'obj2yaml', 'yaml2obj'] + 'llc', 'llvm-as', 'llvm-mc', 'llvm-nm', 'llvm-objdump', 'llvm-pdbutil', + 'llvm-dwarfdump', 'llvm-readelf', 'llvm-readobj', 'obj2yaml', 'yaml2obj', + 'opt', 'llvm-dis'] llvm_config.add_tool_substitutions(tool_patterns) @@ -64,6 +65,7 @@ llvm_config.feature_config( 'AMDGPU': 'amdgpu', 'ARM': 'arm', 'AVR': 'avr', + 'Hexagon': 'hexagon', 'Mips': 'mips', 'PowerPC': 'ppc', 'Sparc': 'sparc', @@ -71,8 +73,9 @@ llvm_config.feature_config( 'X86': 'x86'}) ]) -# Set a fake constant version so that we get consitent output. +# Set a fake constant version so that we get consistent output. config.environment['LLD_VERSION'] = 'LLD 1.0' +config.environment['LLD_IN_TEST'] = '1' # Indirectly check if the mt.exe Microsoft utility exists by searching for # cvtres, which always accompanies it. Alternatively, check if we can use @@ -84,6 +87,9 @@ if (lit.util.which('cvtres', config.environment['PATH'])) or \ if (config.llvm_libxml2_enabled == '1'): config.available_features.add('libxml2') +if config.have_dia_sdk: + config.available_features.add("diasdk") + tar_executable = lit.util.which('tar', config.environment['PATH']) if tar_executable: tar_version = subprocess.Popen( diff --git a/test/lit.site.cfg.py.in b/test/lit.site.cfg.py.in index 50593f7d01bd..764ab83fbcf2 100644 --- a/test/lit.site.cfg.py.in +++ b/test/lit.site.cfg.py.in @@ -1,5 +1,8 @@ @LIT_SITE_CFG_IN_HEADER@ +import lit.util + +config.have_dia_sdk = lit.util.pythonize_bool("@LLVM_ENABLE_DIA_SDK@") config.llvm_src_root = "@LLVM_SOURCE_DIR@" config.llvm_obj_root = "@LLVM_BINARY_DIR@" config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" diff --git a/test/mach-o/Inputs/swift-version-1.yaml b/test/mach-o/Inputs/swift-version-1.yaml index 1337d7a13245..b555e4782843 100644 --- a/test/mach-o/Inputs/swift-version-1.yaml +++ b/test/mach-o/Inputs/swift-version-1.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/hello-world-x86_64.yaml 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -r %s %p/Inputs/hello-world-x86_64.yaml 2>&1 | FileCheck %s --- !mach-o arch: x86_64 diff --git a/test/mach-o/Inputs/wrong-arch-error.yaml b/test/mach-o/Inputs/wrong-arch-error.yaml index 304c872375e4..39ef3c1a9500 100644 --- a/test/mach-o/Inputs/wrong-arch-error.yaml +++ b/test/mach-o/Inputs/wrong-arch-error.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s 2> %t.err +# RUN: not ld64.lld -arch x86_64 -r %s 2> %t.err # RUN: FileCheck %s < %t.err --- !mach-o diff --git a/test/mach-o/PIE.yaml b/test/mach-o/PIE.yaml index 24f8773cbd23..e7c15fbc1f14 100644 --- a/test/mach-o/PIE.yaml +++ b/test/mach-o/PIE.yaml @@ -1,12 +1,12 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: %p/Inputs/PIE.yaml -o %t && \ # RUN: llvm-objdump -macho -private-headers %t | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: %p/Inputs/PIE.yaml -pie -o %t\ # RUN: && llvm-objdump -macho -private-headers %t | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: %p/Inputs/PIE.yaml -no_pie -o %t\ # RUN: && llvm-objdump -macho -private-headers %t \ # RUN: | FileCheck --check-prefix=CHECK_NO_PIE %s diff --git a/test/mach-o/align_text.yaml b/test/mach-o/align_text.yaml index 66b5afb5ff30..d633a8eb95df 100644 --- a/test/mach-o/align_text.yaml +++ b/test/mach-o/align_text.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -r %t -o %t2 -print_atoms | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r %t -o %t2 -print_atoms | FileCheck %s # # Test that alignment info round trips through -r # diff --git a/test/mach-o/arm-interworking-movw.yaml b/test/mach-o/arm-interworking-movw.yaml index b555112dde82..ade459c8c896 100644 --- a/test/mach-o/arm-interworking-movw.yaml +++ b/test/mach-o/arm-interworking-movw.yaml @@ -1,6 +1,6 @@ # REQUIRES: arm -# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s -# RUN: lld -flavor darwin -arch armv7 -dylib -print_atoms %t -o %t2 \ +# RUN: ld64.lld -arch armv7 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch armv7 -dylib -print_atoms %t -o %t2 \ # RUN: %p/Inputs/armv7/libSystem.yaml -sectalign __TEXT __text 0x1000 | FileCheck %s # RUN: llvm-objdump -d -macho -no-symbolic-operands %t2 | FileCheck -check-prefix=CODE %s # diff --git a/test/mach-o/arm-interworking.yaml b/test/mach-o/arm-interworking.yaml index 3988a1958458..a41355fcb955 100644 --- a/test/mach-o/arm-interworking.yaml +++ b/test/mach-o/arm-interworking.yaml @@ -1,6 +1,6 @@ -# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s \ +# RUN: ld64.lld -arch armv7 -r -print_atoms %s \ # RUN: %p/Inputs/arm-interworking.yaml -o %t | FileCheck %s \ -# RUN: && lld -flavor darwin -arch armv7 -dylib -print_atoms \ +# RUN: && ld64.lld -arch armv7 -dylib -print_atoms \ # RUN: %p/Inputs/armv7/libSystem.yaml %t -o %t2 | FileCheck %s \ # RUN: && llvm-readobj -s -sd %t2 | FileCheck -check-prefix=CODE %s # diff --git a/test/mach-o/arm-shims.yaml b/test/mach-o/arm-shims.yaml index 1b54de4f05aa..37e266e6218e 100644 --- a/test/mach-o/arm-shims.yaml +++ b/test/mach-o/arm-shims.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/arm-shims.yaml \ +# RUN: ld64.lld -arch armv7 %s %p/Inputs/arm-shims.yaml \ # RUN: -dylib %p/Inputs/armv7/libSystem.yaml -o %t # RUN: llvm-readobj -s -sd %t | FileCheck %s # diff --git a/test/mach-o/arm-subsections-via-symbols.yaml b/test/mach-o/arm-subsections-via-symbols.yaml index 23c2847e6c77..63e23da9f71e 100644 --- a/test/mach-o/arm-subsections-via-symbols.yaml +++ b/test/mach-o/arm-subsections-via-symbols.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch armv7 %s -r -print_atoms -o %t | FileCheck %s +# RUN: ld64.lld -arch armv7 %s -r -print_atoms -o %t | FileCheck %s # # Test that assembly written without .subsections_via_symbols is parsed so # that atoms are non-dead-strip and there is a layout-after references diff --git a/test/mach-o/arm64-reloc-negDelta32-fixup.yaml b/test/mach-o/arm64-reloc-negDelta32-fixup.yaml index ee8686cabb62..b0c86f92a98f 100644 --- a/test/mach-o/arm64-reloc-negDelta32-fixup.yaml +++ b/test/mach-o/arm64-reloc-negDelta32-fixup.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch arm64 -r %s -o %t -# RUN: lld -flavor darwin -arch arm64 -r %t -o %t2 +# RUN: ld64.lld -arch arm64 -r %s -o %t +# RUN: ld64.lld -arch arm64 -r %t -o %t2 # RUN: llvm-objdump -s -section="__eh_frame" %t | FileCheck %s # RUN: llvm-objdump -s -section="__eh_frame" %t2 | FileCheck %s diff --git a/test/mach-o/arm64-relocs-errors-delta64-offset.yaml b/test/mach-o/arm64-relocs-errors-delta64-offset.yaml index d238097f9695..01a3e1bb6fc6 100644 --- a/test/mach-o/arm64-relocs-errors-delta64-offset.yaml +++ b/test/mach-o/arm64-relocs-errors-delta64-offset.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch arm64 %s -r \ +# RUN: not ld64.lld -arch arm64 %s -r \ # RUN: 2> %t.err # RUN: FileCheck %s < %t.err diff --git a/test/mach-o/arm64-section-order.yaml b/test/mach-o/arm64-section-order.yaml index 50d684668a52..0dbf52c2546c 100644 --- a/test/mach-o/arm64-section-order.yaml +++ b/test/mach-o/arm64-section-order.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 +# RUN: ld64.lld -arch arm64 -r -print_atoms %s -o %t +# RUN: ld64.lld -arch arm64 -r -print_atoms %t -o %t2 # RUN: llvm-objdump -section-headers %t | FileCheck %s # RUN: llvm-objdump -section-headers %t2 | FileCheck %s diff --git a/test/mach-o/bind-opcodes.yaml b/test/mach-o/bind-opcodes.yaml index ad8cd169a85c..294171755759 100644 --- a/test/mach-o/bind-opcodes.yaml +++ b/test/mach-o/bind-opcodes.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t +# RUN: ld64.lld -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t # RUN: obj2yaml %t | FileCheck %s # diff --git a/test/mach-o/cstring-sections.yaml b/test/mach-o/cstring-sections.yaml index 433dffcf62d9..2bc7e7c5c2f6 100644 --- a/test/mach-o/cstring-sections.yaml +++ b/test/mach-o/cstring-sections.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s # # Test -keep_private_externs in -r mode. # diff --git a/test/mach-o/data-in-code-load-command.yaml b/test/mach-o/data-in-code-load-command.yaml index 0c84bd4d7452..32c5d9220c51 100644 --- a/test/mach-o/data-in-code-load-command.yaml +++ b/test/mach-o/data-in-code-load-command.yaml @@ -1,11 +1,11 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -data_in_code_info -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -data_in_code_info -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r -data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -r -no_data_in_code_info && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_DATA_IN_CODE_INFO --- !mach-o arch: x86_64 diff --git a/test/mach-o/data-only-dylib.yaml b/test/mach-o/data-only-dylib.yaml index 541e02f61ef9..a163609225b2 100644 --- a/test/mach-o/data-only-dylib.yaml +++ b/test/mach-o/data-only-dylib.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 -dylib %s -o %t %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-nm %t | FileCheck %s # # Test that a data-only dylib can be built. diff --git a/test/mach-o/dead-strip-globals.yaml b/test/mach-o/dead-strip-globals.yaml index 45d919db3aa5..42edd19f62ce 100644 --- a/test/mach-o/dead-strip-globals.yaml +++ b/test/mach-o/dead-strip-globals.yaml @@ -1,8 +1,8 @@ -# RUN: lld -flavor darwin -arch x86_64 -dead_strip -export_dynamic %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s -# RUN: lld -flavor darwin -arch x86_64 -export_dynamic -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s -# RUN: lld -flavor darwin -arch x86_64 -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t2.dylib -print_atoms | FileCheck -check-prefix=CHECK2 %s +# RUN: ld64.lld -arch x86_64 -dead_strip -export_dynamic %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s +# RUN: ld64.lld -arch x86_64 -export_dynamic -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t.dylib -print_atoms | FileCheck -check-prefix=CHECK1 %s +# RUN: ld64.lld -arch x86_64 -dead_strip %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t2.dylib -print_atoms | FileCheck -check-prefix=CHECK2 %s -# RUN: lld -flavor darwin -arch x86_64 -r %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t3.o +# RUN: ld64.lld -arch x86_64 -r %s -dylib %p/Inputs/x86_64/libSystem.yaml -o %t3.o # RUN: llvm-nm -m %t3.o | FileCheck -check-prefix=RELOCATABLE_SYMBOLS %s # diff --git a/test/mach-o/debug-syms.yaml b/test/mach-o/debug-syms.yaml index 28428724ffe7..cd61c879b0b5 100644 --- a/test/mach-o/debug-syms.yaml +++ b/test/mach-o/debug-syms.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -o %t %s -dylib %p/Inputs/x86_64/libSystem.yaml && \ +# RUN: ld64.lld -arch x86_64 -o %t %s -dylib %p/Inputs/x86_64/libSystem.yaml && \ # RUN: llvm-nm -no-sort -debug-syms %t | FileCheck %s # CHECK: 0000000000000000 - 00 0000 SO /Users/lhames/Projects/lld/lld-svn-tot/scratch/ diff --git a/test/mach-o/demangle.yaml b/test/mach-o/demangle.yaml index 333a59eaa528..cdd5e8adb621 100644 --- a/test/mach-o/demangle.yaml +++ b/test/mach-o/demangle.yaml @@ -1,10 +1,10 @@ # REQUIRES: system-linker-mach-o # -# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: -dylib -o %t %p/Inputs/x86_64/libSystem.yaml 2> %t.err # RUN: FileCheck %s < %t.err # -# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: -dylib -o %t %p/Inputs/x86_64/libSystem.yaml -demangle 2> %t.err2 # RUN: FileCheck %s --check-prefix=DCHECK < %t.err2 # diff --git a/test/mach-o/dependency_info.yaml b/test/mach-o/dependency_info.yaml index 2ec59b8afebb..34d688541b91 100644 --- a/test/mach-o/dependency_info.yaml +++ b/test/mach-o/dependency_info.yaml @@ -1,6 +1,6 @@ # Test -dependency_info option # -# RUN: lld -flavor darwin -arch x86_64 -test_file_usage \ +# RUN: ld64.lld -arch x86_64 -test_file_usage \ # RUN: -dependency_info %t.info \ # RUN: -path_exists /System/Library/Frameworks \ # RUN: -path_exists /System/Library/Frameworks/Foo.framework/Foo \ @@ -9,7 +9,7 @@ # RUN: -F/Custom/Frameworks \ # RUN: -framework Bar \ # RUN: -framework Foo -# RUN: %python %p/Inputs/DependencyDump.py %t.info | FileCheck %s +# RUN: '%python' %p/Inputs/DependencyDump.py %t.info | FileCheck %s # CHECK: linker-vers: lld diff --git a/test/mach-o/do-not-emit-unwind-fde-arm64.yaml b/test/mach-o/do-not-emit-unwind-fde-arm64.yaml index 70f76b5246f1..3afdc2be1fb7 100644 --- a/test/mach-o/do-not-emit-unwind-fde-arm64.yaml +++ b/test/mach-o/do-not-emit-unwind-fde-arm64.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s # RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t | FileCheck -check-prefix=CODE %s # RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t2 | FileCheck -check-prefix=CODE %s diff --git a/test/mach-o/dso_handle.yaml b/test/mach-o/dso_handle.yaml index 0796c2ee566d..6c74371a0b3f 100644 --- a/test/mach-o/dso_handle.yaml +++ b/test/mach-o/dso_handle.yaml @@ -1,13 +1,13 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -o %t1 +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -o %t1 # RUN: llvm-nm -m -n %t1 | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dead_strip -o %t2 +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dead_strip -o %t2 # RUN: llvm-nm -m -n %t2 | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dylib -o %t3 +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -dylib -o %t3 # RUN: llvm-nm -m -n %t3 | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -bundle -o %t4 +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml -bundle -o %t4 # RUN: llvm-nm -m -n %t4 | FileCheck %s # # Test that ___dso_handle symbol is available for executables, bundles, and dylibs diff --git a/test/mach-o/dylib-install-names.yaml b/test/mach-o/dylib-install-names.yaml index af00adfd5908..10209ba12abb 100644 --- a/test/mach-o/dylib-install-names.yaml +++ b/test/mach-o/dylib-install-names.yaml @@ -1,23 +1,23 @@ # Check we accept -install_name correctly: -# RUN: lld -flavor darwin -arch x86_64 -install_name libwibble.dylib -dylib \ +# RUN: ld64.lld -arch x86_64 -install_name libwibble.dylib -dylib \ # RUN: -compatibility_version 2.0 -current_version 5.3 \ # RUN: %p/Inputs/x86_64/libSystem.yaml %s -o %t.dylib # RUN: llvm-objdump -private-headers %t.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE # Check we read LC_ID_DYLIB correctly: -# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/use-dylib-install-names.yaml \ +# RUN: ld64.lld -arch x86_64 %p/Inputs/use-dylib-install-names.yaml \ # RUN: %p/Inputs/x86_64/libSystem.yaml %t.dylib -dylib -o %t2.dylib # RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-READ # Check we default the install-name to the output file: -# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o libwibble.dylib \ +# RUN: ld64.lld -arch x86_64 -dylib %s -o libwibble.dylib \ # RUN: -compatibility_version 2.0 -current_version 5.3 \ # RUN: %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-objdump -private-headers libwibble.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE # RUN: rm -f libwibble.dylib # Check -single_module does nothing -# RUN: lld -flavor darwin -arch x86_64 -dylib %s -install_name libwibble.dylib \ +# RUN: ld64.lld -arch x86_64 -dylib %s -install_name libwibble.dylib \ # RUN: -compatibility_version 2.0 -current_version 5.3 \ # RUN: -single_module -o %t2.dylib %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-objdump -private-headers %t2.dylib | FileCheck %s --check-prefix=CHECK-BINARY-WRITE diff --git a/test/mach-o/eh-frame-relocs-arm64.yaml b/test/mach-o/eh-frame-relocs-arm64.yaml index e23dd7c48ed9..a71f79e692ff 100644 --- a/test/mach-o/eh-frame-relocs-arm64.yaml +++ b/test/mach-o/eh-frame-relocs-arm64.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s # RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t | FileCheck -check-prefix=CODE %s # RUN: llvm-objdump -r -s -section="__eh_frame" -macho %t2 | FileCheck -check-prefix=CODE %s diff --git a/test/mach-o/error-simulator-vs-macosx.yaml b/test/mach-o/error-simulator-vs-macosx.yaml index bd62db39fccb..609eb3be43ab 100644 --- a/test/mach-o/error-simulator-vs-macosx.yaml +++ b/test/mach-o/error-simulator-vs-macosx.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s %p/Inputs/hello-world-x86.yaml -o %t && llvm-nm -m %t | FileCheck %s -# RUN: not lld -flavor darwin -arch i386 -ios_simulator_version_min 5.0 %s %p/Inputs/hello-world-x86.yaml -o %t 2>&1 | FileCheck %s --check-prefix=ERROR +# RUN: ld64.lld -arch i386 -macosx_version_min 10.8 %s %p/Inputs/hello-world-x86.yaml -o %t && llvm-nm -m %t | FileCheck %s +# RUN: not ld64.lld -arch i386 -ios_simulator_version_min 5.0 %s %p/Inputs/hello-world-x86.yaml -o %t 2>&1 | FileCheck %s --check-prefix=ERROR # # Test that i386 can link with a macos version but gives an error with a simululator version. # diff --git a/test/mach-o/exe-offsets.yaml b/test/mach-o/exe-offsets.yaml index 6a0e35cedb46..31b778286bb2 100644 --- a/test/mach-o/exe-offsets.yaml +++ b/test/mach-o/exe-offsets.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e start %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 %s -o %t -e start %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-readobj -sections %t | FileCheck %s # Make sure data gets put at offset diff --git a/test/mach-o/exe-segment-overlap.yaml b/test/mach-o/exe-segment-overlap.yaml index 47f0214efd6c..b2ded264f4b0 100644 --- a/test/mach-o/exe-segment-overlap.yaml +++ b/test/mach-o/exe-segment-overlap.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s -o %t %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 %s -o %t %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-readobj -sections -section-data %t | FileCheck %s --- !native diff --git a/test/mach-o/executable-exports.yaml b/test/mach-o/executable-exports.yaml index f16cbd5ce935..46ba9ca6d1d4 100644 --- a/test/mach-o/executable-exports.yaml +++ b/test/mach-o/executable-exports.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 \ # RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t && \ # RUN: llvm-objdump -exports-trie %t | FileCheck %s # diff --git a/test/mach-o/export-trie-order.yaml b/test/mach-o/export-trie-order.yaml index a11c998bdb06..53ee8afae660 100644 --- a/test/mach-o/export-trie-order.yaml +++ b/test/mach-o/export-trie-order.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t +# RUN: ld64.lld -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t # RUN: llvm-objdump -exports-trie %t | FileCheck %s # # Test that the export trie is emitted in order. diff --git a/test/mach-o/exported_symbols_list-dylib.yaml b/test/mach-o/exported_symbols_list-dylib.yaml index f9de5fe976e2..860d26848fea 100644 --- a/test/mach-o/exported_symbols_list-dylib.yaml +++ b/test/mach-o/exported_symbols_list-dylib.yaml @@ -1,19 +1,19 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \ # RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t \ # RUN: -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \ # RUN: llvm-nm -m %t | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \ # RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t2 \ # RUN: -exported_symbol _foo -exported_symbol _b && \ # RUN: llvm-nm -m %t2 | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \ # RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t3 \ # RUN: -unexported_symbol _bar -unexported_symbol _a && \ # RUN: llvm-nm -m %t3 | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \ # RUN: %s %p/Inputs/x86_64/libSystem.yaml -dead_strip -o %t \ # RUN: -exported_symbols_list %p/Inputs/exported_symbols_list.exp && \ # RUN: llvm-nm -m %t | FileCheck -check-prefix=CHECK_DEAD %s diff --git a/test/mach-o/exported_symbols_list-obj.yaml b/test/mach-o/exported_symbols_list-obj.yaml index 31b325c7387b..cc0f75cdc2f7 100644 --- a/test/mach-o/exported_symbols_list-obj.yaml +++ b/test/mach-o/exported_symbols_list-obj.yaml @@ -1,11 +1,11 @@ -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -exported_symbol _bar \ +# RUN: ld64.lld -arch x86_64 -r %s -o %t -exported_symbol _bar \ # RUN: && llvm-nm -m %t | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t2 -keep_private_externs \ +# RUN: ld64.lld -arch x86_64 -r %s -o %t2 -keep_private_externs \ # RUN: -exported_symbol _bar && \ # RUN: llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s # -# RUN: not lld -flavor darwin -arch x86_64 -r %s -o %t3 \ +# RUN: not ld64.lld -arch x86_64 -r %s -o %t3 \ # RUN: -exported_symbol _foo 2> %t4 # Test -exported_symbols_list properly changes visibility in -r mode. diff --git a/test/mach-o/exported_symbols_list-undef.yaml b/test/mach-o/exported_symbols_list-undef.yaml index 377282f2a7c4..6aca11b61d2a 100644 --- a/test/mach-o/exported_symbols_list-undef.yaml +++ b/test/mach-o/exported_symbols_list-undef.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -dylib \ +# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.8 -dylib \ # RUN: %s %p/Inputs/x86_64/libSystem.yaml -o %t -exported_symbol _foobar 2> %t2 # # Test -exported_symbol fails if exported symbol not found. diff --git a/test/mach-o/fat-archive.yaml b/test/mach-o/fat-archive.yaml index 979ede30a72a..a36c25bca7e1 100644 --- a/test/mach-o/fat-archive.yaml +++ b/test/mach-o/fat-archive.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t \ # RUN: -L %p/Inputs -lfoo %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-nm -m -n %t | FileCheck %s # diff --git a/test/mach-o/filelist.yaml b/test/mach-o/filelist.yaml index 28bfeb74d02b..85c04f570722 100644 --- a/test/mach-o/filelist.yaml +++ b/test/mach-o/filelist.yaml @@ -1,11 +1,11 @@ -# RUN: lld -flavor darwin -test_file_usage \ +# RUN: ld64.lld -test_file_usage \ # RUN: -filelist %p/Inputs/full.filelist \ # RUN: -path_exists /foo/bar/a.o \ # RUN: -path_exists /foo/bar/b.o \ # RUN: -path_exists /foo/x.a \ # RUN: 2>&1 | FileCheck %s # -# RUN: lld -flavor darwin -test_file_usage -t \ +# RUN: ld64.lld -test_file_usage -t \ # RUN: -filelist %p/Inputs/partial.filelist,/foo \ # RUN: -path_exists /foo/bar/a.o \ # RUN: -path_exists /foo/bar/b.o \ diff --git a/test/mach-o/flat_namespace_undef_error.yaml b/test/mach-o/flat_namespace_undef_error.yaml index af84608aa5ff..6d4c38ec1cca 100644 --- a/test/mach-o/flat_namespace_undef_error.yaml +++ b/test/mach-o/flat_namespace_undef_error.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined error %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined error %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s --- !native defined-atoms: diff --git a/test/mach-o/flat_namespace_undef_suppress.yaml b/test/mach-o/flat_namespace_undef_suppress.yaml index e68fd998c1b2..8fdcfb9c30db 100644 --- a/test/mach-o/flat_namespace_undef_suppress.yaml +++ b/test/mach-o/flat_namespace_undef_suppress.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 -flat_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml # # Sanity check '-flat_namespace -undefined suppress'. # This should pass without error, even though '_bar' is undefined. diff --git a/test/mach-o/force_load-dylib.yaml b/test/mach-o/force_load-dylib.yaml index d32c63eab5c1..4e27b0220c34 100644 --- a/test/mach-o/force_load-dylib.yaml +++ b/test/mach-o/force_load-dylib.yaml @@ -1,6 +1,6 @@ -# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \ +# RUN: ld64.lld -arch x86_64 -dylib %p/Inputs/bar.yaml \ # RUN: -install_name /usr/lib/libbar.dylib %p/Inputs/x86_64/libSystem.yaml -o %t1.dylib -# RUN: lld -flavor darwin -arch x86_64 -dylib %s -all_load %t1.dylib \ +# RUN: ld64.lld -arch x86_64 -dylib %s -all_load %t1.dylib \ # RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/x86_64/libSystem.yaml -o %t # RUN: llvm-nm -m %t | FileCheck %s # diff --git a/test/mach-o/force_load-x86_64.yaml b/test/mach-o/force_load-x86_64.yaml index 5b37f4764e68..7ea2a7851833 100644 --- a/test/mach-o/force_load-x86_64.yaml +++ b/test/mach-o/force_load-x86_64.yaml @@ -1,8 +1,8 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \ # RUN: %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t1 # RUN: llvm-nm -m -n %t1 | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \ # RUN: -force_load %p/Inputs/libfoo.a %p/Inputs/libbar.a -o %t2 # RUN: llvm-nm -m -n %t2 | FileCheck --check-prefix=CHECKF %s # diff --git a/test/mach-o/framework-user-paths.yaml b/test/mach-o/framework-user-paths.yaml index 80d6e3b5868b..bb4d82250723 100644 --- a/test/mach-o/framework-user-paths.yaml +++ b/test/mach-o/framework-user-paths.yaml @@ -5,7 +5,7 @@ # /opt/Frameworks should not be found in SDK # /System/Library/Frameworks is implicit and should be in SDK # -# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \ +# RUN: ld64.lld -arch x86_64 -r -test_file_usage -v \ # RUN: -path_exists myFrameworks \ # RUN: -path_exists myFrameworks/my.framework/my \ # RUN: -path_exists /opt/Frameworks \ diff --git a/test/mach-o/function-starts-load-command.yaml b/test/mach-o/function-starts-load-command.yaml index 5cfe9dcac67d..fadc731e40e1 100644 --- a/test/mach-o/function-starts-load-command.yaml +++ b/test/mach-o/function-starts-load-command.yaml @@ -1,8 +1,8 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -function_starts -no_function_starts && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_FUNCTION_STARTS --- !mach-o arch: x86_64 diff --git a/test/mach-o/gcc_except_tab-got-arm64.yaml b/test/mach-o/gcc_except_tab-got-arm64.yaml index 47b174d6cf29..ed517c8bd6b1 100644 --- a/test/mach-o/gcc_except_tab-got-arm64.yaml +++ b/test/mach-o/gcc_except_tab-got-arm64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch arm64 %s \ +# RUN: ld64.lld -arch arm64 %s \ # RUN: -dylib %p/Inputs/arm64/libSystem.yaml -o %t # RUN: llvm-objdump -section-headers %t | FileCheck %s diff --git a/test/mach-o/got-order.yaml b/test/mach-o/got-order.yaml index 2e8579cad6d2..f7984741e519 100644 --- a/test/mach-o/got-order.yaml +++ b/test/mach-o/got-order.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/got-order.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/got-order.yaml \ # RUN: %p/Inputs/got-order2.yaml -o %t %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-objdump -bind %t | FileCheck %s # diff --git a/test/mach-o/hello-world-arm64.yaml b/test/mach-o/hello-world-arm64.yaml index 138af5940997..b2e73662c13f 100644 --- a/test/mach-o/hello-world-arm64.yaml +++ b/test/mach-o/hello-world-arm64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t +# RUN: ld64.lld -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t # RUN: llvm-nm -m -n %t | FileCheck %s # RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-PRIVATE-HEADER # diff --git a/test/mach-o/hello-world-armv6.yaml b/test/mach-o/hello-world-armv6.yaml index 8a9edeeddbac..b14b775baaf7 100644 --- a/test/mach-o/hello-world-armv6.yaml +++ b/test/mach-o/hello-world-armv6.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch armv6 %s %p/Inputs/hello-world-armv6.yaml -o %t +# RUN: ld64.lld -arch armv6 %s %p/Inputs/hello-world-armv6.yaml -o %t # RUN: llvm-nm -m %t | FileCheck %s # # Test that armv6 (arm) hello-world can be linked into a mach-o executable diff --git a/test/mach-o/hello-world-armv7.yaml b/test/mach-o/hello-world-armv7.yaml index 1871d68f6b92..28a96af0a882 100644 --- a/test/mach-o/hello-world-armv7.yaml +++ b/test/mach-o/hello-world-armv7.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch armv7 %s %p/Inputs/hello-world-armv7.yaml -o %t +# RUN: ld64.lld -arch armv7 %s %p/Inputs/hello-world-armv7.yaml -o %t # RUN: llvm-nm -m -n %t | FileCheck %s # # Test that armv7 (thumb) hello-world can be linked into a mach-o executable diff --git a/test/mach-o/hello-world-x86.yaml b/test/mach-o/hello-world-x86.yaml index 779b6811e080..7a0cfdc909f0 100644 --- a/test/mach-o/hello-world-x86.yaml +++ b/test/mach-o/hello-world-x86.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t +# RUN: ld64.lld -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t # RUN: llvm-nm -m %t | FileCheck %s # # Test that i386 hello-world can be linked into a mach-o executable diff --git a/test/mach-o/hello-world-x86_64.yaml b/test/mach-o/hello-world-x86_64.yaml index 8803c4476c39..9df969d6baf7 100644 --- a/test/mach-o/hello-world-x86_64.yaml +++ b/test/mach-o/hello-world-x86_64.yaml @@ -1,8 +1,8 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml \ # RUN: -o %t # RUN: llvm-nm -m -n %t | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml \ # RUN: -dead_strip -o %t2 # RUN: llvm-nm -m -n %t2 | FileCheck %s # diff --git a/test/mach-o/image-base.yaml b/test/mach-o/image-base.yaml index aa78fea1c338..f0eb68096604 100644 --- a/test/mach-o/image-base.yaml +++ b/test/mach-o/image-base.yaml @@ -1,10 +1,10 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 %s -o %t -image_base 31415926000 %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-readobj -macho-segment %t | FileCheck %s -# RUN: not lld -flavor darwin -arch x86_64 -image_base 0x31415926530 %s >/dev/null 2> %t +# RUN: not ld64.lld -arch x86_64 -image_base 0x31415926530 %s >/dev/null 2> %t # RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED -# RUN: not lld -flavor darwin -arch x86_64 -image_base 1000 %s >/dev/null 2> %t +# RUN: not ld64.lld -arch x86_64 -image_base 1000 %s >/dev/null 2> %t # RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-OVERLAP -# RUN: not lld -flavor darwin -arch x86_64 -image_base hithere %s >/dev/null 2> %t +# RUN: not ld64.lld -arch x86_64 -image_base hithere %s >/dev/null 2> %t # RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX --- !native diff --git a/test/mach-o/infer-arch.yaml b/test/mach-o/infer-arch.yaml index c09c94dd1b70..2dbf124ee4e6 100644 --- a/test/mach-o/infer-arch.yaml +++ b/test/mach-o/infer-arch.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch i386 -macosx_version_min 10.8 %s -r -o %t \ -# RUN: && lld -flavor darwin -r %t -o %t2 -print_atoms | FileCheck %s +# RUN: ld64.lld -arch i386 -macosx_version_min 10.8 %s -r -o %t \ +# RUN: && ld64.lld -r %t -o %t2 -print_atoms | FileCheck %s # # Test linker can detect architecture without -arch option. # diff --git a/test/mach-o/interposing-section.yaml b/test/mach-o/interposing-section.yaml index ec4eaa3f70ad..7b45f8a4d834 100644 --- a/test/mach-o/interposing-section.yaml +++ b/test/mach-o/interposing-section.yaml @@ -1,8 +1,8 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/interposing-section.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/interposing-section.yaml \ # RUN: -dylib -o %t %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-objdump -private-headers %t | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 %s -r -o %t1 +# RUN: ld64.lld -arch x86_64 %s -r -o %t1 # RUN: llvm-objdump -private-headers %t1 | FileCheck %s # # Test that interposing section is preserved by linker. diff --git a/test/mach-o/keep_private_externs.yaml b/test/mach-o/keep_private_externs.yaml index e7adf180fc7b..fdee3d4bf043 100644 --- a/test/mach-o/keep_private_externs.yaml +++ b/test/mach-o/keep_private_externs.yaml @@ -1,7 +1,7 @@ -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t \ +# RUN: ld64.lld -arch x86_64 -r %s -o %t \ # RUN: && llvm-nm -m %t | FileCheck %s # -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t2 -keep_private_externs \ +# RUN: ld64.lld -arch x86_64 -r %s -o %t2 -keep_private_externs \ # RUN: && llvm-nm -m %t2 | FileCheck -check-prefix=CHECK_KPE %s # # Test -keep_private_externs in -r mode. diff --git a/test/mach-o/lazy-bind-x86_64.yaml b/test/mach-o/lazy-bind-x86_64.yaml index 1322719e5f65..37b8c31a9552 100644 --- a/test/mach-o/lazy-bind-x86_64.yaml +++ b/test/mach-o/lazy-bind-x86_64.yaml @@ -1,6 +1,6 @@ # REQUIRES: x86 -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: %p/Inputs/lazy-bind-x86_64.yaml %p/Inputs/lazy-bind-x86_64-2.yaml \ # RUN: %p/Inputs/lazy-bind-x86_64-3.yaml -o %t \ # RUN: %p/Inputs/x86_64/libSystem.yaml diff --git a/test/mach-o/lc_segment_filesize.yaml b/test/mach-o/lc_segment_filesize.yaml index 4413c7698767..71184c230842 100644 --- a/test/mach-o/lc_segment_filesize.yaml +++ b/test/mach-o/lc_segment_filesize.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -o %t %s && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -o %t %s && llvm-objdump -private-headers %t | FileCheck %s # CHECK: filesize 19 diff --git a/test/mach-o/lib-search-paths.yaml b/test/mach-o/lib-search-paths.yaml index 5005f016857f..68998e03f4f2 100644 --- a/test/mach-o/lib-search-paths.yaml +++ b/test/mach-o/lib-search-paths.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -r -print_atoms 2>&1 | FileCheck %s +# RUN: ld64.lld -arch x86_64 %s -syslibroot %p/Inputs/lib-search-paths -lmyshared -lmystatic -lfile.o -r -print_atoms 2>&1 | FileCheck %s --- !native undefined-atoms: diff --git a/test/mach-o/library-order.yaml b/test/mach-o/library-order.yaml index b53232dd398f..6e091fb9aa83 100644 --- a/test/mach-o/library-order.yaml +++ b/test/mach-o/library-order.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %s -o %t \ +# RUN: ld64.lld -arch x86_64 %p/Inputs/libfoo.a %s -o %t \ # RUN: %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-nm -m -n %t | FileCheck %s # diff --git a/test/mach-o/library-rescan.yaml b/test/mach-o/library-rescan.yaml index 99c7b88c7e34..a09f35259e44 100644 --- a/test/mach-o/library-rescan.yaml +++ b/test/mach-o/library-rescan.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \ +# RUN: ld64.lld -arch x86_64 %p/Inputs/libfoo.a %p/Inputs/libbar.a \ # RUN: %s -o %t %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-nm -m -n %t | FileCheck %s # diff --git a/test/mach-o/libresolve-bizarre-root-override.yaml b/test/mach-o/libresolve-bizarre-root-override.yaml index c65ca319432d..1c346808022c 100644 --- a/test/mach-o/libresolve-bizarre-root-override.yaml +++ b/test/mach-o/libresolve-bizarre-root-override.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -test_file_usage -v \ +# RUN: not ld64.lld -test_file_usage -v \ # RUN: -path_exists /usr/lib \ # RUN: -path_exists /Applications/MySDK/usr/local/lib \ # RUN: -path_exists /Applications/MySDK/usr/lib \ diff --git a/test/mach-o/libresolve-multiple-syslibroots.yaml b/test/mach-o/libresolve-multiple-syslibroots.yaml index 0b63eb64e7a9..bc8e96462c2f 100644 --- a/test/mach-o/libresolve-multiple-syslibroots.yaml +++ b/test/mach-o/libresolve-multiple-syslibroots.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -test_file_usage -v \ +# RUN: ld64.lld -test_file_usage -v \ # RUN: -path_exists /usr/lib \ # RUN: -path_exists /Applications/MyFirstSDK/usr/local/lib \ # RUN: -path_exists /Applications/MySecondSDK/usr/local/lib \ diff --git a/test/mach-o/libresolve-one-syslibroot.yaml b/test/mach-o/libresolve-one-syslibroot.yaml index f9042fcfada2..8e28ab4d302a 100644 --- a/test/mach-o/libresolve-one-syslibroot.yaml +++ b/test/mach-o/libresolve-one-syslibroot.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -test_file_usage -v \ +# RUN: ld64.lld -test_file_usage -v \ # RUN: -path_exists /usr/lib \ # RUN: -path_exists /Applications/MySDK/usr/local/lib \ # RUN: -path_exists /Applications/MySDK/usr/local/lib/libSystem.a \ diff --git a/test/mach-o/libresolve-simple.yaml b/test/mach-o/libresolve-simple.yaml index ffb045fa3e3c..965099122d44 100644 --- a/test/mach-o/libresolve-simple.yaml +++ b/test/mach-o/libresolve-simple.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \ +# RUN: ld64.lld -arch x86_64 -r -test_file_usage -v \ # RUN: -path_exists /usr/lib \ # RUN: -path_exists /usr/local/lib \ # RUN: -path_exists /usr/lib/libSystem.dylib \ diff --git a/test/mach-o/libresolve-user-paths.yaml b/test/mach-o/libresolve-user-paths.yaml index 9fe885671686..b50703d821d6 100644 --- a/test/mach-o/libresolve-user-paths.yaml +++ b/test/mach-o/libresolve-user-paths.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \ +# RUN: ld64.lld -arch x86_64 -r -test_file_usage -v \ # RUN: -path_exists hasFoo \ # RUN: -path_exists hasFoo/libFoo.dylib \ # RUN: -path_exists /hasBar \ diff --git a/test/mach-o/libresolve-z.yaml b/test/mach-o/libresolve-z.yaml index 1df7eceac1e4..509f80b525dc 100644 --- a/test/mach-o/libresolve-z.yaml +++ b/test/mach-o/libresolve-z.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \ +# RUN: ld64.lld -arch x86_64 -r -test_file_usage -v \ # RUN: -path_exists /usr/lib \ # RUN: -path_exists /usr/local/lib \ # RUN: -path_exists /usr/lib/libSystem.dylib \ diff --git a/test/mach-o/mach_header-cpusubtype.yaml b/test/mach-o/mach_header-cpusubtype.yaml index fa9024f999db..95d4627cf99f 100644 --- a/test/mach-o/mach_header-cpusubtype.yaml +++ b/test/mach-o/mach_header-cpusubtype.yaml @@ -1,6 +1,6 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.4 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_LIB64 -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=LIB64 -# RUN: lld -flavor darwin -arch x86_64 -dylib -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=DYLIB +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.4 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_LIB64 +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=LIB64 +# RUN: ld64.lld -arch x86_64 -dylib -macosx_version_min 10.5 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=DYLIB --- !mach-o arch: x86_64 diff --git a/test/mach-o/mh_bundle_header.yaml b/test/mach-o/mh_bundle_header.yaml index d1b7d9ab2143..33944a4be882 100644 --- a/test/mach-o/mh_bundle_header.yaml +++ b/test/mach-o/mh_bundle_header.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch x86_64 %s -bundle -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 %s -bundle -dead_strip -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 %s -bundle -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 %s -bundle -dead_strip -o %t %p/Inputs/x86_64/libSystem.yaml && llvm-nm -m -n %t | FileCheck %s # # Test that __mh_bundle_header symbol is available for bundles # diff --git a/test/mach-o/mh_dylib_header.yaml b/test/mach-o/mh_dylib_header.yaml index 8222063ee161..27d34c44ad18 100644 --- a/test/mach-o/mh_dylib_header.yaml +++ b/test/mach-o/mh_dylib_header.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s -dylib -o %t %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 %s -dylib -o %t %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-nm -m -n %t | FileCheck %s # # Test that __mh_dylib_header symbol is available for dylibs diff --git a/test/mach-o/objc-category-list-atom.yaml b/test/mach-o/objc-category-list-atom.yaml index 93974a646e06..4e6cd847840e 100644 --- a/test/mach-o/objc-category-list-atom.yaml +++ b/test/mach-o/objc-category-list-atom.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s --- !mach-o diff --git a/test/mach-o/objc-image-info-host-vs-simulator.yaml b/test/mach-o/objc-image-info-host-vs-simulator.yaml index f836a7423271..38f251beb4ac 100644 --- a/test/mach-o/objc-image-info-host-vs-simulator.yaml +++ b/test/mach-o/objc-image-info-host-vs-simulator.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -r %s 2>&1 | FileCheck %s # The file is built for the host, but the objc image info flags are for # the simulator. diff --git a/test/mach-o/objc-image-info-invalid-size.yaml b/test/mach-o/objc-image-info-invalid-size.yaml index 47fce886f2cc..a67f61a2fcca 100644 --- a/test/mach-o/objc-image-info-invalid-size.yaml +++ b/test/mach-o/objc-image-info-invalid-size.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -r %s 2>&1 | FileCheck %s --- !mach-o arch: x86_64 diff --git a/test/mach-o/objc-image-info-invalid-version.yaml b/test/mach-o/objc-image-info-invalid-version.yaml index 04d62e9fb789..845ac56f12b1 100644 --- a/test/mach-o/objc-image-info-invalid-version.yaml +++ b/test/mach-o/objc-image-info-invalid-version.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -r %s 2>&1 | FileCheck %s --- !mach-o arch: x86_64 diff --git a/test/mach-o/objc-image-info-mismatched-swift-version.yaml b/test/mach-o/objc-image-info-mismatched-swift-version.yaml index efb7c319285b..238991782611 100644 --- a/test/mach-o/objc-image-info-mismatched-swift-version.yaml +++ b/test/mach-o/objc-image-info-mismatched-swift-version.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s %p/Inputs/swift-version-1.yaml 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -r %s %p/Inputs/swift-version-1.yaml 2>&1 | FileCheck %s --- !mach-o arch: x86_64 diff --git a/test/mach-o/objc-image-info-pass-output.yaml b/test/mach-o/objc-image-info-pass-output.yaml index 7fc95a846324..c81e6bce1531 100644 --- a/test/mach-o/objc-image-info-pass-output.yaml +++ b/test/mach-o/objc-image-info-pass-output.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s +# RUN: ld64.lld -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s # Make sure that we have an objc image info in the output. It should have # been generated by the objc pass. diff --git a/test/mach-o/objc-image-info-simulator-vs-host.yaml b/test/mach-o/objc-image-info-simulator-vs-host.yaml index c4f9bd58f968..4fda686c9027 100644 --- a/test/mach-o/objc-image-info-simulator-vs-host.yaml +++ b/test/mach-o/objc-image-info-simulator-vs-host.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -ios_simulator_version_min 5.0 -arch x86_64 -r %s 2>&1 | FileCheck %s # The file is built for the simulator, but the objc image info flags are for # the host. diff --git a/test/mach-o/objc-image-info-unsupported-gc.yaml b/test/mach-o/objc-image-info-unsupported-gc.yaml index 9f98369a39cb..1014b4acf7cc 100644 --- a/test/mach-o/objc-image-info-unsupported-gc.yaml +++ b/test/mach-o/objc-image-info-unsupported-gc.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s 2>&1 | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -r %s 2>&1 | FileCheck %s --- !mach-o arch: x86_64 diff --git a/test/mach-o/objc_export_list.yaml b/test/mach-o/objc_export_list.yaml index a2fcfa22ec07..55dff8d3e856 100644 --- a/test/mach-o/objc_export_list.yaml +++ b/test/mach-o/objc_export_list.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -dylib %s -o %t \ +# RUN: ld64.lld -arch x86_64 -dylib %s -o %t \ # RUN: -exported_symbol .objc_class_name_Foo %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-nm -m %t | FileCheck %s # diff --git a/test/mach-o/order_file-basic.yaml b/test/mach-o/order_file-basic.yaml index f4d29fa17012..8c43ee6a7aaa 100644 --- a/test/mach-o/order_file-basic.yaml +++ b/test/mach-o/order_file-basic.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/x86_64/libSystem.yaml \ # RUN: -order_file %p/Inputs/order_file-basic.order \ # RUN: -force_load %p/Inputs/libfoo.a -o %t # RUN: llvm-nm -m -n %t | FileCheck %s diff --git a/test/mach-o/parse-aliases.yaml b/test/mach-o/parse-aliases.yaml index 54da2d64e63a..9d0a1c07dfce 100644 --- a/test/mach-o/parse-aliases.yaml +++ b/test/mach-o/parse-aliases.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test multiple labels to same address parse into aliases. # diff --git a/test/mach-o/parse-arm-relocs.yaml b/test/mach-o/parse-arm-relocs.yaml index abeb3ddeb9d1..9add766bef0c 100644 --- a/test/mach-o/parse-arm-relocs.yaml +++ b/test/mach-o/parse-arm-relocs.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s -# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch armv7 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s # # Test parsing of armv7 relocations. # diff --git a/test/mach-o/parse-cfstring32.yaml b/test/mach-o/parse-cfstring32.yaml index 8e746f276664..52588d561dd9 100644 --- a/test/mach-o/parse-cfstring32.yaml +++ b/test/mach-o/parse-cfstring32.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of mach-o functions. # diff --git a/test/mach-o/parse-cfstring64.yaml b/test/mach-o/parse-cfstring64.yaml index b90277f056e5..f427ae51b648 100644 --- a/test/mach-o/parse-cfstring64.yaml +++ b/test/mach-o/parse-cfstring64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of CFString constants. # diff --git a/test/mach-o/parse-compact-unwind32.yaml b/test/mach-o/parse-compact-unwind32.yaml index ff613f0809bb..6af5fd4a2371 100644 --- a/test/mach-o/parse-compact-unwind32.yaml +++ b/test/mach-o/parse-compact-unwind32.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of __LD/__compact_unwind (compact unwind) section. # diff --git a/test/mach-o/parse-compact-unwind64.yaml b/test/mach-o/parse-compact-unwind64.yaml index af8967476e16..f0c1c86c2c07 100644 --- a/test/mach-o/parse-compact-unwind64.yaml +++ b/test/mach-o/parse-compact-unwind64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of __LD/__compact_unwind (compact unwind) section. # diff --git a/test/mach-o/parse-data-in-code-armv7.yaml b/test/mach-o/parse-data-in-code-armv7.yaml index 163cb18fdc5f..18eb6ffddc57 100644 --- a/test/mach-o/parse-data-in-code-armv7.yaml +++ b/test/mach-o/parse-data-in-code-armv7.yaml @@ -1,6 +1,6 @@ -# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %s -o %t | FileCheck %s -# RUN: lld -flavor darwin -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s -# RUN: lld -flavor darwin -arch armv7 -dylib %s -o %t3.dylib %p/Inputs/armv7/libSystem.yaml \ +# RUN: ld64.lld -arch armv7 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch armv7 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch armv7 -dylib %s -o %t3.dylib %p/Inputs/armv7/libSystem.yaml \ # RUN: && llvm-objdump -macho -private-headers %t3.dylib | FileCheck --check-prefix=CHECK2 %s # # Test parsing LC_DATA_IN_CODE diff --git a/test/mach-o/parse-data-in-code-x86.yaml b/test/mach-o/parse-data-in-code-x86.yaml index 43934440f2a0..927a9aa30cb0 100644 --- a/test/mach-o/parse-data-in-code-x86.yaml +++ b/test/mach-o/parse-data-in-code-x86.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s \ -# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s \ +# RUN: && ld64.lld -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s # # Test parsing LC_DATA_IN_CODE # diff --git a/test/mach-o/parse-data-relocs-arm64.yaml b/test/mach-o/parse-data-relocs-arm64.yaml index 0edd64689b2e..a46da1bffba3 100644 --- a/test/mach-o/parse-data-relocs-arm64.yaml +++ b/test/mach-o/parse-data-relocs-arm64.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s # # Test parsing and writing of arm64 data relocations. # diff --git a/test/mach-o/parse-data-relocs-x86_64.yaml b/test/mach-o/parse-data-relocs-x86_64.yaml index 6b5bb4b8fb59..d696aff0feff 100644 --- a/test/mach-o/parse-data-relocs-x86_64.yaml +++ b/test/mach-o/parse-data-relocs-x86_64.yaml @@ -1,6 +1,6 @@ -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \ -# RUN: && lld -flavor darwin -arch x86_64 %t -r -print_atoms -o %t2 | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r %s -o %t -print_atoms | FileCheck %s \ +# RUN: && ld64.lld -arch x86_64 %t -r -print_atoms -o %t2 | FileCheck %s # # Test parsing and writing of x86_64 data relocations. # diff --git a/test/mach-o/parse-data.yaml b/test/mach-o/parse-data.yaml index 3b422e04cae7..b1929ef230b6 100644 --- a/test/mach-o/parse-data.yaml +++ b/test/mach-o/parse-data.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of mach-o data symbols. # diff --git a/test/mach-o/parse-eh-frame-relocs-x86_64.yaml b/test/mach-o/parse-eh-frame-relocs-x86_64.yaml index b009cbcea139..0bc47ffef009 100644 --- a/test/mach-o/parse-eh-frame-relocs-x86_64.yaml +++ b/test/mach-o/parse-eh-frame-relocs-x86_64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of x86_64 __eh_frame (dwarf unwind) relocations. diff --git a/test/mach-o/parse-eh-frame-x86-anon.yaml b/test/mach-o/parse-eh-frame-x86-anon.yaml index 09b6ba37c09a..7a85dcb2de90 100644 --- a/test/mach-o/parse-eh-frame-x86-anon.yaml +++ b/test/mach-o/parse-eh-frame-x86-anon.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of new __eh_frame (dwarf unwind) section that has no .eh labels # and no relocations. diff --git a/test/mach-o/parse-eh-frame-x86-labeled.yaml b/test/mach-o/parse-eh-frame-x86-labeled.yaml index 5be5abcc4a0e..7ec86de6d012 100644 --- a/test/mach-o/parse-eh-frame-x86-labeled.yaml +++ b/test/mach-o/parse-eh-frame-x86-labeled.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of old __eh_frame (dwarf unwind) section that has .eh labels # and relocations. diff --git a/test/mach-o/parse-eh-frame.yaml b/test/mach-o/parse-eh-frame.yaml index 6453474024bb..6571c4f4d2d8 100644 --- a/test/mach-o/parse-eh-frame.yaml +++ b/test/mach-o/parse-eh-frame.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of __eh_frame (dwarf unwind) section. # diff --git a/test/mach-o/parse-function.yaml b/test/mach-o/parse-function.yaml index bfd8e5c815f4..677cf9a7f166 100644 --- a/test/mach-o/parse-function.yaml +++ b/test/mach-o/parse-function.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch x86_64 -r %s -o %t -# RUN: lld -flavor darwin -arch x86_64 -r %t -print_atoms -o %t2 | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r %s -o %t +# RUN: ld64.lld -arch x86_64 -r %t -print_atoms -o %t2 | FileCheck %s # # Test parsing of mach-o functions. # diff --git a/test/mach-o/parse-initializers32.yaml b/test/mach-o/parse-initializers32.yaml index ede7b90e2cb9..b15f2954a4bb 100644 --- a/test/mach-o/parse-initializers32.yaml +++ b/test/mach-o/parse-initializers32.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of literal sections. # diff --git a/test/mach-o/parse-initializers64.yaml b/test/mach-o/parse-initializers64.yaml index c55a0ea0a5fa..9b3cb2d2264f 100644 --- a/test/mach-o/parse-initializers64.yaml +++ b/test/mach-o/parse-initializers64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of literal sections. # diff --git a/test/mach-o/parse-literals-error.yaml b/test/mach-o/parse-literals-error.yaml index 8daeeca5f654..9dad0cbbf974 100644 --- a/test/mach-o/parse-literals-error.yaml +++ b/test/mach-o/parse-literals-error.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t 2> %t.err +# RUN: not ld64.lld -arch x86_64 -r -print_atoms %s -o %t 2> %t.err # RUN: FileCheck %s < %t.err # # Test for error if literal section is not correct size mulitple. diff --git a/test/mach-o/parse-literals.yaml b/test/mach-o/parse-literals.yaml index 7f80ba5212b8..f23653d475a9 100644 --- a/test/mach-o/parse-literals.yaml +++ b/test/mach-o/parse-literals.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of literal sections. # diff --git a/test/mach-o/parse-non-lazy-pointers.yaml b/test/mach-o/parse-non-lazy-pointers.yaml index 0b0ec5cf36ef..9d6a86221b2f 100644 --- a/test/mach-o/parse-non-lazy-pointers.yaml +++ b/test/mach-o/parse-non-lazy-pointers.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of non-lazy-pointer sections. # diff --git a/test/mach-o/parse-relocs-x86.yaml b/test/mach-o/parse-relocs-x86.yaml index c7ce80bb42a1..b93b43645714 100644 --- a/test/mach-o/parse-relocs-x86.yaml +++ b/test/mach-o/parse-relocs-x86.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch i386 -r -print_atoms %s -o %t | FileCheck %s \ -# RUN: && lld -flavor darwin -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch i386 -r -print_atoms %s -o %t | FileCheck %s \ +# RUN: && ld64.lld -arch i386 -r -print_atoms %t -o %t2 | FileCheck %s # # Test parsing and writing of x86 relocations. # diff --git a/test/mach-o/parse-section-no-symbol.yaml b/test/mach-o/parse-section-no-symbol.yaml index 46d005a1cd18..6164f0e3aaaf 100644 --- a/test/mach-o/parse-section-no-symbol.yaml +++ b/test/mach-o/parse-section-no-symbol.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r %s -print_atoms -o %t2 | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r %s -print_atoms -o %t2 | FileCheck %s # # Test parsing of mach-o functions with no symbols at all. # diff --git a/test/mach-o/parse-tentative-defs.yaml b/test/mach-o/parse-tentative-defs.yaml index 1757c8c928b6..63596e9e37ad 100644 --- a/test/mach-o/parse-tentative-defs.yaml +++ b/test/mach-o/parse-tentative-defs.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s # # Test parsing of tentative definitions, including size, scope, and alignment. # diff --git a/test/mach-o/parse-text-relocs-arm64.yaml b/test/mach-o/parse-text-relocs-arm64.yaml index 38a52e7f6f28..9112782eba98 100644 --- a/test/mach-o/parse-text-relocs-arm64.yaml +++ b/test/mach-o/parse-text-relocs-arm64.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \ -# RUN: && lld -flavor darwin -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch arm64 -r -print_atoms %s -o %t | FileCheck %s \ +# RUN: && ld64.lld -arch arm64 -r -print_atoms %t -o %t2 | FileCheck %s # # Test parsing and writing of arm64 text relocations. # diff --git a/test/mach-o/parse-text-relocs-x86_64.yaml b/test/mach-o/parse-text-relocs-x86_64.yaml index 6d0a52f60045..76df030c69ed 100644 --- a/test/mach-o/parse-text-relocs-x86_64.yaml +++ b/test/mach-o/parse-text-relocs-x86_64.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \ -# RUN: && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \ +# RUN: && ld64.lld -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s # # Test parsing and writing of x86_64 text relocations. # diff --git a/test/mach-o/parse-tlv-relocs-x86-64.yaml b/test/mach-o/parse-tlv-relocs-x86-64.yaml index 78b17841d4e7..b1a12e20ff7b 100644 --- a/test/mach-o/parse-tlv-relocs-x86-64.yaml +++ b/test/mach-o/parse-tlv-relocs-x86-64.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \ -# RUN: && lld -flavor darwin -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s +# RUN: ld64.lld -arch x86_64 -r -print_atoms %s -o %t | FileCheck %s \ +# RUN: && ld64.lld -arch x86_64 -r -print_atoms %t -o %t2 | FileCheck %s # # Test parsing of x86_64 tlv relocations. diff --git a/test/mach-o/re-exported-dylib-ordinal.yaml b/test/mach-o/re-exported-dylib-ordinal.yaml index ff4d756338ce..b25a5ec00221 100644 --- a/test/mach-o/re-exported-dylib-ordinal.yaml +++ b/test/mach-o/re-exported-dylib-ordinal.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s \ # RUN: %p/Inputs/re-exported-dylib-ordinal.yaml \ # RUN: %p/Inputs/re-exported-dylib-ordinal2.yaml \ # RUN: %p/Inputs/re-exported-dylib-ordinal3.yaml -dylib -o %t \ diff --git a/test/mach-o/rpath.yaml b/test/mach-o/rpath.yaml index 639149381293..b25266ced993 100644 --- a/test/mach-o/rpath.yaml +++ b/test/mach-o/rpath.yaml @@ -1,5 +1,5 @@ # Check we handle -rpath correctly: -# RUN: lld -flavor darwin -arch x86_64 -rpath @loader_path/../Frameworks \ +# RUN: ld64.lld -arch x86_64 -rpath @loader_path/../Frameworks \ # RUN: %p/Inputs/x86_64/libSystem.yaml %s -o %t # RUN: llvm-objdump -private-headers %t | FileCheck %s --check-prefix=CHECK-BINARY-WRITE diff --git a/test/mach-o/run-tlv-pass-x86-64.yaml b/test/mach-o/run-tlv-pass-x86-64.yaml index dd524c067d87..765e1c1fd1bb 100644 --- a/test/mach-o/run-tlv-pass-x86-64.yaml +++ b/test/mach-o/run-tlv-pass-x86-64.yaml @@ -1,5 +1,5 @@ -# RUN: lld -flavor darwin -macosx_version_min 10.7 -arch x86_64 -print_atoms %s -o %t | FileCheck %s -# RUN: not lld -flavor darwin -macosx_version_min 10.6 -arch x86_64 -o %t %s 2> %t2 +# RUN: ld64.lld -macosx_version_min 10.7 -arch x86_64 -print_atoms %s -o %t | FileCheck %s +# RUN: not ld64.lld -macosx_version_min 10.6 -arch x86_64 -o %t %s 2> %t2 # RUN: FileCheck < %t2 %s --check-prefix=CHECK-ERROR # RUN: llvm-objdump -macho -private-headers %t | FileCheck %s --check-prefix=CHECK-LOADCMDS # diff --git a/test/mach-o/sdk-version-error.yaml b/test/mach-o/sdk-version-error.yaml index 2607bb8e9c58..c7e4011b238c 100644 --- a/test/mach-o/sdk-version-error.yaml +++ b/test/mach-o/sdk-version-error.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -sdk_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR +# RUN: not ld64.lld -arch x86_64 -sdk_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR --- !mach-o arch: x86_64 diff --git a/test/mach-o/sectalign.yaml b/test/mach-o/sectalign.yaml index f0df9f9c5485..b788d422bbb8 100644 --- a/test/mach-o/sectalign.yaml +++ b/test/mach-o/sectalign.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -dylib \ # RUN: -sectalign __DATA __custom 0x800 -sectalign __TEXT __text 0x400 \ # RUN: %p/Inputs/x86_64/libSystem.yaml -o %t \ # RUN: && llvm-readobj -sections %t | FileCheck %s diff --git a/test/mach-o/sectattrs.yaml b/test/mach-o/sectattrs.yaml index 21113dcf8280..467c2b7fca07 100644 --- a/test/mach-o/sectattrs.yaml +++ b/test/mach-o/sectattrs.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -dylib \ +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -dylib \ # RUN: %p/Inputs/x86_64/libSystem.yaml -o %t \ # RUN: && llvm-objdump -private-headers %t | FileCheck %s # diff --git a/test/mach-o/sectcreate.yaml b/test/mach-o/sectcreate.yaml index 51c59dc5f3d4..aa32a05a6fb7 100644 --- a/test/mach-o/sectcreate.yaml +++ b/test/mach-o/sectcreate.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -r -arch x86_64 -o %t -sectcreate __DATA __data \ +# RUN: ld64.lld -r -arch x86_64 -o %t -sectcreate __DATA __data \ # RUN: %p/Inputs/hw.raw_bytes -print_atoms | FileCheck %s # CHECK: --- !native diff --git a/test/mach-o/seg-protection-arm64.yaml b/test/mach-o/seg-protection-arm64.yaml index f63b33ad2dc3..6b00fc9cfaea 100644 --- a/test/mach-o/seg-protection-arm64.yaml +++ b/test/mach-o/seg-protection-arm64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch arm64 %s %p/Inputs/hello-world-arm64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --- !mach-o arch: arm64 diff --git a/test/mach-o/seg-protection-x86_64.yaml b/test/mach-o/seg-protection-x86_64.yaml index 474f72f4c57f..2ce356634c7b 100644 --- a/test/mach-o/seg-protection-x86_64.yaml +++ b/test/mach-o/seg-protection-x86_64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/hello-world-x86_64.yaml -o %t && llvm-objdump -private-headers %t | FileCheck %s --- !mach-o arch: x86_64 diff --git a/test/mach-o/source-version.yaml b/test/mach-o/source-version.yaml index 4e0eaee394f1..ce185f8886b6 100644 --- a/test/mach-o/source-version.yaml +++ b/test/mach-o/source-version.yaml @@ -1,5 +1,5 @@ -# RUN: not lld -flavor darwin -arch x86_64 -source_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR -# RUN: lld -flavor darwin -arch x86_64 -source_version 10.1.2.3.4 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s +# RUN: not ld64.lld -arch x86_64 -source_version 10.blah %s -o %t 2>&1 | FileCheck %s --check-prefix=ERROR +# RUN: ld64.lld -arch x86_64 -source_version 10.1.2.3.4 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s --- !mach-o arch: x86_64 diff --git a/test/mach-o/stack-size.yaml b/test/mach-o/stack-size.yaml index 048282c504ef..6a5e313c4596 100644 --- a/test/mach-o/stack-size.yaml +++ b/test/mach-o/stack-size.yaml @@ -1,10 +1,10 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 %s -o %t %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-DEFAULT %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 %s -o %t -stack_size 31415926000 %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 %s -o %t -stack_size 31415926000 %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-objdump -private-headers %t | FileCheck --check-prefix=CHECK-EXPLICIT %s -# RUN: not lld -flavor darwin -arch x86_64 -stack_size 0x31415926530 %s >/dev/null 2> %t +# RUN: not ld64.lld -arch x86_64 -stack_size 0x31415926530 %s >/dev/null 2> %t # RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-MISPAGED -# RUN: not lld -flavor darwin -arch x86_64 -stack_size hithere %s >/dev/null 2> %t +# RUN: not ld64.lld -arch x86_64 -stack_size hithere %s >/dev/null 2> %t # RUN: FileCheck < %t %s --check-prefix=CHECK-ERROR-NOTHEX --- !native diff --git a/test/mach-o/string-table.yaml b/test/mach-o/string-table.yaml index eec2c77fe157..8bb4cfe495ad 100644 --- a/test/mach-o/string-table.yaml +++ b/test/mach-o/string-table.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t +# RUN: ld64.lld -arch i386 %s %p/Inputs/hello-world-x86.yaml -o %t # RUN: obj2yaml %t | FileCheck %s # # Test that the string table contains a ' ' as its first symbol diff --git a/test/mach-o/subsections-via-symbols-default.yaml b/test/mach-o/subsections-via-symbols-default.yaml index 93ddbc943f9a..a9bb4236875e 100644 --- a/test/mach-o/subsections-via-symbols-default.yaml +++ b/test/mach-o/subsections-via-symbols-default.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t +# RUN: ld64.lld -ios_simulator_version_min 5.0 -arch x86_64 -r %s -o %t # RUN: llvm-readobj -file-headers %t | FileCheck %s # Make sure that we have an objc image info in the output. It should have diff --git a/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml b/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml index b402ae3e17f2..a8ceb0f81ce4 100644 --- a/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml +++ b/test/mach-o/twolevel_namespace_undef_dynamic_lookup.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined dynamic_lookup %s -o %t %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined dynamic_lookup %s -o %t %p/Inputs/x86_64/libSystem.yaml # # Sanity check '-twolevel_namespace -undefined dynamic_lookup'. # This should pass without error, even though '_bar' is undefined. diff --git a/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml b/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml index 1ac704cdf954..6d9eaddacf99 100644 --- a/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml +++ b/test/mach-o/twolevel_namespace_undef_warning_suppress.yaml @@ -1,6 +1,6 @@ -# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined warning %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \ +# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined warning %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \ # RUN: FileCheck --check-prefix=CHECK-WARNING %s -# RUN: not lld -flavor darwin -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \ +# RUN: not ld64.lld -arch x86_64 -macosx_version_min 10.9 -twolevel_namespace -undefined suppress %s -o %t %p/Inputs/x86_64/libSystem.yaml 2>&1 | \ # RUN: FileCheck --check-prefix=CHECK-SUPPRESS %s --- !native diff --git a/test/mach-o/unwind-info-simple-arm64.yaml b/test/mach-o/unwind-info-simple-arm64.yaml index 4caaf3582630..920cc0d7c363 100644 --- a/test/mach-o/unwind-info-simple-arm64.yaml +++ b/test/mach-o/unwind-info-simple-arm64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch arm64 -o %t %s \ +# RUN: ld64.lld -arch arm64 -o %t %s \ # RUN: %p/Inputs/unwind-info-simple-arm64.yaml -e _main %p/Inputs/arm64/libSystem.yaml # RUN: llvm-objdump -unwind-info %t | FileCheck %s diff --git a/test/mach-o/unwind-info-simple-x86_64.yaml b/test/mach-o/unwind-info-simple-x86_64.yaml index 797c5a319d2c..0c9b74c478c9 100644 --- a/test/mach-o/unwind-info-simple-x86_64.yaml +++ b/test/mach-o/unwind-info-simple-x86_64.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s -o %t -e _main %p/Inputs/x86_64/libSystem.yaml +# RUN: ld64.lld -arch x86_64 %s -o %t -e _main %p/Inputs/x86_64/libSystem.yaml # RUN: llvm-objdump -unwind-info %t | FileCheck %s # CHECK: Contents of __unwind_info section: diff --git a/test/mach-o/upward-dylib-load-command.yaml b/test/mach-o/upward-dylib-load-command.yaml index 54e31f6960be..7fc703c7bef5 100644 --- a/test/mach-o/upward-dylib-load-command.yaml +++ b/test/mach-o/upward-dylib-load-command.yaml @@ -1,6 +1,6 @@ -# RUN: lld -flavor darwin -arch x86_64 -dylib %p/Inputs/bar.yaml \ +# RUN: ld64.lld -arch x86_64 -dylib %p/Inputs/bar.yaml \ # RUN: -install_name /usr/lib/libbar.dylib %p/Inputs/x86_64/libSystem.yaml -o %t1.dylib -# RUN: lld -flavor darwin -arch x86_64 -dylib %s -upward_library %t1.dylib \ +# RUN: ld64.lld -arch x86_64 -dylib %s -upward_library %t1.dylib \ # RUN: -install_name /usr/lib/libfoo.dylib %p/Inputs/x86_64/libSystem.yaml -o %t # RUN: llvm-objdump -private-headers %t | FileCheck %s # diff --git a/test/mach-o/upward-dylib-paths.yaml b/test/mach-o/upward-dylib-paths.yaml index 53ff9fa2298c..48536330695a 100644 --- a/test/mach-o/upward-dylib-paths.yaml +++ b/test/mach-o/upward-dylib-paths.yaml @@ -1,6 +1,6 @@ # # -# RUN: lld -flavor darwin -arch x86_64 -r -test_file_usage -v \ +# RUN: ld64.lld -arch x86_64 -r -test_file_usage -v \ # RUN: -path_exists /Custom/Frameworks \ # RUN: -path_exists /Custom/Frameworks/Bar.framework/Bar \ # RUN: -path_exists /usr/lib \ diff --git a/test/mach-o/usage.yaml b/test/mach-o/usage.yaml index 20a506284c96..d95823d24b83 100644 --- a/test/mach-o/usage.yaml +++ b/test/mach-o/usage.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin | FileCheck %s +# RUN: not ld64.lld | FileCheck %s # # Test that running darwin linker with no option prints out usage message. # diff --git a/test/mach-o/use-dylib.yaml b/test/mach-o/use-dylib.yaml index c173cc0af352..bcb2d07e38e8 100644 --- a/test/mach-o/use-dylib.yaml +++ b/test/mach-o/use-dylib.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s \ +# RUN: ld64.lld -arch x86_64 %s \ # RUN: %p/Inputs/use-simple-dylib.yaml %p/Inputs/x86_64/libSystem.yaml -dylib -o %t.dylib # RUN: llvm-objdump -private-headers %t.dylib | FileCheck %s diff --git a/test/mach-o/use-simple-dylib.yaml b/test/mach-o/use-simple-dylib.yaml index 658be16356ea..09906597f8dd 100644 --- a/test/mach-o/use-simple-dylib.yaml +++ b/test/mach-o/use-simple-dylib.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 -print_atoms -r %s \ +# RUN: ld64.lld -arch x86_64 -print_atoms -r %s \ # RUN: %p/Inputs/use-simple-dylib.yaml -o %t | FileCheck %s diff --git a/test/mach-o/version-min-load-command-object.yaml b/test/mach-o/version-min-load-command-object.yaml index 33001cc6f715..08eb6ab768bf 100644 --- a/test/mach-o/version-min-load-command-object.yaml +++ b/test/mach-o/version-min-load-command-object.yaml @@ -1,6 +1,6 @@ -# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r -macosx_version_min 10.8 && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 %s -o %t -r %p/Inputs/no-version-min-load-command-object.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN +# RUN: ld64.lld -arch x86_64 %s -o %t -r -macosx_version_min 10.8 && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 %s -o %t -r && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 %s -o %t -r %p/Inputs/no-version-min-load-command-object.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN # If we are emitting an object file, then we only emit a min version load command if the source object file(s) all have # version(s) and either known platforms or contain min version load commands themselves. diff --git a/test/mach-o/version-min-load-command.yaml b/test/mach-o/version-min-load-command.yaml index cb5331ec7f4b..a4d39b85e4c2 100644 --- a/test/mach-o/version-min-load-command.yaml +++ b/test/mach-o/version-min-load-command.yaml @@ -1,11 +1,11 @@ -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s --check-prefix=WARNING -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command && llvm-objdump -private-headers %t | FileCheck %s -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml 2>&1 | FileCheck %s --check-prefix=WARNING +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command && llvm-objdump -private-headers %t | FileCheck %s +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static -version_load_command -no_version_load_command && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml -static && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=NO_VERSION_MIN -# RUN: lld -flavor darwin -arch x86_64 -macosx_version_min 10.8 -sdk_version 10.9 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=SDK_VERSION +# RUN: ld64.lld -arch x86_64 -macosx_version_min 10.8 -sdk_version 10.9 %s -o %t -dylib %p/Inputs/x86_64/libSystem.yaml && llvm-objdump -private-headers %t | FileCheck %s --check-prefix=SDK_VERSION --- !mach-o arch: x86_64 diff --git a/test/mach-o/write-final-sections.yaml b/test/mach-o/write-final-sections.yaml index 4e94acfa25b1..b39127139f80 100644 --- a/test/mach-o/write-final-sections.yaml +++ b/test/mach-o/write-final-sections.yaml @@ -1,4 +1,4 @@ -# RUN: lld -flavor darwin -arch x86_64 %s %p/Inputs/write-final-sections.yaml \ +# RUN: ld64.lld -arch x86_64 %s %p/Inputs/write-final-sections.yaml \ # RUN: -o %t -e _foo # RUN: llvm-readobj -sections -section-data %t | FileCheck %s diff --git a/test/mach-o/wrong-arch-error.yaml b/test/mach-o/wrong-arch-error.yaml index 3b8ef0dc7ee6..d518c2943842 100644 --- a/test/mach-o/wrong-arch-error.yaml +++ b/test/mach-o/wrong-arch-error.yaml @@ -1,4 +1,4 @@ -# RUN: not lld -flavor darwin -arch x86_64 -r %s \ +# RUN: not ld64.lld -arch x86_64 -r %s \ # RUN: %p/Inputs/wrong-arch-error.yaml 2> %t.err # RUN: FileCheck %s < %t.err diff --git a/test/wasm/Inputs/archive1.ll b/test/wasm/Inputs/archive1.ll index c942fa2c1b55..7f614795aa0c 100644 --- a/test/wasm/Inputs/archive1.ll +++ b/test/wasm/Inputs/archive1.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + declare i32 @bar() local_unnamed_addr #1 define i32 @foo() local_unnamed_addr #0 { diff --git a/test/wasm/Inputs/archive2.ll b/test/wasm/Inputs/archive2.ll index 35534dc9e076..66bfeac5ac6c 100644 --- a/test/wasm/Inputs/archive2.ll +++ b/test/wasm/Inputs/archive2.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + declare i32 @foo() local_unnamed_addr #1 define i32 @bar() local_unnamed_addr #0 { @@ -5,3 +7,8 @@ entry: %call = tail call i32 @foo() #2 ret i32 %call } + +define void @archive2_symbol() local_unnamed_addr #0 { +entry: + ret void +} diff --git a/test/wasm/Inputs/archive3.ll b/test/wasm/Inputs/archive3.ll new file mode 100644 index 000000000000..8c78a464f490 --- /dev/null +++ b/test/wasm/Inputs/archive3.ll @@ -0,0 +1,11 @@ +target triple = "wasm32-unknown-unknown" + +define i32 @bar() local_unnamed_addr #0 { +entry: + ret i32 1 +} + +define void @archive3_symbol() local_unnamed_addr #0 { +entry: + ret void +} diff --git a/test/wasm/Inputs/call-indirect.ll b/test/wasm/Inputs/call-indirect.ll index 388ea60c3a07..6afcf30c2515 100644 --- a/test/wasm/Inputs/call-indirect.ll +++ b/test/wasm/Inputs/call-indirect.ll @@ -1,17 +1,20 @@ -@indirect_bar = internal local_unnamed_addr global i32 ()* @bar, align 4 +target triple = "wasm32-unknown-unknown" + +@indirect_bar = internal local_unnamed_addr global i64 ()* @bar, align 4 @indirect_foo = internal local_unnamed_addr global i32 ()* @foo, align 4 declare i32 @foo() local_unnamed_addr -define i32 @bar() { +define i64 @bar() { entry: - ret i32 1 + ret i64 1 } define void @call_bar_indirect() local_unnamed_addr #1 { entry: - %0 = load i32 ()*, i32 ()** @indirect_bar, align 4 + %0 = load i64 ()*, i64 ()** @indirect_bar, align 4 %1 = load i32 ()*, i32 ()** @indirect_foo, align 4 - %call = tail call i32 %0() #2 + %call0 = tail call i64 %0() #2 + %call1 = tail call i32 %1() #2 ret void } diff --git a/test/wasm/Inputs/comdat1.ll b/test/wasm/Inputs/comdat1.ll new file mode 100644 index 000000000000..12678b0eeff7 --- /dev/null +++ b/test/wasm/Inputs/comdat1.ll @@ -0,0 +1,13 @@ +target triple = "wasm32-unknown-unknown" + +$inlineFn = comdat any +@constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn) +define linkonce_odr i32 @inlineFn() comdat { +entry: + ret i32 ptrtoint ([3 x i8]* @constantData to i32) +} + +define i32 @callInline1() { +entry: + ret i32 ptrtoint (i32 ()* @inlineFn to i32) +} diff --git a/test/wasm/Inputs/comdat2.ll b/test/wasm/Inputs/comdat2.ll new file mode 100644 index 000000000000..d910e1afcdfc --- /dev/null +++ b/test/wasm/Inputs/comdat2.ll @@ -0,0 +1,13 @@ +target triple = "wasm32-unknown-unknown" + +$inlineFn = comdat any +@constantData = weak_odr constant [3 x i8] c"abc", comdat($inlineFn) +define linkonce_odr i32 @inlineFn() comdat { +entry: + ret i32 ptrtoint ([3 x i8]* @constantData to i32) +} + +define i32 @callInline2() { +entry: + ret i32 ptrtoint (i32 ()* @inlineFn to i32) +} diff --git a/test/wasm/Inputs/custom.ll b/test/wasm/Inputs/custom.ll new file mode 100644 index 000000000000..30b4ef00bc4c --- /dev/null +++ b/test/wasm/Inputs/custom.ll @@ -0,0 +1,6 @@ +target triple = "wasm32-unknown-unknown" + +!0 = !{ !"red", !"foo" } +!1 = !{ !"green", !"bar" } +!2 = !{ !"green", !"qux" } +!wasm.custom_sections = !{ !0, !1, !2 } diff --git a/test/wasm/Inputs/debuginfo1.ll b/test/wasm/Inputs/debuginfo1.ll new file mode 100644 index 000000000000..7f37fd4fccb8 --- /dev/null +++ b/test/wasm/Inputs/debuginfo1.ll @@ -0,0 +1,68 @@ +; ModuleID = 'hi.c' +source_filename = "hi.c" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; // hi.c: +; extern void foo(int); +; +; int test(int t) { +; return t * t; +; } +; +; int _start() { +; foo(test(10)); +; return 0; +; } + +; Function Attrs: nounwind readnone +define hidden i32 @test(i32 %t) local_unnamed_addr #0 !dbg !7 { +entry: + call void @llvm.dbg.value(metadata i32 %t, metadata !12, metadata !DIExpression()), !dbg !13 + %mul = mul nsw i32 %t, %t, !dbg !14 + ret i32 %mul, !dbg !15 +} + +; Function Attrs: nounwind +define hidden i32 @_start() local_unnamed_addr #1 !dbg !16 { +entry: + tail call void @foo(i32 100) #4, !dbg !19 + ret i32 0, !dbg !20 +} + +declare void @foo(i32) local_unnamed_addr #2 + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #3 + +attributes #0 = { nounwind readnone "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { nounwind readnone speculatable } +attributes #4 = { nounwind } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 331321)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "hi.c", directory: "/Users/yury/llvmwasm") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 7.0.0 (trunk 331321)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !11) +!8 = !DISubroutineType(types: !9) +!9 = !{!10, !10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !{!12} +!12 = !DILocalVariable(name: "t", arg: 1, scope: !7, file: !1, line: 3, type: !10) +!13 = !DILocation(line: 3, column: 14, scope: !7) +!14 = !DILocation(line: 4, column: 12, scope: !7) +!15 = !DILocation(line: 4, column: 3, scope: !7) +!16 = distinct !DISubprogram(name: "_start", scope: !1, file: !1, line: 7, type: !17, isLocal: false, isDefinition: true, scopeLine: 7, isOptimized: true, unit: !0, retainedNodes: !2) +!17 = !DISubroutineType(types: !18) +!18 = !{!10} +!19 = !DILocation(line: 8, column: 3, scope: !16) +!20 = !DILocation(line: 9, column: 3, scope: !16) diff --git a/test/wasm/Inputs/debuginfo2.ll b/test/wasm/Inputs/debuginfo2.ll new file mode 100644 index 000000000000..72f94e0407c1 --- /dev/null +++ b/test/wasm/Inputs/debuginfo2.ll @@ -0,0 +1,70 @@ +; ModuleID = 'hi_foo.c' +source_filename = "hi_foo.c" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +; // hi_foo.c: +; int y[2] = {23, 41}; +; +; void foo(int p) { +; y[p & 1]++; +; } +; +; // Will be GCed, but remain visible in debug info +; int z[2] = {1, 2}; + +@y = hidden local_unnamed_addr global [2 x i32] [i32 23, i32 41], align 4, !dbg !0 +@z = hidden local_unnamed_addr global [2 x i32] [i32 1, i32 2], align 4, !dbg !6 + +; Function Attrs: nounwind +define hidden void @foo(i32 %p) local_unnamed_addr #0 !dbg !16 { +entry: + call void @llvm.dbg.value(metadata i32 %p, metadata !20, metadata !DIExpression()), !dbg !21 + %and = and i32 %p, 1, !dbg !22 + %arrayidx = getelementptr inbounds [2 x i32], [2 x i32]* @y, i32 0, i32 %and, !dbg !23 + %0 = load i32, i32* %arrayidx, align 4, !dbg !24, !tbaa !25 + %inc = add nsw i32 %0, 1, !dbg !24 + store i32 %inc, i32* %arrayidx, align 4, !dbg !24, !tbaa !25 + ret void, !dbg !29 +} + +; Function Attrs: nounwind readnone speculatable +declare void @llvm.dbg.value(metadata, metadata, metadata) #1 + +attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="generic" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind readnone speculatable } + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!12, !13, !14} +!llvm.ident = !{!15} + +!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) +!1 = distinct !DIGlobalVariable(name: "y", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true) +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 7.0.0 (trunk 332913) (llvm/trunk 332919)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) +!3 = !DIFile(filename: "hi_foo.c", directory: "/usr/local/google/home/sbc/dev/wasm/llvm-build") +!4 = !{} +!5 = !{!0, !6} +!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) +!7 = distinct !DIGlobalVariable(name: "z", scope: !2, file: !3, line: 8, type: !8, isLocal: false, isDefinition: true) +!8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 64, elements: !10) +!9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!10 = !{!11} +!11 = !DISubrange(count: 2) +!12 = !{i32 2, !"Dwarf Version", i32 4} +!13 = !{i32 2, !"Debug Info Version", i32 3} +!14 = !{i32 1, !"wchar_size", i32 4} +!15 = !{!"clang version 7.0.0 (trunk 332913) (llvm/trunk 332919)"} +!16 = distinct !DISubprogram(name: "foo", scope: !3, file: !3, line: 3, type: !17, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !2, retainedNodes: !19) +!17 = !DISubroutineType(types: !18) +!18 = !{null, !9} +!19 = !{!20} +!20 = !DILocalVariable(name: "p", arg: 1, scope: !16, file: !3, line: 3, type: !9) +!21 = !DILocation(line: 3, column: 14, scope: !16) +!22 = !DILocation(line: 4, column: 7, scope: !16) +!23 = !DILocation(line: 4, column: 3, scope: !16) +!24 = !DILocation(line: 4, column: 11, scope: !16) +!25 = !{!26, !26, i64 0} +!26 = !{!"int", !27, i64 0} +!27 = !{!"omnipotent char", !28, i64 0} +!28 = !{!"Simple C/C++ TBAA"} +!29 = !DILocation(line: 5, column: 1, scope: !16) diff --git a/test/wasm/Inputs/global-ctor-dtor.ll b/test/wasm/Inputs/global-ctor-dtor.ll index 5cacd7e433ab..5e73f06b0c02 100644 --- a/test/wasm/Inputs/global-ctor-dtor.ll +++ b/test/wasm/Inputs/global-ctor-dtor.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + define hidden void @myctor() { entry: ret void @@ -9,6 +11,14 @@ entry: ret void } -@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @myctor, i8* null }] +@llvm.global_ctors = appending global [3 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 2002, void ()* @myctor, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @myctor, i8* null }, + { i32, void ()*, i8* } { i32 202, void ()* @myctor, i8* null } +] -@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @mydtor, i8* null }] +@llvm.global_dtors = appending global [3 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 2002, void ()* @mydtor, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @mydtor, i8* null }, + { i32, void ()*, i8* } { i32 202, void ()* @mydtor, i8* null } +] diff --git a/test/wasm/Inputs/globals.yaml b/test/wasm/Inputs/globals.yaml new file mode 100644 index 000000000000..c08a3044ec95 --- /dev/null +++ b/test/wasm/Inputs/globals.yaml @@ -0,0 +1,54 @@ +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ReturnType: I64 + ParamTypes: + - Type: FUNCTION + FunctionTypes: [ 0 ] + - Type: GLOBAL + Globals: + - Index: 0 + Type: I64 + Mutable: true + InitExpr: + Opcode: I64_CONST + Value: 123 + - Index: 1 + Type: I64 + Mutable: true + InitExpr: + Opcode: I64_CONST + Value: 456 + - Type: CODE + Functions: + - Index: 0 + Locals: + Body: 2381808080000B + Relocations: + - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB + Index: 1 + Offset: 0x00000004 + - Type: CUSTOM + Name: linking + Version: 1 + SymbolTable: + - Index: 0 + Kind: GLOBAL + Name: unused_global + Flags: [ VISIBILITY_HIDDEN ] + Global: 0 + - Index: 1 + Kind: GLOBAL + Name: used_global + Flags: [ VISIBILITY_HIDDEN ] + Global: 1 + - Index: 2 + Kind: FUNCTION + Name: use_global + Flags: [ VISIBILITY_HIDDEN ] + Function: 0 +... diff --git a/test/wasm/Inputs/hello.ll b/test/wasm/Inputs/hello.ll index 93df0f559809..675566861cc7 100644 --- a/test/wasm/Inputs/hello.ll +++ b/test/wasm/Inputs/hello.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + ; Wasm module generated from the following C code: ; void puts(const char*); ; void hello() { puts("hello\n"); } diff --git a/test/wasm/Inputs/hidden.ll b/test/wasm/Inputs/hidden.ll index 25890e9f03f2..4af16b3b99ed 100644 --- a/test/wasm/Inputs/hidden.ll +++ b/test/wasm/Inputs/hidden.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + ; Function Attrs: norecurse nounwind readnone define hidden i32 @archiveHidden() #0 { entry: diff --git a/test/wasm/Inputs/locals-duplicate1.ll b/test/wasm/Inputs/locals-duplicate1.ll new file mode 100644 index 000000000000..f118dd4bd679 --- /dev/null +++ b/test/wasm/Inputs/locals-duplicate1.ll @@ -0,0 +1,51 @@ +target triple = "wasm32-unknown-unknown" + +; Will collide: local (internal linkage) with global (external) linkage +@colliding_global1 = internal default global i32 0, align 4 +; Will collide: global with local +@colliding_global2 = default global i32 0, align 4 +; Will collide: local with local +@colliding_global3 = internal default global i32 0, align 4 + +; Will collide: local with global +define internal i32 @colliding_func1() { +entry: + ret i32 2 +} +; Will collide: global with local +define i32 @colliding_func2() { +entry: + ret i32 2 +} +; Will collide: local with local +define internal i32 @colliding_func3() { +entry: + ret i32 2 +} + + +define i32* @get_global1A() { +entry: + ret i32* @colliding_global1 +} +define i32* @get_global2A() { +entry: + ret i32* @colliding_global2 +} +define i32* @get_global3A() { +entry: + ret i32* @colliding_global3 +} + +define i32 ()* @get_func1A() { +entry: + ret i32 ()* @colliding_func1 +} +define i32 ()* @get_func2A() { +entry: + ret i32 ()* @colliding_func2 +} +define i32 ()* @get_func3A() { +entry: + ret i32 ()* @colliding_func3 +} diff --git a/test/wasm/Inputs/locals-duplicate2.ll b/test/wasm/Inputs/locals-duplicate2.ll new file mode 100644 index 000000000000..617abfea0cdc --- /dev/null +++ b/test/wasm/Inputs/locals-duplicate2.ll @@ -0,0 +1,51 @@ +target triple = "wasm32-unknown-unknown" + +; Will collide: local (internal linkage) with global (external) linkage +@colliding_global1 = default global i32 0, align 4 +; Will collide: global with local +@colliding_global2 = internal default global i32 0, align 4 +; Will collide: local with local +@colliding_global3 = internal default global i32 0, align 4 + +; Will collide: local with global +define i32 @colliding_func1() { +entry: + ret i32 2 +} +; Will collide: global with local +define internal i32 @colliding_func2() { +entry: + ret i32 2 +} +; Will collide: local with local +define internal i32 @colliding_func3() { +entry: + ret i32 2 +} + + +define i32* @get_global1B() { +entry: + ret i32* @colliding_global1 +} +define i32* @get_global2B() { +entry: + ret i32* @colliding_global2 +} +define i32* @get_global3B() { +entry: + ret i32* @colliding_global3 +} + +define i32 ()* @get_func1B() { +entry: + ret i32 ()* @colliding_func1 +} +define i32 ()* @get_func2B() { +entry: + ret i32 ()* @colliding_func2 +} +define i32 ()* @get_func3B() { +entry: + ret i32 ()* @colliding_func3 +} diff --git a/test/wasm/Inputs/many-funcs.ll b/test/wasm/Inputs/many-funcs.ll index b8daab23638d..1829d7d6b488 100644 --- a/test/wasm/Inputs/many-funcs.ll +++ b/test/wasm/Inputs/many-funcs.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + @g0 = global i32 1, align 4 @foo = global i32 1, align 4 diff --git a/test/wasm/Inputs/ret32.ll b/test/wasm/Inputs/ret32.ll index a4565288f08b..674b34b66499 100644 --- a/test/wasm/Inputs/ret32.ll +++ b/test/wasm/Inputs/ret32.ll @@ -1,6 +1,6 @@ -; Function Attrs: norecurse nounwind readnone -define i32 @ret32(float %arg) #0 { +target triple = "wasm32-unknown-unknown" + +define hidden i32 @ret32(float %arg) { entry: ret i32 0 - ; ptrtoint (i32 (float)* @ret32 to i32) } diff --git a/test/wasm/Inputs/ret64.ll b/test/wasm/Inputs/ret64.ll index 6a9de0dace1d..c1dd5e55fee0 100644 --- a/test/wasm/Inputs/ret64.ll +++ b/test/wasm/Inputs/ret64.ll @@ -1,4 +1,6 @@ -define i64 @ret64(double %arg) local_unnamed_addr #0 { +target triple = "wasm32-unknown-unknown" + +define hidden i64 @ret64(double %arg) { entry: ret i64 1 } diff --git a/test/wasm/Inputs/start.ll b/test/wasm/Inputs/start.ll new file mode 100644 index 000000000000..e2629659bf50 --- /dev/null +++ b/test/wasm/Inputs/start.ll @@ -0,0 +1,6 @@ +target triple = "wasm32-unknown-unknown" + +define void @_start() local_unnamed_addr { +entry: + ret void +} diff --git a/test/wasm/Inputs/strong-symbol.ll b/test/wasm/Inputs/strong-symbol.ll new file mode 100644 index 000000000000..cc2aa8ab5d26 --- /dev/null +++ b/test/wasm/Inputs/strong-symbol.ll @@ -0,0 +1,6 @@ +target triple = "wasm32-unknown-unknown" + +define i64 @weakFn() #0 { +entry: + ret i64 1 +} diff --git a/test/wasm/Inputs/undefined-globals.yaml b/test/wasm/Inputs/undefined-globals.yaml new file mode 100644 index 000000000000..440a538d6587 --- /dev/null +++ b/test/wasm/Inputs/undefined-globals.yaml @@ -0,0 +1,52 @@ +--- !WASM +FileHeader: + Version: 0x00000001 +Sections: + - Type: TYPE + Signatures: + - Index: 0 + ReturnType: I64 + ParamTypes: + - Type: IMPORT + Imports: + - Module: env + Field: unused_undef_global + Kind: GLOBAL + GlobalType: I64 + GlobalMutable: true + - Module: env + Field: used_undef_global + Kind: GLOBAL + GlobalType: I64 + GlobalMutable: true + - Type: FUNCTION + FunctionTypes: [ 0 ] + - Type: CODE + Functions: + - Index: 0 + Locals: + Body: 2381808080000B + Relocations: + - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB + Index: 1 + Offset: 0x00000004 + - Type: CUSTOM + Name: linking + Version: 1 + SymbolTable: + - Index: 0 + Kind: GLOBAL + Name: unused_undef_global + Flags: [ VISIBILITY_HIDDEN, UNDEFINED ] + Global: 0 + - Index: 1 + Kind: GLOBAL + Name: used_undef_global + Flags: [ VISIBILITY_HIDDEN, UNDEFINED ] + Global: 1 + - Index: 2 + Kind: FUNCTION + Name: use_undef_global + Flags: [ VISIBILITY_HIDDEN ] + Function: 0 +... diff --git a/test/wasm/Inputs/weak-alias.ll b/test/wasm/Inputs/weak-alias.ll index b911b35529c5..1840ffd1fc54 100644 --- a/test/wasm/Inputs/weak-alias.ll +++ b/test/wasm/Inputs/weak-alias.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + ; Function Attrs: norecurse nounwind readnone define i32 @direct_fn() #0 { entry: diff --git a/test/wasm/Inputs/weak-symbol1.ll b/test/wasm/Inputs/weak-symbol1.ll index 61e7e5818c54..6e394ff91d0c 100644 --- a/test/wasm/Inputs/weak-symbol1.ll +++ b/test/wasm/Inputs/weak-symbol1.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + define weak i32 @weakFn() #0 { entry: ret i32 1 diff --git a/test/wasm/Inputs/weak-symbol2.ll b/test/wasm/Inputs/weak-symbol2.ll index 9e2e270f8693..e9c30c18f7de 100644 --- a/test/wasm/Inputs/weak-symbol2.ll +++ b/test/wasm/Inputs/weak-symbol2.ll @@ -1,3 +1,5 @@ +target triple = "wasm32-unknown-unknown" + define weak i32 @weakFn() #0 { entry: ret i32 2 diff --git a/test/wasm/alias.ll b/test/wasm/alias.ll new file mode 100644 index 000000000000..f88452e538c4 --- /dev/null +++ b/test/wasm/alias.ll @@ -0,0 +1,88 @@ +; RUN: llc -filetype=obj -o %t.o %s +; RUN: wasm-ld %t.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +@start_alias = alias void (), void ()* @_start + +; Function Attrs: nounwind uwtable +define void @_start() local_unnamed_addr #1 { +entry: + ret void +} + +; CHECK: --- !WASM +; CHECK-NEXT: FileHeader: +; CHECK-NEXT: Version: 0x00000001 +; CHECK-NEXT: Sections: +; CHECK-NEXT: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Type: FUNCTION +; CHECK-NEXT: FunctionTypes: [ 0, 0 ] +; CHECK-NEXT: - Type: TABLE +; CHECK-NEXT: Tables: +; CHECK-NEXT: - ElemType: ANYFUNC +; CHECK-NEXT: Limits: +; CHECK-NEXT: Flags: [ HAS_MAX ] +; CHECK-NEXT: Initial: 0x00000001 +; CHECK-NEXT: Maximum: 0x00000001 +; CHECK-NEXT: - Type: MEMORY +; CHECK-NEXT: Memories: +; CHECK-NEXT: - Initial: 0x00000002 +; CHECK-NEXT: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: start_alias +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: ... diff --git a/test/wasm/archive.ll b/test/wasm/archive.ll index a43e460d69f2..50f72d627386 100644 --- a/test/wasm/archive.ll +++ b/test/wasm/archive.ll @@ -1,31 +1,51 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/archive1.ll -o %t.a1.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/archive2.ll -o %t.a2.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/hello.ll -o %t.a3.o -; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o -; RUN: lld -flavor wasm %t.a %t.o -o %t.wasm +; RUN: llc -filetype=obj %s -o %t.o +; RUN: llc -filetype=obj %S/Inputs/archive1.ll -o %t.a1.o +; RUN: llc -filetype=obj %S/Inputs/archive2.ll -o %t.a2.o +; RUN: llc -filetype=obj %S/Inputs/archive3.ll -o %t.a3.o +; RUN: llc -filetype=obj %S/Inputs/hello.ll -o %t.hello.o +; RUN: llvm-ar rcs %t.a %t.a1.o %t.a2.o %t.a3.o %t.hello.o +; RUN: rm -f %t.imports +; RUN: not wasm-ld %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED %s + +; CHECK-UNDEFINED: undefined symbol: missing_func + +; RUN: echo 'missing_func' > %t.imports +; RUN: wasm-ld -r %t.a %t.o -o %t.wasm + ; RUN: llvm-nm -a %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + declare i32 @foo() local_unnamed_addr #1 +declare i32 @missing_func() local_unnamed_addr #1 -define i32 @_start() local_unnamed_addr #0 { +define void @_start() local_unnamed_addr #0 { entry: - %call = tail call i32 @foo() #2 - ret i32 %call + %call1 = call i32 @foo() #2 + %call2 = call i32 @missing_func() #2 + ret void } -; Verify that multually dependant object files in an archive is handled -; correctly. +; Verify that mutually dependant object files in an archive is handled +; correctly. Since we're using llvm-nm, we must link with --relocatable. +; +; TODO(ncw): Update LLD so that the symbol table is written out for +; non-relocatable output (with an option to strip it) -; CHECK: 00000002 T _start -; CHECK-NEXT: 00000002 T _start -; CHECK-NEXT: 00000000 T bar -; CHECK-NEXT: 00000000 T bar -; CHECK-NEXT: 00000001 T foo -; CHECK-NEXT: 00000001 T foo +; CHECK: 00000004 T _start +; CHECK-NEXT: 00000002 T archive2_symbol +; CHECK-NEXT: 00000001 T bar +; CHECK-NEXT: 00000003 T foo +; CHECK-NEXT: U missing_func ; Verify that symbols from unused objects don't appear in the symbol table ; CHECK-NOT: hello ; Specifying the same archive twice is allowed. -; RUN: lld -flavor wasm %t.a %t.a %t.o -o %t.wasm +; RUN: wasm-ld %t.a %t.a %t.o -o %t.wasm + +; Verfiy errors include library name +; RUN: not wasm-ld -u archive2_symbol -u archive3_symbol %t.a %t.o -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-DUP %s +; CHECK-DUP: error: duplicate symbol: bar +; CHECK-DUP: >>> defined in {{.*}}.a({{.*}}.a2.o) +; CHECK-DUP: >>> defined in {{.*}}.a({{.*}}.a3.o) diff --git a/test/wasm/call-indirect.ll b/test/wasm/call-indirect.ll index 2b838a8efa4d..63a6def87382 100644 --- a/test/wasm/call-indirect.ll +++ b/test/wasm/call-indirect.ll @@ -1,6 +1,6 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/call-indirect.ll -o %t2.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -o %t.wasm %t2.o %t.o +; RUN: llc -filetype=obj %p/Inputs/call-indirect.ll -o %t2.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t2.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s ; bitcode generated from the following C code: @@ -8,6 +8,8 @@ ; int (*indirect_func)(void) = &foo; ; void _start(void) { indirect_func(); } +target triple = "wasm32-unknown-unknown" + @indirect_func = local_unnamed_addr global i32 ()* @foo, align 4 ; Function Attrs: norecurse nounwind readnone @@ -17,11 +19,11 @@ entry: } ; Function Attrs: nounwind -define i32 @_start() local_unnamed_addr #1 { +define void @_start() local_unnamed_addr #1 { entry: %0 = load i32 ()*, i32 ()** @indirect_func, align 4 %call = call i32 %0() #2 - ret i32 0 + ret void } ; Indirect function call where no function actually has this type. @@ -38,21 +40,24 @@ define void @call_ptr(i64 (i64)* %arg) { ; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ReturnType: I64 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: ReturnType: NORESULT -; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - I32 -; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: ReturnType: I64 -; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - I64 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 2 ] +; CHECK-NEXT: FunctionTypes: [ 3, 0, 3, 1, 3, 4 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -65,49 +70,87 @@ define void @call_ptr(i64 (i64)* %arg) { ; CHECK-NEXT: - Initial: 0x00000002 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1036 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1032 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 -; CHECK-NEXT: - Name: foo -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Index: 4 ; CHECK-NEXT: - Name: bar ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: call_bar_indirect ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: foo +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: indirect_func +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: call_ptr ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 4 +; CHECK-NEXT: Index: 5 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 0, 2 ] +; CHECK-NEXT: Functions: [ 1, 3 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41010B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 410028028088808000118080808000001A0B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 42010B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: Count: 1 +; CHECK-NEXT: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41020B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 410028028888808000118080808000001A41000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 42012000118380808000001A0B +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 410028028888808000118180808000001A0B +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 42012000118280808000001A0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 @@ -117,16 +160,18 @@ define void @call_ptr(i64 (i64)* %arg) { ; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: Content: '010000000200000002000000' ; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 12 -; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: bar +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: call_bar_indirect +; CHECK-NEXT: Name: bar ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: foo +; CHECK-NEXT: Name: call_bar_indirect ; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: foo +; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: call_ptr +; CHECK-NEXT: ... diff --git a/test/wasm/comdats.ll b/test/wasm/comdats.ll new file mode 100644 index 000000000000..d0bec4cda146 --- /dev/null +++ b/test/wasm/comdats.ll @@ -0,0 +1,99 @@ +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat1.ll -o %t1.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %p/Inputs/comdat2.ll -o %t2.o +; RUN: llc -filetype=obj -mtriple=wasm32-unknown-uknown-wasm %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.o %t1.o %t2.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +declare i32 @inlineFn() + +define void @_start() local_unnamed_addr { +entry: + %call = call i32 @inlineFn() + ret void +} + +; CHECK: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1027 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: inlineFn +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: constantData +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: callInline1 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: callInline2 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 2 ] +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1082808080001A0B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4180888080000B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4181808080000B +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4181808080000B +; CHECK-NEXT: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '616263' diff --git a/test/wasm/compress-relocs.ll b/test/wasm/compress-relocs.ll new file mode 100644 index 000000000000..b137d5abd43e --- /dev/null +++ b/test/wasm/compress-relocs.ll @@ -0,0 +1,22 @@ +; RUN: llc -filetype=obj %p/Inputs/call-indirect.ll -o %t2.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t2.o %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; RUN: wasm-ld -O2 -o %t-compressed.wasm %t2.o %t.o +; RUN: obj2yaml %t-compressed.wasm | FileCheck %s -check-prefix=COMPRESS + +target triple = "wasm32-unknown-unknown-wasm" + +define i32 @foo() { +entry: + ret i32 2 +} + +define void @_start() local_unnamed_addr { +entry: + ret void +} + +; CHECK: Body: 4100280284888080002100410028028088808000118080808000001A2000118180808000001A0B +; COMPRESS: Body: 41002802840821004100280280081100001A20001101001A0B diff --git a/test/wasm/conflict.test b/test/wasm/conflict.test index 41684ae51a12..9adc92ed1eda 100644 --- a/test/wasm/conflict.test +++ b/test/wasm/conflict.test @@ -1,5 +1,5 @@ -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -# RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s +# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +# RUN: not wasm-ld -o %t.wasm %t.ret32.o %t.ret32.o 2>&1 | FileCheck %s # CHECK: duplicate symbol: ret32 # CHECK-NEXT: >>> defined in {{.*}}conflict.test.tmp.ret32.o diff --git a/test/wasm/custom-sections.ll b/test/wasm/custom-sections.ll new file mode 100644 index 000000000000..c33ca2774afa --- /dev/null +++ b/test/wasm/custom-sections.ll @@ -0,0 +1,22 @@ +; RUN: llc -filetype=obj %s -o %t1.o +; RUN: llc -filetype=obj %S/Inputs/custom.ll -o %t2.o +; RUN: wasm-ld --relocatable -o %t.wasm %t1.o %t2.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +define i32 @_start() local_unnamed_addr { +entry: + %retval = alloca i32, align 4 + ret i32 0 +} + +!0 = !{ !"red", !"extra" } +!wasm.custom_sections = !{ !0 } + +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: green +; CHECK-NEXT: Payload: '626172717578' +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: red +; CHECK-NEXT: Payload: 6578747261666F6F diff --git a/test/wasm/cxx-mangling.ll b/test/wasm/cxx-mangling.ll new file mode 100644 index 000000000000..67f3594e8166 --- /dev/null +++ b/test/wasm/cxx-mangling.ll @@ -0,0 +1,66 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld --demangle -o %t_demangle.wasm %t.o +; RUN: obj2yaml %t_demangle.wasm | FileCheck %s +; RUN: wasm-ld --no-demangle -o %t_nodemangle.wasm %t.o +; RUN: obj2yaml %t_nodemangle.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +; Check that the EXPORT name is still mangled, but that the "name" custom +; section contains the unmangled name. + +define void @_Z3fooi(i32 %arg) { + ret void +} + +declare extern_weak void @_Z3bari(i32 %arg) + +define void @_start() { + call void @_Z3fooi(i32 1) + call void @_Z3bari(i32 1) + ret void +} + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: _Z3fooi +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 000B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 410110828080800041011081808080000B +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: 'undefined function bar(int)' +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: 'foo(int)' +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: ... diff --git a/test/wasm/data-layout.ll b/test/wasm/data-layout.ll index 2300b362a55f..5fd3f2d7791c 100644 --- a/test/wasm/data-layout.ll +++ b/test/wasm/data-layout.ll @@ -1,7 +1,7 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/hello.ll -o %t.hello.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm --emit-relocs --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o -; RUN: obj2yaml %t.wasm | FileCheck %s +; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o +; RUN: llc -filetype=obj %s -o %t.o + +target triple = "wasm32-unknown-unknown" @foo = hidden global i32 1, align 4 @aligned_bar = hidden global i32 3, align 16 @@ -9,53 +9,138 @@ @hello_str = external global i8* @external_ref = global i8** @hello_str, align 8 -; CHECK: - Type: GLOBAL +%struct.s = type { i32, i32 } +@local_struct = hidden global %struct.s zeroinitializer, align 4 +@local_struct_internal_ptr = hidden local_unnamed_addr global i32* getelementptr inbounds (%struct.s, %struct.s* @local_struct, i32 0, i32 1), align 4 + +; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry -o %t.wasm %t.o %t.hello.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; CHECK: - Type: MEMORY +; CHECK-NEXT: Memories: +; CHECK-NEXT: - Initial: 0x00000002 +; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66608 -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: false -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1024 -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: false -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1040 -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: false ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1048 -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: false -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1052 +; CHECK-NEXT: Value: 66608 -; CHECK: - Type: DATA -; CHECK-NEXT: Relocations: -; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 -; CHECK-NEXT: Index: 4 -; CHECK-NEXT: Offset: 0x0000001F +; CHECK: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 ; CHECK-NEXT: MemoryIndex: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1024 -; CHECK-NEXT: Content: 0100000000000000000000000000000003000000000000001C040000 -; CHECK-NEXT: - SectionOffset: 41 +; CHECK-NEXT: Content: '0100000000000000000000000000000003000000000000002804000024040000' +; CHECK-NEXT: - SectionOffset: 45 ; CHECK-NEXT: MemoryIndex: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1052 +; CHECK-NEXT: Value: 1056 +; CHECK-NEXT: Content: '0000000000000000' +; CHECK-NEXT: - SectionOffset: 59 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1064 ; CHECK-NEXT: Content: 68656C6C6F0A00 +; CHECK-NEXT: - Type: CUSTOM + + +; RUN: wasm-ld -no-gc-sections --allow-undefined --no-entry \ +; RUN: --initial-memory=131072 --max-memory=131072 -o %t_max.wasm %t.o \ +; RUN: %t.hello.o +; RUN: obj2yaml %t_max.wasm | FileCheck %s -check-prefix=CHECK-MAX + +; CHECK-MAX: - Type: MEMORY +; CHECK-MAX-NEXT: Memories: +; CHECK-MAX-NEXT: - Flags: [ HAS_MAX ] +; CHECK-MAX-NEXT: Initial: 0x00000002 +; CHECK-MAX-NEXT: Maximum: 0x00000002 + + +; RUN: wasm-ld --relocatable -o %t_reloc.wasm %t.o %t.hello.o +; RUN: obj2yaml %t_reloc.wasm | FileCheck %s -check-prefix=RELOC + +; RELOC: - Type: DATA +; RELOC-NEXT: Relocations: +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x00000018 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 +; RELOC-NEXT: Index: 3 +; RELOC-NEXT: Offset: 0x0000002E +; RELOC-NEXT: Addend: 4 +; RELOC-NEXT: Segments: +; RELOC-NEXT: - SectionOffset: 6 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 0 +; RELOC-NEXT: Content: '01000000' +; RELOC-NEXT: - SectionOffset: 15 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 16 +; RELOC-NEXT: Content: '03000000' +; RELOC-NEXT: - SectionOffset: 24 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 24 +; RELOC-NEXT: Content: '28000000' +; RELOC-NEXT: - SectionOffset: 33 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 28 +; RELOC-NEXT: Content: '0000000000000000' +; RELOC-NEXT: - SectionOffset: 46 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 36 +; RELOC-NEXT: Content: '20000000' +; RELOC-NEXT: - SectionOffset: 55 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 40 +; RELOC-NEXT: Content: 68656C6C6F0A00 -; CHECK: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 35 +; RELOC: SymbolTable: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: foo +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Segment: 0 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: aligned_bar +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Segment: 1 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: external_ref +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Segment: 2 +; RELOC-NEXT: Size: 4 +; RELOC: - Index: 6 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: hello_str +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Segment: 5 +; RELOC-NEXT: Size: 7 diff --git a/test/wasm/data-segment-merging.ll b/test/wasm/data-segment-merging.ll new file mode 100644 index 000000000000..d0df84d0fc23 --- /dev/null +++ b/test/wasm/data-segment-merging.ll @@ -0,0 +1,48 @@ +target triple = "wasm32-unknown-unknown" + +@a = hidden global [6 x i8] c"hello\00", align 1 +@b = hidden global [8 x i8] c"goodbye\00", align 1 +@c = hidden global [9 x i8] c"whatever\00", align 1 +@d = hidden global i32 42, align 4 + +; RUN: llc -filetype=obj %s -o %t.data-segment-merging.o + +; RUN: wasm-ld -no-gc-sections --no-entry -o %t.merged.wasm %t.data-segment-merging.o +; RUN: obj2yaml %t.merged.wasm | FileCheck %s --check-prefix=MERGE +; MERGE: - Type: DATA +; MERGE-NEXT: Segments: +; MERGE-NEXT: - SectionOffset: 7 +; MERGE-NEXT: MemoryIndex: 0 +; MERGE-NEXT: Offset: +; MERGE-NEXT: Opcode: I32_CONST +; MERGE-NEXT: Value: 1024 +; MERGE-NEXT: Content: 68656C6C6F00676F6F6462796500776861746576657200002A000000 + +; RUN: wasm-ld -no-gc-sections --no-entry --no-merge-data-segments -o %t.separate.wasm %t.data-segment-merging.o +; RUN: obj2yaml %t.separate.wasm | FileCheck %s --check-prefix=SEPARATE +; SEPARATE: - Type: DATA +; SEPARATE-NEXT: Segments: +; SEPARATE-NEXT: - SectionOffset: 7 +; SEPARATE-NEXT: MemoryIndex: 0 +; SEPARATE-NEXT: Offset: +; SEPARATE-NEXT: Opcode: I32_CONST +; SEPARATE-NEXT: Value: 1024 +; SEPARATE-NEXT: Content: 68656C6C6F00 +; SEPARATE-NEXT: - SectionOffset: 19 +; SEPARATE-NEXT: MemoryIndex: 0 +; SEPARATE-NEXT: Offset: +; SEPARATE-NEXT: Opcode: I32_CONST +; SEPARATE-NEXT: Value: 1030 +; SEPARATE-NEXT: Content: 676F6F6462796500 +; SEPARATE-NEXT: - SectionOffset: 33 +; SEPARATE-NEXT: MemoryIndex: 0 +; SEPARATE-NEXT: Offset: +; SEPARATE-NEXT: Opcode: I32_CONST +; SEPARATE-NEXT: Value: 1038 +; SEPARATE-NEXT: Content: '776861746576657200' +; SEPARATE-NEXT: - SectionOffset: 48 +; SEPARATE-NEXT: MemoryIndex: 0 +; SEPARATE-NEXT: Offset: +; SEPARATE-NEXT: Opcode: I32_CONST +; SEPARATE-NEXT: Value: 1048 +; SEPARATE-NEXT: Content: 2A000000 diff --git a/test/wasm/debuginfo.test b/test/wasm/debuginfo.test new file mode 100644 index 000000000000..ce68a03bcbce --- /dev/null +++ b/test/wasm/debuginfo.test @@ -0,0 +1,85 @@ +RUN: llc -filetype=obj %p/Inputs/debuginfo1.ll -o %t.debuginfo1.o +RUN: llc -filetype=obj %p/Inputs/debuginfo2.ll -o %t.debuginfo2.o +RUN: wasm-ld -o %t.wasm %t.debuginfo1.o %t.debuginfo2.o +RUN: llvm-dwarfdump %t.wasm | FileCheck %s + +CHECK: file format WASM + +CHECK: .debug_info contents: +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk {{.*}})") +CHECK-NEXT: DW_AT_language (DW_LANG_C99) +CHECK-NEXT: DW_AT_name ("hi.c") + +CHECK: DW_TAG_subprogram +CHECK-NEXT: DW_AT_low_pc +CHECK-NEXT: DW_AT_high_pc +CHECK-NEXT: DW_AT_name ("test") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c") +CHECK-NEXT: DW_AT_decl_line (3) +CHECK-NEXT: DW_AT_prototyped (true) + +CHECK: DW_TAG_formal_parameter +CHECK-NEXT: DW_AT_name ("t") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c") +CHECK-NEXT: DW_AT_decl_line (3) + +CHECK: DW_TAG_subprogram +CHECK-NEXT: DW_AT_low_pc +CHECK-NEXT: DW_AT_high_pc +CHECK-NEXT: DW_AT_name ("_start") +CHECK-NEXT: DW_AT_decl_file ("/Users/yury/llvmwasm{{(/|\\)}}hi.c") +CHECK-NEXT: DW_AT_decl_line (7) + +CHECK: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("int") +CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +CHECK-NEXT: DW_AT_byte_size (0x04) + +CHECK: DW_TAG_compile_unit +CHECK-NEXT: DW_AT_producer ("clang version 7.0.0 (trunk {{.*}})") +CHECK-NEXT: DW_AT_language (DW_LANG_C99) +CHECK-NEXT: DW_AT_name ("hi_foo.c") + +CHECK: DW_TAG_variable +CHECK-NEXT: DW_AT_name ("y") +CHECK-NEXT: DW_AT_type (0x00000097 "int[]") +CHECK-NEXT: DW_AT_external (true) +CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c") +CHECK-NEXT: DW_AT_decl_line (1) +CHECK: DW_AT_location (DW_OP_addr 0x400) + +CHECK: DW_TAG_array_type + +CHECK: DW_TAG_subrange_type + +CHECK: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("int") +CHECK-NEXT: DW_AT_encoding (DW_ATE_signed) +CHECK-NEXT: DW_AT_byte_size (0x04) + +CHECK: DW_TAG_base_type +CHECK-NEXT: DW_AT_name ("__ARRAY_SIZE_TYPE__") +CHECK-NEXT: DW_AT_byte_size (0x08) +CHECK-NEXT: DW_AT_encoding (DW_ATE_unsigned) + +CHECK: DW_TAG_variable +CHECK-NEXT: DW_AT_name ("z") +CHECK-NEXT: DW_AT_type (0x00000097 "int[]") +CHECK-NEXT: DW_AT_external (true) +CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c") +CHECK-NEXT: DW_AT_decl_line (8) +CHECK-NEXT: DW_AT_location (DW_OP_addr 0x0) + +CHECK: DW_TAG_subprogram +CHECK-NEXT: DW_AT_low_pc +CHECK-NEXT: DW_AT_high_pc +CHECK-NEXT: DW_AT_name ("foo") +CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c") +CHECK-NEXT: DW_AT_decl_line (3) + +CHECK: DW_TAG_formal_parameter +CHECK-NEXT: DW_AT_name ("p") +CHECK-NEXT: DW_AT_decl_file ("{{.*}}hi_foo.c") +CHECK-NEXT: DW_AT_decl_line (3) + diff --git a/test/wasm/demangle.ll b/test/wasm/demangle.ll new file mode 100644 index 000000000000..f0416bb6b32f --- /dev/null +++ b/test/wasm/demangle.ll @@ -0,0 +1,17 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: not wasm-ld --undefined _Z3fooi \ +; RUN: -o %t.wasm %t.o 2>&1 | FileCheck %s + +; CHECK: error: undefined symbol: foo(int) + +; RUN: not wasm-ld --no-demangle --undefined _Z3fooi \ +; RUN: -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-NODEMANGLE %s + +; CHECK-NODEMANGLE: error: undefined symbol: _Z3fooi + +target triple = "wasm32-unknown-unknown" + +define hidden void @_start() local_unnamed_addr { +entry: + ret void +} diff --git a/test/wasm/driver.ll b/test/wasm/driver.ll new file mode 100644 index 000000000000..22e6bc180e4a --- /dev/null +++ b/test/wasm/driver.ll @@ -0,0 +1,22 @@ +; RUN: llc -filetype=obj %s -o %t.o + +target triple = "wasm32-unknown-unknown" + +define hidden void @entry() local_unnamed_addr #0 { +entry: + ret void +} + +; RUN: not wasm-ld -o %t.exe 2>&1 | FileCheck -check-prefix=IN %s +; IN: error: no input files + +; RUN: not wasm-ld %t.o 2>&1 | FileCheck -check-prefix=OUT %s +; OUT: error: no output file specified + +; RUN: not wasm-ld 2>&1 | FileCheck -check-prefix=BOTH %s +; BOTH: error: no input files +; BOTH-NOT: error: no output file specified + +; RUN: not wasm-ld --export-table --import-table %t.o 2>&1 \ +; RUN: | FileCheck -check-prefix=TABLE %s +; TABLE: error: --import-table and --export-table may not be used together diff --git a/test/wasm/entry-signature.ll b/test/wasm/entry-signature.ll new file mode 100644 index 000000000000..8e245b14e964 --- /dev/null +++ b/test/wasm/entry-signature.ll @@ -0,0 +1,10 @@ +; Verify that the entry point signauture can be flexible. +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t1.wasm %t.o + +target triple = "wasm32-unknown-unknown-wasm" + +define hidden i32 @_start(i32, i64) local_unnamed_addr #0 { +entry: + ret i32 0 +} diff --git a/test/wasm/entry.ll b/test/wasm/entry.ll index 4749d8306651..30fff9a2bdcb 100644 --- a/test/wasm/entry.ll +++ b/test/wasm/entry.ll @@ -1,19 +1,50 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -e entry -o %t.wasm %t.o -; RUN: obj2yaml %t.wasm | FileCheck %s -; RUN: lld -flavor wasm --entry=entry -o %t.wasm %t.o -; RUN: obj2yaml %t.wasm | FileCheck %s +; RUN: llc -filetype=obj %s -o %t.o -define void @entry() local_unnamed_addr #0 { +target triple = "wasm32-unknown-unknown" + +define hidden void @entry() local_unnamed_addr #0 { entry: ret void } -; CHECK: - Type: EXPORT -; CHECK: Exports: -; CHECK: - Name: memory -; CHECK: Kind: MEMORY -; CHECK: Index: 0 -; CHECK: - Name: entry -; CHECK: Kind: FUNCTION -; CHECK: Index: 0 +; RUN: wasm-ld -e entry -o %t1.wasm %t.o +; RUN: obj2yaml %t1.wasm | FileCheck %s +; RUN: wasm-ld --entry=entry -o %t2.wasm %t.o +; RUN: obj2yaml %t2.wasm | FileCheck %s + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: entry +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Type: + +; The __wasm_call_ctors is somewhat special since its created by the linker. +; Make sure we can use it as the entry point if we choose +; RUN: wasm-ld --entry=__wasm_call_ctors -o %t3.wasm %t.o +; RUN: obj2yaml %t3.wasm | FileCheck %s -check-prefix=CHECK-CTOR + +; CHECK-CTOR: - Type: EXPORT +; CHECK-CTOR-NEXT: Exports: +; CHECK-CTOR-NEXT: - Name: memory +; CHECK-CTOR-NEXT: Kind: MEMORY +; CHECK-CTOR-NEXT: Index: 0 +; CHECK-CTOR-NEXT: - Name: __wasm_call_ctors +; CHECK-CTOR-NEXT: Kind: FUNCTION +; CHECK-CTOR-NEXT: Index: 0 +; CHECK-CTOR-NEXT: - Name: __heap_base +; CHECK-CTOR-NEXT: Kind: GLOBAL +; CHECK-CTOR-NEXT: Index: 1 +; CHECK-CTOR-NEXT: - Name: __data_end +; CHECK-CTOR-NEXT: Kind: GLOBAL +; CHECK-CTOR-NEXT: Index: 2 +; CHECK-CTOR-NEXT: - Type: diff --git a/test/wasm/export-all.ll b/test/wasm/export-all.ll new file mode 100644 index 000000000000..34797aac76f7 --- /dev/null +++ b/test/wasm/export-all.ll @@ -0,0 +1,48 @@ +; RUN: llc -O0 -filetype=obj %s -o %t.o + +; RUN: wasm-ld -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; RUN: wasm-ld --export-all -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=EXPORT + +; RUN: wasm-ld --export-all --no-gc-sections -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s -check-prefix=EXPORT + +; Verify the --export-all flag exports hidden symbols + +target triple = "wasm32-unknown-unknown" + +define internal void @internal_func() local_unnamed_addr { +entry: + ret void +} + +define hidden void @bar() local_unnamed_addr { +entry: + ret void +} + +define hidden void @foo() local_unnamed_addr { +entry: + ret void +} + +define hidden void @_start() local_unnamed_addr { +entry: + call void @foo() + call void @internal_func() + ret void +} + +; CHECK: - Type: EXPORT +; CHECK: - Name: _start +; CHECK-NOT: - Name: bar +; CHECK-NOT: - Name: foo +; CHECK-NOT: - Name: internal_func + +; EXPORT: - Type: EXPORT +; EXPORT: - Name: _start +; EXPORT: - Name: bar +; EXPORT: - Name: foo +; EXPORT-NOT: - Name: internal_func diff --git a/test/wasm/export-table.test b/test/wasm/export-table.test new file mode 100644 index 000000000000..58775b928f7f --- /dev/null +++ b/test/wasm/export-table.test @@ -0,0 +1,19 @@ +# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o +# RUN: wasm-ld --export-table -o %t.wasm %t.start.o +# RUN: obj2yaml %t.wasm | FileCheck %s + +# Verify the --export-table flag creates a table export + +# CHECK: - Type: TABLE +# CHECK-NEXT: Tables: +# CHECK-NEXT: - ElemType: ANYFUNC +# CHECK-NEXT: Limits: +# CHECK-NEXT: Flags: [ HAS_MAX ] +# CHECK-NEXT: Initial: 0x00000001 +# CHECK-NEXT: Maximum: 0x00000001 +# CHECK-NEXT: - Type: +# CHECK: - Type: EXPORT +# CHECK-NEXT: Exports: +# CHECK: - Name: __indirect_function_table +# CHECK-NEXT: Kind: TABLE +# CHECK-NEXT: Index: 0 diff --git a/test/wasm/export.ll b/test/wasm/export.ll new file mode 100644 index 000000000000..16b2b6ca57cc --- /dev/null +++ b/test/wasm/export.ll @@ -0,0 +1,37 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: not wasm-ld --export=missing -o %t.wasm %t.o 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s +; RUN: wasm-ld --export=hidden_function -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +define hidden i32 @hidden_function() local_unnamed_addr { +entry: + ret i32 0 +} + +define void @_start() local_unnamed_addr { +entry: + ret void +} + +; CHECK-ERROR: error: symbol exported via --export not found: missing + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: hidden_function +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Type: CODE diff --git a/test/wasm/fatal-warnings.ll b/test/wasm/fatal-warnings.ll new file mode 100644 index 000000000000..0007dc203f02 --- /dev/null +++ b/test/wasm/fatal-warnings.ll @@ -0,0 +1,17 @@ +; RUN: llc -filetype=obj %s -o %t.main.o +; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: lld -flavor wasm -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-WARN +; RUN: not lld -flavor wasm --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-FATAL + +; CHECK-WARN: warning: function signature mismatch: ret32 +; CHECK-FATAL: error: function signature mismatch: ret32 + +target triple = "wasm32-unknown-unknown" + +define hidden void @_start() local_unnamed_addr #0 { +entry: + %call = tail call i32 @ret32(i32 1, i64 2, i32 3) #2 + ret void +} + +declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1 diff --git a/test/wasm/function-imports-first.ll b/test/wasm/function-imports-first.ll index eda1302703c0..00c73741b066 100644 --- a/test/wasm/function-imports-first.ll +++ b/test/wasm/function-imports-first.ll @@ -1,8 +1,10 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -o %t.wasm %t.o %t.ret32.o +; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.o %t.ret32.o ; RUN: obj2yaml %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + ; Function Attrs: nounwind define hidden void @_start() local_unnamed_addr #0 { entry: @@ -22,21 +24,25 @@ declare i32 @ret32(float) local_unnamed_addr #1 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - F32 ; CHECK: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 1 ] ; CHECK: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 43000000001081808080001A0B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 43000000001082808080001A0B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41000B ; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 0 -; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: _start +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Name: ret32 ; CHECK-NEXT: ... diff --git a/test/wasm/function-imports.ll b/test/wasm/function-imports.ll index 072554d8400a..a2c6405b0565 100644 --- a/test/wasm/function-imports.ll +++ b/test/wasm/function-imports.ll @@ -1,8 +1,10 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -o %t.wasm %t.ret32.o %t.o +; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.ret32.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + ; Function Attrs: nounwind define hidden void @_start() local_unnamed_addr #0 { entry: @@ -16,22 +18,25 @@ declare i32 @ret32(float) local_unnamed_addr #1 ; CHECK: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - F32 ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - F32 ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ] ; CHECK: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK: - Locals: -; CHECK: - Locals: +; CHECK: - Index: 0 +; CHECK: - Index: 1 +; CHECK: - Index: 2 ; CHECK: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: ret32 +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: ret32 +; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Name: _start ; CHECK-NEXT: ... diff --git a/test/wasm/function-index.test b/test/wasm/function-index.test index c65c560d11c8..82f5d0cfb245 100644 --- a/test/wasm/function-index.test +++ b/test/wasm/function-index.test @@ -1,6 +1,6 @@ -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret64.ll -o %t.ret64.o -# RUN: lld -flavor wasm -r -o %t.wasm %t.ret32.o %t.ret64.o +# RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +# RUN: llc -filetype=obj %p/Inputs/ret64.ll -o %t.ret64.o +# RUN: wasm-ld -r -o %t.wasm %t.ret32.o %t.ret64.o # RUN: obj2yaml %t.wasm | FileCheck %s CHECK: Sections: diff --git a/test/wasm/gc-imports.ll b/test/wasm/gc-imports.ll new file mode 100644 index 000000000000..fbcb74dbdd3e --- /dev/null +++ b/test/wasm/gc-imports.ll @@ -0,0 +1,93 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: yaml2obj %S/Inputs/undefined-globals.yaml -o %t_globals.o +; RUN: wasm-ld --allow-undefined -o %t1.wasm %t.o %t_globals.o + +target triple = "wasm32-unknown-unknown" + +declare i64 @unused_undef_function(i64 %arg) + +declare i32 @used_undef_function() + +declare i64 @use_undef_global() + +define hidden void @foo() { +entry: + call i64 @unused_undef_function(i64 0) + ret void +} + +define hidden void @_start() { +entry: + call i32 @used_undef_function() + call i64 @use_undef_global() + ret void +} + +; RUN: obj2yaml %t1.wasm | FileCheck %s + +; CHECK: - Type: IMPORT +; CHECK-NEXT: Imports: +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: used_undef_function +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 0 +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: used_undef_global +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: GlobalType: I64 +; CHECK-NEXT: GlobalMutable: true +; CHECK-NEXT: - Type: +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: used_undef_function +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: use_undef_global +; CHECK-NEXT: ... + +; RUN: wasm-ld --no-gc-sections --allow-undefined \ +; RUN: -o %t1.no-gc.wasm %t.o %t_globals.o +; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC + +; NO-GC: - Type: IMPORT +; NO-GC-NEXT: Imports: +; NO-GC-NEXT: - Module: env +; NO-GC-NEXT: Field: unused_undef_function +; NO-GC-NEXT: Kind: FUNCTION +; NO-GC-NEXT: SigIndex: 0 +; NO-GC-NEXT: - Module: env +; NO-GC-NEXT: Field: used_undef_function +; NO-GC-NEXT: Kind: FUNCTION +; NO-GC-NEXT: SigIndex: 1 +; NO-GC-NEXT: - Module: env +; NO-GC-NEXT: Field: unused_undef_global +; NO-GC-NEXT: Kind: GLOBAL +; NO-GC-NEXT: GlobalType: I64 +; NO-GC-NEXT: GlobalMutable: true +; NO-GC-NEXT: - Module: env +; NO-GC-NEXT: Field: used_undef_global +; NO-GC-NEXT: Kind: GLOBAL +; NO-GC-NEXT: GlobalType: I64 +; NO-GC-NEXT: GlobalMutable: true +; NO-GC-NEXT: - Type: +; NO-GC: - Type: CUSTOM +; NO-GC-NEXT: Name: name +; NO-GC-NEXT: FunctionNames: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: Name: unused_undef_function +; NO-GC-NEXT: - Index: 1 +; NO-GC-NEXT: Name: used_undef_function +; NO-GC-NEXT: - Index: 2 +; NO-GC-NEXT: Name: __wasm_call_ctors +; NO-GC-NEXT: - Index: 3 +; NO-GC-NEXT: Name: foo +; NO-GC-NEXT: - Index: 4 +; NO-GC-NEXT: Name: _start +; NO-GC-NEXT: - Index: 5 +; NO-GC-NEXT: Name: use_undef_global +; NO-GC-NEXT: ... diff --git a/test/wasm/gc-sections.ll b/test/wasm/gc-sections.ll new file mode 100644 index 000000000000..57b69738a6f3 --- /dev/null +++ b/test/wasm/gc-sections.ll @@ -0,0 +1,153 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: yaml2obj %S/Inputs/globals.yaml -o %t_globals.o +; RUN: wasm-ld -print-gc-sections -o %t1.wasm %t.o %t_globals.o | \ +; RUN: FileCheck %s -check-prefix=PRINT-GC +; PRINT-GC: removing unused section {{.*}}:(unused_function) +; PRINT-GC-NOT: removing unused section {{.*}}:(used_function) +; PRINT-GC: removing unused section {{.*}}:(.data.unused_data) +; PRINT-GC-NOT: removing unused section {{.*}}:(.data.used_data) +; PRINT-GC: removing unused section {{.*}}:(unused_global) +; PRINT-GC-NOT: removing unused section {{.*}}:(used_global) + +target triple = "wasm32-unknown-unknown" + +@unused_data = hidden global i64 1, align 4 +@used_data = hidden global i32 2, align 4 + +define hidden i64 @unused_function(i64 %arg) { + %1 = load i64, i64* @unused_data, align 4 + ret i64 %1 +} + +define hidden i32 @used_function() { + %1 = load i32, i32* @used_data, align 4 + ret i32 %1 +} + +declare i64 @use_global() + +define hidden void @_start() { +entry: + call i32 @used_function() + call i64 @use_global() + ret void +} + +; RUN: obj2yaml %t1.wasm | FileCheck %s + +; CHECK: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: ReturnType: I64 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Type: FUNCTION + +; CHECK: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I64 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I64_CONST +; CHECK-NEXT: Value: 456 + +; CHECK: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '02000000' +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: used_function +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: use_global +; CHECK-NEXT: ... + +; RUN: wasm-ld -print-gc-sections --no-gc-sections -o %t1.no-gc.wasm \ +; RUN: %t.o %t_globals.o +; RUN: obj2yaml %t1.no-gc.wasm | FileCheck %s -check-prefix=NO-GC + +; NO-GC: - Type: TYPE +; NO-GC-NEXT: Signatures: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: ReturnType: NORESULT +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - Index: 1 +; NO-GC-NEXT: ReturnType: I64 +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - I64 +; NO-GC-NEXT: - Index: 2 +; NO-GC-NEXT: ReturnType: I32 +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - Index: 3 +; NO-GC-NEXT: ReturnType: I64 +; NO-GC-NEXT: ParamTypes: +; NO-GC-NEXT: - Type: FUNCTION + +; NO-GC: - Type: GLOBAL +; NO-GC-NEXT: Globals: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: Type: I32 +; NO-GC-NEXT: Mutable: true +; NO-GC-NEXT: InitExpr: +; NO-GC-NEXT: Opcode: I32_CONST +; NO-GC-NEXT: Value: 66576 +; NO-GC-NEXT: - Index: 1 +; NO-GC-NEXT: Type: I64 +; NO-GC-NEXT: Mutable: true +; NO-GC-NEXT: InitExpr: +; NO-GC-NEXT: Opcode: I64_CONST +; NO-GC-NEXT: Value: 123 +; NO-GC-NEXT: - Index: 2 +; NO-GC-NEXT: Type: I64 +; NO-GC-NEXT: Mutable: true +; NO-GC-NEXT: InitExpr: +; NO-GC-NEXT: Opcode: I64_CONST +; NO-GC-NEXT: Value: 456 + +; NO-GC: - Type: DATA +; NO-GC-NEXT: Segments: +; NO-GC-NEXT: - SectionOffset: 7 +; NO-GC-NEXT: MemoryIndex: 0 +; NO-GC-NEXT: Offset: +; NO-GC-NEXT: Opcode: I32_CONST +; NO-GC-NEXT: Value: 1024 +; NO-GC-NEXT: Content: '010000000000000002000000' +; NO-GC-NEXT: - Type: CUSTOM +; NO-GC-NEXT: Name: name +; NO-GC-NEXT: FunctionNames: +; NO-GC-NEXT: - Index: 0 +; NO-GC-NEXT: Name: __wasm_call_ctors +; NO-GC-NEXT: - Index: 1 +; NO-GC-NEXT: Name: unused_function +; NO-GC-NEXT: - Index: 2 +; NO-GC-NEXT: Name: used_function +; NO-GC-NEXT: - Index: 3 +; NO-GC-NEXT: Name: _start +; NO-GC-NEXT: - Index: 4 +; NO-GC-NEXT: Name: use_global +; NO-GC-NEXT: ... + +; RUN: not wasm-ld --gc-sections --relocatable -o %t1.no-gc.wasm %t.o 2>&1 | FileCheck %s -check-prefix=CHECK-ERROR +; CHECK-ERROR: error: -r and --gc-sections may not be used together diff --git a/test/wasm/import-memory.test b/test/wasm/import-memory.test index 9713e6cd5a17..49bf06b74832 100644 --- a/test/wasm/import-memory.test +++ b/test/wasm/import-memory.test @@ -1,13 +1,33 @@ -# RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -# RUN: lld -flavor wasm -entry ret32 --import-memory -o %t.wasm %t.ret32.o +# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o +# RUN: wasm-ld --import-memory -o %t.wasm %t.start.o # RUN: obj2yaml %t.wasm | FileCheck %s # Verify the --import-memory flag creates a memory import # CHECK: - Type: IMPORT -# CHECK-NEXT: Imports: +# CHECK-NEXT: Imports: # CHECK-NEXT: - Module: env # CHECK-NEXT: Field: memory # CHECK-NEXT: Kind: MEMORY -# CHECK-NEXT: Memory: +# CHECK-NEXT: Memory: # CHECK-NEXT: Initial: 0x00000002 +# CHECK-NEXT: - Type: + + + +# RUN: wasm-ld --import-memory --initial-memory=262144 \ +# RUN: --max-memory=327680 -o %t.max.wasm %t.start.o +# RUN: obj2yaml %t.max.wasm | FileCheck -check-prefix=CHECK-MAX %s + +# Verify the --initial-memory and --max-memory arguments work with imports + +# CHECK-MAX: - Type: IMPORT +# CHECK-MAX-NEXT: Imports: +# CHECK-MAX-NEXT: - Module: env +# CHECK-MAX-NEXT: Field: memory +# CHECK-MAX-NEXT: Kind: MEMORY +# CHECK-MAX-NEXT: Memory: +# CHECK-MAX-NEXT: Flags: [ HAS_MAX ] +# CHECK-MAX-NEXT: Initial: 0x00000004 +# CHECK-MAX-NEXT: Maximum: 0x00000005 +# CHECK-MAX-NEXT: - Type: diff --git a/test/wasm/import-table.test b/test/wasm/import-table.test new file mode 100644 index 000000000000..eb767090292a --- /dev/null +++ b/test/wasm/import-table.test @@ -0,0 +1,18 @@ +# RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o +# RUN: wasm-ld --import-table -o %t.wasm %t.start.o +# RUN: obj2yaml %t.wasm | FileCheck %s + +# Verify the --import-table flag creates a table import + +# CHECK: - Type: IMPORT +# CHECK-NEXT: Imports: +# CHECK-NEXT: - Module: env +# CHECK-NEXT: Field: __indirect_function_table +# CHECK-NEXT: Kind: TABLE +# CHECK-NEXT: Table: +# CHECK-NEXT: ElemType: ANYFUNC +# CHECK-NEXT: Limits: +# CHECK-NEXT: Flags: [ HAS_MAX ] +# CHECK-NEXT: Initial: 0x00000001 +# CHECK-NEXT: Maximum: 0x00000001 + diff --git a/test/wasm/init-fini.ll b/test/wasm/init-fini.ll index bdae29811d8e..9a7f5357ef01 100644 --- a/test/wasm/init-fini.ll +++ b/test/wasm/init-fini.ll @@ -1,5 +1,7 @@ -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/global-ctor-dtor.ll -o %t.global-ctor-dtor.o +; RUN: llc -filetype=obj -o %t.o %s +; RUN: llc -filetype=obj %S/Inputs/global-ctor-dtor.ll -o %t.global-ctor-dtor.o + +target triple = "wasm32-unknown-unknown" define hidden void @func1() { entry: @@ -11,89 +13,316 @@ entry: ret void } -define void @__cxa_atexit() { +define hidden void @func3() { +entry: ret void } +define hidden void @func4() { +entry: + ret void +} + +declare hidden void @externCtor() +declare hidden void @externDtor() + +define i32 @__cxa_atexit(i32 %func, i32 %arg, i32 %dso_handle) { + ret i32 0 +} + define hidden void @_start() { entry: ret void } -@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func1, i8* null }] +@llvm.global_ctors = appending global [4 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 1001, void ()* @func1, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func1, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func2, i8* null }, + { i32, void ()*, i8* } { i32 4000, void ()* @externCtor, i8* null } +] -@llvm.global_dtors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 65535, void ()* @func2, i8* null }] +@llvm.global_dtors = appending global [4 x { i32, void ()*, i8* }] [ + { i32, void ()*, i8* } { i32 1001, void ()* @func3, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func3, i8* null }, + { i32, void ()*, i8* } { i32 101, void ()* @func4, i8* null }, + { i32, void ()*, i8* } { i32 4000, void ()* @externDtor, i8* null } +] -; RUN: lld -flavor wasm %t.o %t.global-ctor-dtor.o -o %t.wasm +; RUN: wasm-ld --allow-undefined %t.o %t.global-ctor-dtor.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s -; CHECK: Name: linking -; CHECK-NEXT: DataSize: 0 +; CHECK: - Type: IMPORT +; CHECK-NEXT: Imports: +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: externDtor +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 0 +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: externCtor +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 0 +; CHECK: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 9, 11, 13, 17, 19, 21 ] +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 10031004100A100F1012100F10141003100C100F10161001100E0B +; CHECK: - Index: 22 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 024041868080800041004180888080001087808080000D000F0B00000B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name -; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: func1 +; CHECK-NEXT: Name: externDtor ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: func2 +; CHECK-NEXT: Name: externCtor ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: __cxa_atexit +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Name: _start +; CHECK-NEXT: Name: func1 ; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: Name: func2 ; CHECK-NEXT: - Index: 5 -; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: Name: func3 ; CHECK-NEXT: - Index: 6 -; CHECK-NEXT: Name: .Lbitcast +; CHECK-NEXT: Name: func4 ; CHECK-NEXT: - Index: 7 -; CHECK-NEXT: Name: myctor +; CHECK-NEXT: Name: __cxa_atexit ; CHECK-NEXT: - Index: 8 -; CHECK-NEXT: Name: mydtor +; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 9 -; CHECK-NEXT: Name: .Lcall_dtors +; CHECK-NEXT: Name: .Lcall_dtors.101 ; CHECK-NEXT: - Index: 10 -; CHECK-NEXT: Name: .Lregister_call_dtors +; CHECK-NEXT: Name: .Lregister_call_dtors.101 +; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: Name: .Lcall_dtors.1001 +; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: Name: .Lregister_call_dtors.1001 +; CHECK-NEXT: - Index: 13 +; CHECK-NEXT: Name: .Lcall_dtors.4000 +; CHECK-NEXT: - Index: 14 +; CHECK-NEXT: Name: .Lregister_call_dtors.4000 +; CHECK-NEXT: - Index: 15 +; CHECK-NEXT: Name: myctor +; CHECK-NEXT: - Index: 16 +; CHECK-NEXT: Name: mydtor +; CHECK-NEXT: - Index: 17 +; CHECK-NEXT: Name: .Lcall_dtors.101 +; CHECK-NEXT: - Index: 18 +; CHECK-NEXT: Name: .Lregister_call_dtors.101 +; CHECK-NEXT: - Index: 19 +; CHECK-NEXT: Name: .Lcall_dtors.202 +; CHECK-NEXT: - Index: 20 +; CHECK-NEXT: Name: .Lregister_call_dtors.202 +; CHECK-NEXT: - Index: 21 +; CHECK-NEXT: Name: .Lcall_dtors.2002 +; CHECK-NEXT: - Index: 22 +; CHECK-NEXT: Name: .Lregister_call_dtors.2002 ; CHECK-NEXT: ... -; RUN: lld -flavor wasm -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm +; RUN: wasm-ld -r %t.o %t.global-ctor-dtor.o -o %t.reloc.wasm ; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s -; RELOC: Name: linking -; RELOC-NEXT: DataSize: 0 -; RELOC-NEXT: InitFunctions: -; RELOC-NEXT: - Priority: 65535 -; RELOC-NEXT: FunctionIndex: 0 -; RELOC-NEXT: - Priority: 65535 -; RELOC-NEXT: FunctionIndex: 5 -; RELOC-NEXT: - Priority: 65535 -; RELOC-NEXT: FunctionIndex: 7 -; RELOC-NEXT: - Priority: 65535 -; RELOC-NEXT: FunctionIndex: 10 -; RELOC-NEXT: - Type: CUSTOM -; RELOC-NEXT: Name: name -; RELOC-NEXT: FunctionNames: +; RELOC: SymbolTable: ; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Kind: FUNCTION ; RELOC-NEXT: Name: func1 +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 2 ; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Kind: FUNCTION ; RELOC-NEXT: Name: func2 +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 3 ; RELOC-NEXT: - Index: 2 -; RELOC-NEXT: Name: __cxa_atexit +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: func3 +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 4 ; RELOC-NEXT: - Index: 3 -; RELOC-NEXT: Name: _start +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: func4 +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 5 ; RELOC-NEXT: - Index: 4 -; RELOC-NEXT: Name: .Lcall_dtors +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: __cxa_atexit +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 6 ; RELOC-NEXT: - Index: 5 -; RELOC-NEXT: Name: .Lregister_call_dtors +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: _start +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 7 ; RELOC-NEXT: - Index: 6 -; RELOC-NEXT: Name: .Lbitcast +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lcall_dtors.101 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 8 ; RELOC-NEXT: - Index: 7 -; RELOC-NEXT: Name: myctor +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lregister_call_dtors.101 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 9 ; RELOC-NEXT: - Index: 8 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: __dso_handle +; RELOC-NEXT: Flags: [ BINDING_WEAK, VISIBILITY_HIDDEN, UNDEFINED ] +; RELOC-NEXT: - Index: 9 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lcall_dtors.1001 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 10 +; RELOC-NEXT: - Index: 10 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lregister_call_dtors.1001 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 11 +; RELOC-NEXT: - Index: 11 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lcall_dtors.4000 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 12 +; RELOC-NEXT: - Index: 12 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: externDtor +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN, UNDEFINED ] +; RELOC-NEXT: Function: 0 +; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lregister_call_dtors.4000 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 13 +; RELOC-NEXT: - Index: 14 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: externCtor +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN, UNDEFINED ] +; RELOC-NEXT: Function: 1 +; RELOC-NEXT: - Index: 15 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: myctor +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 14 +; RELOC-NEXT: - Index: 16 +; RELOC-NEXT: Kind: FUNCTION ; RELOC-NEXT: Name: mydtor +; RELOC-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; RELOC-NEXT: Function: 15 +; RELOC-NEXT: - Index: 17 +; RELOC-NEXT: Kind: GLOBAL +; RELOC-NEXT: Name: __stack_pointer +; RELOC-NEXT: Flags: [ UNDEFINED ] +; RELOC-NEXT: Global: 0 +; RELOC-NEXT: - Index: 18 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lcall_dtors.101 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 16 +; RELOC-NEXT: - Index: 19 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lregister_call_dtors.101 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 17 +; RELOC-NEXT: - Index: 20 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lcall_dtors.202 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 18 +; RELOC-NEXT: - Index: 21 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lregister_call_dtors.202 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 19 +; RELOC-NEXT: - Index: 22 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lcall_dtors.2002 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 20 +; RELOC-NEXT: - Index: 23 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: .Lregister_call_dtors.2002 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 21 +; RELOC-NEXT: InitFunctions: +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: Symbol: 0 +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: Symbol: 1 +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: Symbol: 7 +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: Symbol: 15 +; RELOC-NEXT: - Priority: 101 +; RELOC-NEXT: Symbol: 19 +; RELOC-NEXT: - Priority: 202 +; RELOC-NEXT: Symbol: 15 +; RELOC-NEXT: - Priority: 202 +; RELOC-NEXT: Symbol: 21 +; RELOC-NEXT: - Priority: 1001 +; RELOC-NEXT: Symbol: 0 +; RELOC-NEXT: - Priority: 1001 +; RELOC-NEXT: Symbol: 10 +; RELOC-NEXT: - Priority: 2002 +; RELOC-NEXT: Symbol: 15 +; RELOC-NEXT: - Priority: 2002 +; RELOC-NEXT: Symbol: 23 +; RELOC-NEXT: - Priority: 4000 +; RELOC-NEXT: Symbol: 14 +; RELOC-NEXT: - Priority: 4000 +; RELOC-NEXT: Symbol: 13 +; RELOC-NEXT: - Type: CUSTOM +; RELOC-NEXT: Name: name +; RELOC-NEXT: FunctionNames: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Name: externDtor +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Name: externCtor +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Name: func1 +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Name: func2 +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Name: func3 +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Name: func4 +; RELOC-NEXT: - Index: 6 +; RELOC-NEXT: Name: __cxa_atexit +; RELOC-NEXT: - Index: 7 +; RELOC-NEXT: Name: _start +; RELOC-NEXT: - Index: 8 +; RELOC-NEXT: Name: .Lcall_dtors.101 ; RELOC-NEXT: - Index: 9 -; RELOC-NEXT: Name: .Lcall_dtors +; RELOC-NEXT: Name: .Lregister_call_dtors.101 ; RELOC-NEXT: - Index: 10 -; RELOC-NEXT: Name: .Lregister_call_dtors +; RELOC-NEXT: Name: .Lcall_dtors.1001 +; RELOC-NEXT: - Index: 11 +; RELOC-NEXT: Name: .Lregister_call_dtors.1001 +; RELOC-NEXT: - Index: 12 +; RELOC-NEXT: Name: .Lcall_dtors.4000 +; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: Name: .Lregister_call_dtors.4000 +; RELOC-NEXT: - Index: 14 +; RELOC-NEXT: Name: myctor +; RELOC-NEXT: - Index: 15 +; RELOC-NEXT: Name: mydtor +; RELOC-NEXT: - Index: 16 +; RELOC-NEXT: Name: .Lcall_dtors.101 +; RELOC-NEXT: - Index: 17 +; RELOC-NEXT: Name: .Lregister_call_dtors.101 +; RELOC-NEXT: - Index: 18 +; RELOC-NEXT: Name: .Lcall_dtors.202 +; RELOC-NEXT: - Index: 19 +; RELOC-NEXT: Name: .Lregister_call_dtors.202 +; RELOC-NEXT: - Index: 20 +; RELOC-NEXT: Name: .Lcall_dtors.2002 +; RELOC-NEXT: - Index: 21 +; RELOC-NEXT: Name: .Lregister_call_dtors.2002 ; RELOC-NEXT: ... diff --git a/test/wasm/invalid-stack-size.test b/test/wasm/invalid-stack-size.test index 484bbd3ca2c8..90c9fda113e6 100644 --- a/test/wasm/invalid-stack-size.test +++ b/test/wasm/invalid-stack-size.test @@ -1,9 +1,4 @@ -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %s -o %t.o -; RUN: not lld -flavor wasm -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s - -define i32 @_start() local_unnamed_addr #1 { -entry: - ret i32 0 -} +; RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o +; RUN: not wasm-ld -o %t.wasm -z stack-size=1 %t.o 2>&1 | FileCheck %s ; CHECK: error: stack size must be 16-byte aligned diff --git a/test/wasm/load-undefined.ll b/test/wasm/load-undefined.ll deleted file mode 100644 index f979c9acb517..000000000000 --- a/test/wasm/load-undefined.ll +++ /dev/null @@ -1,38 +0,0 @@ -; Verify that the -u / --undefined option is able to pull in symbols from -; an archive, and doesn't error when uses to pull in a symbol already loaded. -; -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret64.ll -o %t.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %S/Inputs/ret32.ll -o %t2.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t3.o -; RUN: llvm-ar rcs %t2.a %t2.o -; RUN: lld -flavor wasm %t3.o %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64 -; RUN: obj2yaml %t.wasm | FileCheck %s - -define i32 @_start() local_unnamed_addr { -entry: - ret i32 1 -} - -; CHECK: - Type: EXPORT -; CHECK-NEXT: Exports: -; CHECK-NEXT: - Name: memory -; CHECK-NEXT: Kind: MEMORY -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: ret32 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: ret64 -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Type: - - -; Verify that referencing a symbol that doesn't exist won't work -; RUN: not lld -flavor wasm %t3.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s -; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist - -; RUN: not lld -flavor wasm %t3.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s -; CHECK-UNDEFINED2: function forced with --undefined not found: symboldoesnotexist diff --git a/test/wasm/load-undefined.test b/test/wasm/load-undefined.test new file mode 100644 index 000000000000..160cb485ac34 --- /dev/null +++ b/test/wasm/load-undefined.test @@ -0,0 +1,40 @@ +; Verify that the -u / --undefined option is able to pull in symbols from +; an archive, and doesn't error when uses to pull in a symbol already loaded. +; +; RUN: llc -filetype=obj %S/Inputs/ret64.ll -o %t.o +; RUN: llc -filetype=obj %S/Inputs/ret32.ll -o %t2.o +; RUN: llc -filetype=obj %S/Inputs/start.ll -o %t.start.o +; RUN: llvm-ar rcs %t2.a %t2.o +; RUN: wasm-ld %t.start.o --no-gc-sections %t2.a %t.o -o %t.wasm -u ret32 --undefined ret64 +; RUN: obj2yaml %t.wasm | FileCheck %s +; RUN: wasm-ld %t.start.o --no-gc-sections %t2.a %t.o -o %t2.wasm +; RUN: obj2yaml %t2.wasm | FileCheck %s -check-prefix=NO-LOAD + +; CHECK: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: ret32 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: ret64 +; CHECK-NEXT: ... + +; NO-LOAD: Name: name +; NO-LOAD-NEXT: FunctionNames: +; NO-LOAD-NEXT: - Index: 0 +; NO-LOAD-NEXT: Name: __wasm_call_ctors +; NO-LOAD-NEXT: - Index: 1 +; NO-LOAD-NEXT: Name: _start +; NO-LOAD-NEXT: - Index: 2 +; NO-LOAD-NEXT: Name: ret64 +; NO-LOAD-NEXT: ... + +; Verify that referencing a symbol that doesn't exist won't work +; RUN: not wasm-ld %t.start.o -o %t.wasm -u symboldoesnotexist 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED1 %s +; CHECK-UNDEFINED1: error: undefined symbol: symboldoesnotexist + +; RUN: not wasm-ld %t.start.o -o %t.wasm --undefined symboldoesnotexist --allow-undefined 2>&1 | FileCheck -check-prefix=CHECK-UNDEFINED2 %s +; CHECK-UNDEFINED2: symbol forced with --undefined not found: symboldoesnotexist diff --git a/test/wasm/local-symbols.ll b/test/wasm/local-symbols.ll index e88f656e14c6..5471466eb076 100644 --- a/test/wasm/local-symbols.ll +++ b/test/wasm/local-symbols.ll @@ -1,18 +1,22 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -o %t.wasm %t.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + @foo = default global i32 1, align 4 @bar = internal default global i32 3, align 4 define internal i32 @baz() local_unnamed_addr { entry: - ret i32 2 + %0 = load i32, i32* @bar, align 4 + ret i32 %0 } -define i32 @_start() local_unnamed_addr { +define void @_start() local_unnamed_addr { entry: - ret i32 1 + call i32 @baz() + ret void } ; CHECK: --- !WASM @@ -22,10 +26,13 @@ entry: ; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -38,25 +45,58 @@ entry: ; CHECK-NEXT: - Initial: 0x00000002 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1032 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: foo +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41020B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41010B +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4100280284888080000B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1081808080001A0B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 7 @@ -66,13 +106,12 @@ entry: ; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: Content: '0100000003000000' ; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 8 -; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: baz +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: baz +; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Name: _start ; CHECK-NEXT: ... diff --git a/test/wasm/locals-duplicate.test b/test/wasm/locals-duplicate.test new file mode 100644 index 000000000000..3c67cdd8cfa4 --- /dev/null +++ b/test/wasm/locals-duplicate.test @@ -0,0 +1,568 @@ +; RUN: llc -filetype=obj %p/Inputs/locals-duplicate1.ll -o %t1.o +; RUN: llc -filetype=obj %p/Inputs/locals-duplicate2.ll -o %t2.o +; RUN: wasm-ld --no-entry -o %t.wasm %t1.o %t2.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +; CHECK: --- !WASM +; CHECK-NEXT: FileHeader: +; CHECK-NEXT: Version: 0x00000001 +; CHECK-NEXT: Sections: +; CHECK-NEXT: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Type: FUNCTION +; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +; CHECK-NEXT: 1, 1, 1 ] +; CHECK-NEXT: - Type: TABLE +; CHECK-NEXT: Tables: +; CHECK-NEXT: - ElemType: ANYFUNC +; CHECK-NEXT: Limits: +; CHECK-NEXT: Flags: [ HAS_MAX ] +; CHECK-NEXT: Initial: 0x00000007 +; CHECK-NEXT: Maximum: 0x00000007 +; CHECK-NEXT: - Type: MEMORY +; CHECK-NEXT: Memories: +; CHECK-NEXT: - Initial: 0x00000002 +; CHECK-NEXT: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66592 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66592 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1048 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1028 +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1036 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: colliding_func2 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: get_global1A +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: get_global2A +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 5 +; CHECK-NEXT: - Name: colliding_global2 +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: get_global3A +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 6 +; CHECK-NEXT: - Name: get_func1A +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 7 +; CHECK-NEXT: - Name: get_func2A +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 8 +; CHECK-NEXT: - Name: get_func3A +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 9 +; CHECK-NEXT: - Name: colliding_func1 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 10 +; CHECK-NEXT: - Name: get_global1B +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 13 +; CHECK-NEXT: - Name: colliding_global1 +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Name: get_global2B +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 14 +; CHECK-NEXT: - Name: get_global3B +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 15 +; CHECK-NEXT: - Name: get_func1B +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 16 +; CHECK-NEXT: - Name: get_func2B +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 17 +; CHECK-NEXT: - Name: get_func3B +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 18 +; CHECK-NEXT: - Type: ELEM +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 1, 2, 3, 10, 11, 12 ] +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41020B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41020B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41020B +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4180888080000B +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4184888080000B +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4188888080000B +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4181808080000B +; CHECK-NEXT: - Index: 8 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4182808080000B +; CHECK-NEXT: - Index: 9 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4183808080000B +; CHECK-NEXT: - Index: 10 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41020B +; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41020B +; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 41020B +; CHECK-NEXT: - Index: 13 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 418C888080000B +; CHECK-NEXT: - Index: 14 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4190888080000B +; CHECK-NEXT: - Index: 15 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4194888080000B +; CHECK-NEXT: - Index: 16 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4184808080000B +; CHECK-NEXT: - Index: 17 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4185808080000B +; CHECK-NEXT: - Index: 18 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4186808080000B +; CHECK-NEXT: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '000000000000000000000000000000000000000000000000' +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: colliding_func1 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: colliding_func2 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: colliding_func3 +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: get_global1A +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: get_global2A +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Name: get_global3A +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Name: get_func1A +; CHECK-NEXT: - Index: 8 +; CHECK-NEXT: Name: get_func2A +; CHECK-NEXT: - Index: 9 +; CHECK-NEXT: Name: get_func3A +; CHECK-NEXT: - Index: 10 +; CHECK-NEXT: Name: colliding_func1 +; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: Name: colliding_func2 +; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: Name: colliding_func3 +; CHECK-NEXT: - Index: 13 +; CHECK-NEXT: Name: get_global1B +; CHECK-NEXT: - Index: 14 +; CHECK-NEXT: Name: get_global2B +; CHECK-NEXT: - Index: 15 +; CHECK-NEXT: Name: get_global3B +; CHECK-NEXT: - Index: 16 +; CHECK-NEXT: Name: get_func1B +; CHECK-NEXT: - Index: 17 +; CHECK-NEXT: Name: get_func2B +; CHECK-NEXT: - Index: 18 +; CHECK-NEXT: Name: get_func3B +; CHECK-NEXT: ... + + +; RUN: wasm-ld -r --no-entry -o %t.reloc.wasm %t1.o %t2.o +; RUN: obj2yaml %t.reloc.wasm | FileCheck -check-prefix=RELOC %s + +; RELOC: --- !WASM +; RELOC-NEXT: FileHeader: +; RELOC-NEXT: Version: 0x00000001 +; RELOC-NEXT: Sections: +; RELOC-NEXT: - Type: TYPE +; RELOC-NEXT: Signatures: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: ReturnType: I32 +; RELOC-NEXT: ParamTypes: +; RELOC-NEXT: - Type: FUNCTION +; RELOC-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +; RELOC-NEXT: 0, 0 ] +; RELOC-NEXT: - Type: TABLE +; RELOC-NEXT: Tables: +; RELOC-NEXT: - ElemType: ANYFUNC +; RELOC-NEXT: Limits: +; RELOC-NEXT: Flags: [ HAS_MAX ] +; RELOC-NEXT: Initial: 0x00000007 +; RELOC-NEXT: Maximum: 0x00000007 +; RELOC-NEXT: - Type: MEMORY +; RELOC-NEXT: Memories: +; RELOC-NEXT: - Initial: 0x00000001 +; RELOC-NEXT: - Type: ELEM +; RELOC-NEXT: Segments: +; RELOC-NEXT: - Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 1 +; RELOC-NEXT: Functions: [ 0, 1, 2, 9, 10, 11 ] +; RELOC-NEXT: - Type: CODE +; RELOC-NEXT: Relocations: +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; RELOC-NEXT: Index: 4 +; RELOC-NEXT: Offset: 0x00000013 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x0000001C +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; RELOC-NEXT: Index: 8 +; RELOC-NEXT: Offset: 0x00000025 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 0 +; RELOC-NEXT: Offset: 0x0000002E +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 1 +; RELOC-NEXT: Offset: 0x00000037 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 2 +; RELOC-NEXT: Offset: 0x00000040 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; RELOC-NEXT: Index: 16 +; RELOC-NEXT: Offset: 0x00000058 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; RELOC-NEXT: Index: 18 +; RELOC-NEXT: Offset: 0x00000061 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; RELOC-NEXT: Index: 20 +; RELOC-NEXT: Offset: 0x0000006A +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 12 +; RELOC-NEXT: Offset: 0x00000073 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 13 +; RELOC-NEXT: Offset: 0x0000007C +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 14 +; RELOC-NEXT: Offset: 0x00000085 +; RELOC-NEXT: Functions: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 41020B +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 41020B +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 41020B +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4180808080000B +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4188808080000B +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4190808080000B +; RELOC-NEXT: - Index: 6 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4181808080000B +; RELOC-NEXT: - Index: 7 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4182808080000B +; RELOC-NEXT: - Index: 8 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4183808080000B +; RELOC-NEXT: - Index: 9 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 41020B +; RELOC-NEXT: - Index: 10 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 41020B +; RELOC-NEXT: - Index: 11 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 41020B +; RELOC-NEXT: - Index: 12 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4184808080000B +; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 418C808080000B +; RELOC-NEXT: - Index: 14 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4194808080000B +; RELOC-NEXT: - Index: 15 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4184808080000B +; RELOC-NEXT: - Index: 16 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4185808080000B +; RELOC-NEXT: - Index: 17 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 4186808080000B +; RELOC-NEXT: - Type: DATA +; RELOC-NEXT: Segments: +; RELOC-NEXT: - SectionOffset: 6 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 0 +; RELOC-NEXT: Content: '0000000000000000' +; RELOC-NEXT: - SectionOffset: 19 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 8 +; RELOC-NEXT: Content: '0000000000000000' +; RELOC-NEXT: - SectionOffset: 32 +; RELOC-NEXT: MemoryIndex: 0 +; RELOC-NEXT: Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 16 +; RELOC-NEXT: Content: '0000000000000000' +; RELOC-NEXT: - Type: CUSTOM +; RELOC-NEXT: Name: linking +; RELOC-NEXT: Version: 1 +; RELOC-NEXT: SymbolTable: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: colliding_func1 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 0 +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: colliding_func2 +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 1 +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: colliding_func3 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 2 +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_global1A +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 3 +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: colliding_global1 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Segment: 0 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_global2A +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 4 +; RELOC-NEXT: - Index: 6 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: colliding_global2 +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Segment: 1 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 7 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_global3A +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 5 +; RELOC-NEXT: - Index: 8 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: colliding_global3 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Segment: 2 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 9 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_func1A +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 6 +; RELOC-NEXT: - Index: 10 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_func2A +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 7 +; RELOC-NEXT: - Index: 11 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_func3A +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 8 +; RELOC-NEXT: - Index: 12 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: colliding_func1 +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 9 +; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: colliding_func2 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 10 +; RELOC-NEXT: - Index: 14 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: colliding_func3 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Function: 11 +; RELOC-NEXT: - Index: 15 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_global1B +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 12 +; RELOC-NEXT: - Index: 16 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: colliding_global1 +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Segment: 0 +; RELOC-NEXT: Offset: 4 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 17 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_global2B +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 13 +; RELOC-NEXT: - Index: 18 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: colliding_global2 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Segment: 1 +; RELOC-NEXT: Offset: 4 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 19 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_global3B +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 14 +; RELOC-NEXT: - Index: 20 +; RELOC-NEXT: Kind: DATA +; RELOC-NEXT: Name: colliding_global3 +; RELOC-NEXT: Flags: [ BINDING_LOCAL ] +; RELOC-NEXT: Segment: 2 +; RELOC-NEXT: Offset: 4 +; RELOC-NEXT: Size: 4 +; RELOC-NEXT: - Index: 21 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_func1B +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 15 +; RELOC-NEXT: - Index: 22 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_func2B +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 16 +; RELOC-NEXT: - Index: 23 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: get_func3B +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 17 +; RELOC-NEXT: SegmentInfo: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Name: .bss.colliding_global1 +; RELOC-NEXT: Alignment: 4 +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Name: .bss.colliding_global2 +; RELOC-NEXT: Alignment: 4 +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Name: .bss.colliding_global3 +; RELOC-NEXT: Alignment: 4 +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: - Type: CUSTOM +; RELOC-NEXT: Name: name +; RELOC-NEXT: FunctionNames: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Name: colliding_func1 +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Name: colliding_func2 +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Name: colliding_func3 +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Name: get_global1A +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Name: get_global2A +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Name: get_global3A +; RELOC-NEXT: - Index: 6 +; RELOC-NEXT: Name: get_func1A +; RELOC-NEXT: - Index: 7 +; RELOC-NEXT: Name: get_func2A +; RELOC-NEXT: - Index: 8 +; RELOC-NEXT: Name: get_func3A +; RELOC-NEXT: - Index: 9 +; RELOC-NEXT: Name: colliding_func1 +; RELOC-NEXT: - Index: 10 +; RELOC-NEXT: Name: colliding_func2 +; RELOC-NEXT: - Index: 11 +; RELOC-NEXT: Name: colliding_func3 +; RELOC-NEXT: - Index: 12 +; RELOC-NEXT: Name: get_global1B +; RELOC-NEXT: - Index: 13 +; RELOC-NEXT: Name: get_global2B +; RELOC-NEXT: - Index: 14 +; RELOC-NEXT: Name: get_global3B +; RELOC-NEXT: - Index: 15 +; RELOC-NEXT: Name: get_func1B +; RELOC-NEXT: - Index: 16 +; RELOC-NEXT: Name: get_func2B +; RELOC-NEXT: - Index: 17 +; RELOC-NEXT: Name: get_func3B +; RELOC-NEXT: ... diff --git a/test/wasm/lto/Inputs/archive.ll b/test/wasm/lto/Inputs/archive.ll new file mode 100644 index 000000000000..75984793246c --- /dev/null +++ b/test/wasm/lto/Inputs/archive.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @f() { + ret void +} diff --git a/test/wasm/lto/Inputs/cache.ll b/test/wasm/lto/Inputs/cache.ll new file mode 100644 index 000000000000..a66f36aef9cb --- /dev/null +++ b/test/wasm/lto/Inputs/cache.ll @@ -0,0 +1,10 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define i32 @_start() { +entry: + call void (...) @globalfunc() + ret i32 0 +} + +declare void @globalfunc(...) diff --git a/test/wasm/lto/Inputs/save-temps.ll b/test/wasm/lto/Inputs/save-temps.ll new file mode 100644 index 000000000000..6f4de417c380 --- /dev/null +++ b/test/wasm/lto/Inputs/save-temps.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @bar() { + ret void +} diff --git a/test/wasm/lto/Inputs/thinlto.ll b/test/wasm/lto/Inputs/thinlto.ll new file mode 100644 index 000000000000..39e573b1c21e --- /dev/null +++ b/test/wasm/lto/Inputs/thinlto.ll @@ -0,0 +1,7 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @g() { +entry: + ret void +} diff --git a/test/wasm/lto/Inputs/used.ll b/test/wasm/lto/Inputs/used.ll new file mode 100644 index 000000000000..d0250d518abc --- /dev/null +++ b/test/wasm/lto/Inputs/used.ll @@ -0,0 +1,8 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +@foo = hidden global i32 1 + +define hidden void @bar() { + ret void +} diff --git a/test/wasm/lto/archive.ll b/test/wasm/lto/archive.ll new file mode 100644 index 000000000000..89fa840cdec5 --- /dev/null +++ b/test/wasm/lto/archive.ll @@ -0,0 +1,25 @@ +; RUN: llvm-as %S/Inputs/archive.ll -o %t1.o +; RUN: rm -f %t.a +; RUN: llvm-ar rcs %t.a %t1.o +; RUN: llvm-as %s -o %t2.o +; RUN: wasm-ld %t2.o %t.a -o %t3 +; RUN: obj2yaml %t3 | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @_start() { + call void @f() + ret void +} + +declare void @f() + +; CHECK: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: f diff --git a/test/wasm/lto/atomics.ll b/test/wasm/lto/atomics.ll new file mode 100644 index 000000000000..a5a82ae2a5fc --- /dev/null +++ b/test/wasm/lto/atomics.ll @@ -0,0 +1,14 @@ +; RUN: llvm-as %s -o %t.o +; RUN: wasm-ld %t.o -o %t.wasm -lto-O0 +; Atomic operations with fail to compile if the ThreadModel is not +; correctly set to Single (i.e. if atomics are not lowered to regular ops). + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +@foo = hidden global i32 1 + +define void @_start() { + %1 = load atomic i32, i32* @foo unordered, align 4 + ret void +} diff --git a/test/wasm/lto/cache.ll b/test/wasm/lto/cache.ll new file mode 100644 index 000000000000..b0a7820c1e19 --- /dev/null +++ b/test/wasm/lto/cache.ll @@ -0,0 +1,38 @@ +; RUN: opt -module-hash -module-summary %s -o %t.o +; RUN: opt -module-hash -module-summary %p/Inputs/cache.ll -o %t2.o + +; RUN: rm -Rf %t.cache && mkdir %t.cache +; Create two files that would be removed by cache pruning due to age. +; We should only remove files matching the pattern "llvmcache-*". +; RUN: touch -t 197001011200 %t.cache/llvmcache-foo %t.cache/foo +; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=1h:prune_interval=0s -o %t.wasm %t2.o %t.o + +; Two cached objects, plus a timestamp file and "foo", minus the file we removed. +; RUN: ls %t.cache | count 4 + +; Create a file of size 64KB. +; RUN: "%python" -c "print(' ' * 65536)" > %t.cache/llvmcache-foo + +; This should leave the file in place. +; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=128k:prune_interval=0s -o %t.wasm %t2.o %t.o +; RUN: ls %t.cache | count 5 + +; This should remove it. +; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy cache_size_bytes=32k:prune_interval=0s -o %t.wasm %t2.o %t.o +; RUN: ls %t.cache | count 4 + +; Setting max number of files to 0 should disable the limit, not delete everything. +; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=0:prune_interval=0s -o %t.wasm %t2.o %t.o +; RUN: ls %t.cache | count 4 + +; Delete everything except for the timestamp, "foo" and one cache file. +; RUN: wasm-ld --thinlto-cache-dir=%t.cache --thinlto-cache-policy prune_after=0s:cache_size=0%:cache_size_files=1:prune_interval=0s -o %t.wasm %t2.o %t.o +; RUN: ls %t.cache | count 3 + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +define void @globalfunc() #0 { +entry: + ret void +} diff --git a/test/wasm/lto/diagnostics.ll b/test/wasm/lto/diagnostics.ll new file mode 100644 index 000000000000..77f68fe93abb --- /dev/null +++ b/test/wasm/lto/diagnostics.ll @@ -0,0 +1,22 @@ +; verify that errors in the LLVM backend during LTO manifest as lld +; errors + +; RUN: llvm-as %s -o %t.o +; RUN: not wasm-ld --lto-O0 %t.o -o %t2 2>&1 | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @_start() { + call i8* @foo() + ret void +} + +define i8* @foo() { + %1 = call i8* @llvm.returnaddress(i32 0) + ret i8* %1 +} + +declare i8* @llvm.returnaddress(i32) + +; CHECK: error: {{.*}} WebAssembly hasn't implemented __builtin_return_address diff --git a/test/wasm/lto/export.ll b/test/wasm/lto/export.ll new file mode 100644 index 000000000000..44ded6f147f6 --- /dev/null +++ b/test/wasm/lto/export.ll @@ -0,0 +1,38 @@ +; RUN: llvm-as -o %t.bc %s +; RUN: not wasm-ld --export=missing -o %t.wasm %t.bc 2>&1 | FileCheck -check-prefix=CHECK-ERROR %s +; RUN: wasm-ld --export=hidden_function -o %t.wasm %t.bc +; RUN: obj2yaml %t.wasm | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define hidden i32 @hidden_function() local_unnamed_addr { +entry: + ret i32 0 +} + +define void @_start() local_unnamed_addr { +entry: + ret void +} + +; CHECK-ERROR: error: symbol exported via --export not found: missing + +; CHECK: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: _start +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: hidden_function +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Type: CODE diff --git a/test/wasm/lto/incompatible.ll b/test/wasm/lto/incompatible.ll new file mode 100644 index 000000000000..ee98cb4b4e63 --- /dev/null +++ b/test/wasm/lto/incompatible.ll @@ -0,0 +1,8 @@ +; REQUIRES: x86 +; RUN: llvm-as %s -o %t.bc +; RUN: not wasm-ld %t.bc -o out.wasm 2>&1 | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK: {{.*}}incompatible.ll.tmp.bc: machine type must be wasm32 diff --git a/test/wasm/lto/internalize-basic.ll b/test/wasm/lto/internalize-basic.ll new file mode 100644 index 000000000000..313a05ecbae4 --- /dev/null +++ b/test/wasm/lto/internalize-basic.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as %s -o %t.o +; RUN: wasm-ld %t.o -o %t2 -save-temps +; RUN: llvm-dis < %t2.0.2.internalize.bc | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +define void @_start() { + ret void +} + +define hidden void @foo() { + ret void +} + +; Check that _start is not internalized. +; CHECK: define void @_start() + +; Check that foo function is correctly internalized. +; CHECK: define internal void @foo() diff --git a/test/wasm/lto/lto-start.ll b/test/wasm/lto/lto-start.ll new file mode 100644 index 000000000000..6e8f99c95308 --- /dev/null +++ b/test/wasm/lto/lto-start.ll @@ -0,0 +1,18 @@ +; RUN: llvm-as %s -o %t.o +; RUN: wasm-ld %t.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: _start + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +define void @_start() { + ret void +} diff --git a/test/wasm/lto/opt-level.ll b/test/wasm/lto/opt-level.ll new file mode 100644 index 000000000000..b7e6a4cdc70a --- /dev/null +++ b/test/wasm/lto/opt-level.ll @@ -0,0 +1,30 @@ +; RUN: llvm-as -o %t.o %s +; RUN: wasm-ld -o %t0 -e main --lto-O0 %t.o +; RUN: obj2yaml %t0 | FileCheck --check-prefix=CHECK-O0 %s +; RUN: wasm-ld -o %t2 -e main --lto-O2 %t.o +; RUN: obj2yaml %t2 | FileCheck --check-prefix=CHECK-O2 %s +; RUN: wasm-ld -o %t2a -e main %t.o +; RUN: obj2yaml %t2a | FileCheck --check-prefix=CHECK-O2 %s + +; Reject invalid optimization levels. +; RUN: not ld.lld -o %t3 -e main --lto-O6 %t.o 2>&1 | \ +; RUN: FileCheck --check-prefix=INVALID %s +; INVALID: invalid optimization level for LTO: 6 + +; RUN: not ld.lld -o %t3 -m elf_x86_64 -e main --lto-O-1 %t.o 2>&1 | \ +; RUN: FileCheck --check-prefix=INVALIDNEGATIVE %s +; INVALIDNEGATIVE: invalid optimization level for LTO: 4294967295 + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +; CHECK-O0: Name: foo +; CHECK-O2-NOT: Name: foo +define internal void @foo() { + ret void +} + +define void @main() { + call void @foo() + ret void +} diff --git a/test/wasm/lto/parallel.ll b/test/wasm/lto/parallel.ll new file mode 100644 index 000000000000..a93c3558d969 --- /dev/null +++ b/test/wasm/lto/parallel.ll @@ -0,0 +1,24 @@ +; RUN: llvm-as -o %t.bc %s +; RUN: rm -f %t.lto.o %t1.lto.o +; RUN: wasm-ld --lto-partitions=2 -save-temps -o %t %t.bc -r +; RUN: llvm-nm %t.lto.o | FileCheck --check-prefix=CHECK0 %s +; RUN: llvm-nm %t1.lto.o | FileCheck --check-prefix=CHECK1 %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +; CHECK0-NOT: bar +; CHECK0: T foo +; CHECK0-NOT: bar +define void @foo() { + call void @bar() + ret void +} + +; CHECK1-NOT: foo +; CHECK1: T bar +; CHECK1-NOT: foo +define void @bar() { + call void @foo() + ret void +} diff --git a/test/wasm/lto/save-temps.ll b/test/wasm/lto/save-temps.ll new file mode 100644 index 000000000000..2734d86815c7 --- /dev/null +++ b/test/wasm/lto/save-temps.ll @@ -0,0 +1,19 @@ +; RUN: cd %T +; 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 +; RUN: wasm-ld -r -o a.out %t.o %t2.o -save-temps +; RUN: llvm-nm a.out | FileCheck %s +; RUN: llvm-nm a.out.0.0.preopt.bc | FileCheck %s +; RUN: llvm-nm a.out.lto.o | FileCheck %s +; RUN: llvm-dis a.out.0.0.preopt.bc + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @foo() { + ret void +} + +; CHECK: T bar +; CHECK: T foo diff --git a/test/wasm/lto/thinlto.ll b/test/wasm/lto/thinlto.ll new file mode 100644 index 000000000000..062da1a33b89 --- /dev/null +++ b/test/wasm/lto/thinlto.ll @@ -0,0 +1,34 @@ +; Basic ThinLTO tests. +; RUN: opt -module-summary %s -o %t1.o +; RUN: opt -module-summary %p/Inputs/thinlto.ll -o %t2.o + +; First force single-threaded mode +; RUN: rm -f %t31.lto.o %t32.lto.o +; RUN: wasm-ld -r -save-temps --thinlto-jobs=1 %t1.o %t2.o -o %t3 +; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2 + +; Next force multi-threaded mode +; RUN: rm -f %t31.lto.o %t32.lto.o +; RUN: wasm-ld -r -save-temps --thinlto-jobs=2 %t1.o %t2.o -o %t3 +; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2 + +; Check without --thinlto-jobs (which currently default to hardware_concurrency) +; RUN: wasm-ld -r %t1.o %t2.o -o %t3 +; RUN: llvm-nm %t31.lto.o | FileCheck %s --check-prefix=NM1 +; RUN: llvm-nm %t32.lto.o | FileCheck %s --check-prefix=NM2 + +; NM1: T f +; NM2: T g + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +declare void @g(...) + +define void @f() { +entry: + call void (...) @g() + ret void +} diff --git a/test/wasm/lto/undef.ll b/test/wasm/lto/undef.ll new file mode 100644 index 000000000000..729007b50c05 --- /dev/null +++ b/test/wasm/lto/undef.ll @@ -0,0 +1,20 @@ +; RUN: llvm-as %s -o %t.o +; RUN: wasm-ld %t.o -o %t.wasm --allow-undefined +; RUN: obj2yaml %t.wasm | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +declare void @bar() + +define void @_start() { + call void @bar() + ret void +} + +; CHECK: - Type: IMPORT +; CHECK-NEXT: Imports: +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: bar +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 0 diff --git a/test/wasm/lto/used.ll b/test/wasm/lto/used.ll new file mode 100644 index 000000000000..8bf840366cc5 --- /dev/null +++ b/test/wasm/lto/used.ll @@ -0,0 +1,45 @@ +; RUN: llc %s -o %t.o -filetype=obj +; RUN: llvm-as %S/Inputs/used.ll -o %t1.o +; RUN: wasm-ld %t.o %t1.o -o %t.wasm +; RUN: obj2yaml %t.wasm | FileCheck %s + +; Verify that symbols references from regular objects are preserved by LTO + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +declare void @bar() + +@foo = external global i32 + +define void @_start() { + %val = load i32, i32* @foo, align 4 + %tobool = icmp ne i32 %val, 0 + br i1 %tobool, label %callbar, label %return + +callbar: + call void @bar() + br label %return + +return: + ret void +} + +; CHECK: - Type: DATA +; CHECK-NEXT: Segments: +; CHECK-NEXT: - SectionOffset: 7 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: Content: '01000000' + +; CHECK: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: _start +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: bar diff --git a/test/wasm/lto/verify-invalid.ll b/test/wasm/lto/verify-invalid.ll new file mode 100644 index 000000000000..c4a5bcdc67d1 --- /dev/null +++ b/test/wasm/lto/verify-invalid.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as %s -o %t.o +; RUN: wasm-ld %t.o -o %t2 -mllvm -debug-pass=Arguments \ +; RUN: 2>&1 | FileCheck -check-prefix=DEFAULT %s +; RUN: wasm-ld %t.o -o %t2 -mllvm -debug-pass=Arguments \ +; RUN: -disable-verify 2>&1 | FileCheck -check-prefix=DISABLE %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown" + +define void @_start() { + ret void +} + +; -disable-verify should disable the verification of bitcode. +; DEFAULT: Pass Arguments: {{.*}} -verify {{.*}} -verify +; DISABLE-NOT: Pass Arguments: {{.*}} -verify {{.*}} -verify diff --git a/test/wasm/lto/weak.ll b/test/wasm/lto/weak.ll new file mode 100644 index 000000000000..03a017c1a183 --- /dev/null +++ b/test/wasm/lto/weak.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as %s -o %t.o +; RUN: wasm-ld %t.o %t.o -o %t.wasm -r +; RUN: llvm-readobj -t %t.wasm | FileCheck %s + +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-unknown-wasm" + +define weak void @f() { + ret void +} + +; CHECK: Symbol { +; CHECK-NEXT: Name: f +; CHECK-NEXT: Type: FUNCTION (0x0) +; CHECK-NEXT: Flags: 0x1 +; CHECK-NEXT: } diff --git a/test/wasm/many-functions.ll b/test/wasm/many-functions.ll index f21298d862d6..02ad9aab51a0 100644 --- a/test/wasm/many-functions.ll +++ b/test/wasm/many-functions.ll @@ -1,6 +1,6 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/many-funcs.ll -o %t.many.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -r -o %t.wasm %t.many.o %t.o +; RUN: llc -filetype=obj %p/Inputs/many-funcs.ll -o %t.many.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -r -o %t.wasm %t.many.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s ; Test that relocations within the CODE section correctly handle @@ -8,6 +8,8 @@ ; 128 function and so the final output requires a 2-byte LEB in ; the CODE section header to store the function count. +target triple = "wasm32-unknown-unknown" + define i32 @func() { entry: %call = tail call i32 @func() @@ -17,655 +19,785 @@ entry: ; CHECK: - Type: CODE ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000008 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000014 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000020 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000002C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000038 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000044 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000050 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000005C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000068 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000074 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000080 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000008C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000098 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000A4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000B0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000BC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000C8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000D4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000E0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000EC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000000F8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000104 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000110 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000011C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000128 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000134 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000140 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000014C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000158 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000164 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000170 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000017C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000188 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000194 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001A0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001AC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001B8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001C4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001D0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001DC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001E8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000001F4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000200 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000020C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000218 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000224 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000230 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000023C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000248 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000254 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000260 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000026C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000278 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000284 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000290 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000029C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002A8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002B4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002C0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002CC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002D8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002E4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002F0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000002FC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000308 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000314 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000320 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000032C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000338 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000344 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000350 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000035C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000368 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000374 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000380 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000038C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000398 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003A4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003B0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003BC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003C8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003D4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003E0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003EC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000003F8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000404 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000410 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000041C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000428 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000434 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000440 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000044C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000458 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000464 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000470 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000047C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000488 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000494 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004A0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004AC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004B8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004C4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004D0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004DC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004E8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000004F4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000500 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000050C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000518 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000524 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000530 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000053C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000548 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000554 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000560 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000056C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000578 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000584 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000590 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x0000059C ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000005A8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000005B4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000005C0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000005CC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000005D8 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000005E4 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x000005F0 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 129 ; CHECK-NEXT: Offset: 0x000005FC ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_LEB -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 129 ; CHECK-NEXT: Offset: 0x00000608 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB -; CHECK-NEXT: Index: 129 +; CHECK-NEXT: Index: 131 ; CHECK-NEXT: Offset: 0x00000611 ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 8 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 9 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 10 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 13 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 14 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 15 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 16 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 17 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 18 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 19 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 20 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 21 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 22 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 23 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 24 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 25 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 26 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 27 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 28 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 29 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 30 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 31 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 32 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 33 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 34 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 35 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 36 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 37 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 38 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 39 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 40 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 41 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 42 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 43 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 44 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 45 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 46 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 47 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 48 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 49 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 50 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 51 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 52 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 53 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 54 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 55 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 56 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 57 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 58 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 59 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 60 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 61 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 62 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 63 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 64 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 65 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 66 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 67 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 68 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 69 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 70 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 71 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 72 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 73 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 74 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 75 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 76 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 77 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 78 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 79 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 80 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 81 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 82 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 83 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 84 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 85 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 86 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 87 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 88 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 89 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 90 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 91 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 92 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 93 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 94 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 95 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 96 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 97 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 98 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 99 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 100 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 101 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 102 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 103 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 104 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 105 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 106 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 107 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 108 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 109 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 110 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 111 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 112 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 113 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 114 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 115 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 116 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 117 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 118 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 119 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 120 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 121 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 122 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 123 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 124 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 125 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 126 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280284808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 127 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280280808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 128 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4100280280808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 129 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 1081818080000B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: @@ -683,7 +815,670 @@ entry: ; CHECK-NEXT: Content: '01000000' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 8 +; CHECK-NEXT: Version: 1 +; CHECK-NEXT: SymbolTable: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f1 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 0 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: foo +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Segment: 1 +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f2 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 1 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f3 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 2 +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f4 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 3 +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f5 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 4 +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f6 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 5 +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f7 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 6 +; CHECK-NEXT: - Index: 8 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f8 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 7 +; CHECK-NEXT: - Index: 9 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f9 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 8 +; CHECK-NEXT: - Index: 10 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f10 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 9 +; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f11 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 10 +; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f12 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 11 +; CHECK-NEXT: - Index: 13 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f13 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 12 +; CHECK-NEXT: - Index: 14 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f14 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 13 +; CHECK-NEXT: - Index: 15 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f15 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 14 +; CHECK-NEXT: - Index: 16 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f16 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 15 +; CHECK-NEXT: - Index: 17 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f17 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 16 +; CHECK-NEXT: - Index: 18 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f18 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 17 +; CHECK-NEXT: - Index: 19 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f19 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 18 +; CHECK-NEXT: - Index: 20 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f20 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 19 +; CHECK-NEXT: - Index: 21 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f21 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 20 +; CHECK-NEXT: - Index: 22 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f22 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 21 +; CHECK-NEXT: - Index: 23 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f23 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 22 +; CHECK-NEXT: - Index: 24 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f24 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 23 +; CHECK-NEXT: - Index: 25 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f25 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 24 +; CHECK-NEXT: - Index: 26 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f26 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 25 +; CHECK-NEXT: - Index: 27 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f27 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 26 +; CHECK-NEXT: - Index: 28 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f28 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 27 +; CHECK-NEXT: - Index: 29 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f29 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 28 +; CHECK-NEXT: - Index: 30 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f30 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 29 +; CHECK-NEXT: - Index: 31 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f31 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 30 +; CHECK-NEXT: - Index: 32 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f32 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 31 +; CHECK-NEXT: - Index: 33 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f33 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 32 +; CHECK-NEXT: - Index: 34 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f34 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 33 +; CHECK-NEXT: - Index: 35 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f35 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 34 +; CHECK-NEXT: - Index: 36 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f36 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 35 +; CHECK-NEXT: - Index: 37 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f37 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 36 +; CHECK-NEXT: - Index: 38 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f38 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 37 +; CHECK-NEXT: - Index: 39 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f39 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 38 +; CHECK-NEXT: - Index: 40 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f40 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 39 +; CHECK-NEXT: - Index: 41 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f41 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 40 +; CHECK-NEXT: - Index: 42 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f42 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 41 +; CHECK-NEXT: - Index: 43 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f43 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 42 +; CHECK-NEXT: - Index: 44 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f44 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 43 +; CHECK-NEXT: - Index: 45 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f45 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 44 +; CHECK-NEXT: - Index: 46 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f46 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 45 +; CHECK-NEXT: - Index: 47 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f47 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 46 +; CHECK-NEXT: - Index: 48 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f48 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 47 +; CHECK-NEXT: - Index: 49 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f49 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 48 +; CHECK-NEXT: - Index: 50 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f50 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 49 +; CHECK-NEXT: - Index: 51 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f51 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 50 +; CHECK-NEXT: - Index: 52 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f52 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 51 +; CHECK-NEXT: - Index: 53 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f53 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 52 +; CHECK-NEXT: - Index: 54 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f54 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 53 +; CHECK-NEXT: - Index: 55 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f55 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 54 +; CHECK-NEXT: - Index: 56 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f56 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 55 +; CHECK-NEXT: - Index: 57 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f57 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 56 +; CHECK-NEXT: - Index: 58 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f58 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 57 +; CHECK-NEXT: - Index: 59 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f59 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 58 +; CHECK-NEXT: - Index: 60 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f60 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 59 +; CHECK-NEXT: - Index: 61 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f61 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 60 +; CHECK-NEXT: - Index: 62 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f62 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 61 +; CHECK-NEXT: - Index: 63 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f63 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 62 +; CHECK-NEXT: - Index: 64 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f64 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 63 +; CHECK-NEXT: - Index: 65 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f65 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 64 +; CHECK-NEXT: - Index: 66 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f66 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 65 +; CHECK-NEXT: - Index: 67 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f67 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 66 +; CHECK-NEXT: - Index: 68 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f68 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 67 +; CHECK-NEXT: - Index: 69 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f69 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 68 +; CHECK-NEXT: - Index: 70 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f70 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 69 +; CHECK-NEXT: - Index: 71 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f71 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 70 +; CHECK-NEXT: - Index: 72 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f72 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 71 +; CHECK-NEXT: - Index: 73 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f73 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 72 +; CHECK-NEXT: - Index: 74 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f74 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 73 +; CHECK-NEXT: - Index: 75 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f75 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 74 +; CHECK-NEXT: - Index: 76 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f76 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 75 +; CHECK-NEXT: - Index: 77 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f77 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 76 +; CHECK-NEXT: - Index: 78 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f78 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 77 +; CHECK-NEXT: - Index: 79 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f79 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 78 +; CHECK-NEXT: - Index: 80 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f80 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 79 +; CHECK-NEXT: - Index: 81 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f81 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 80 +; CHECK-NEXT: - Index: 82 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f82 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 81 +; CHECK-NEXT: - Index: 83 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f83 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 82 +; CHECK-NEXT: - Index: 84 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f84 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 83 +; CHECK-NEXT: - Index: 85 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f85 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 84 +; CHECK-NEXT: - Index: 86 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f86 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 85 +; CHECK-NEXT: - Index: 87 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f87 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 86 +; CHECK-NEXT: - Index: 88 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f88 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 87 +; CHECK-NEXT: - Index: 89 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f89 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 88 +; CHECK-NEXT: - Index: 90 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f90 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 89 +; CHECK-NEXT: - Index: 91 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f91 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 90 +; CHECK-NEXT: - Index: 92 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f92 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 91 +; CHECK-NEXT: - Index: 93 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f93 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 92 +; CHECK-NEXT: - Index: 94 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f94 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 93 +; CHECK-NEXT: - Index: 95 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f95 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 94 +; CHECK-NEXT: - Index: 96 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f96 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 95 +; CHECK-NEXT: - Index: 97 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f97 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 96 +; CHECK-NEXT: - Index: 98 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f98 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 97 +; CHECK-NEXT: - Index: 99 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f99 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 98 +; CHECK-NEXT: - Index: 100 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f100 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 99 +; CHECK-NEXT: - Index: 101 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f101 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 100 +; CHECK-NEXT: - Index: 102 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f102 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 101 +; CHECK-NEXT: - Index: 103 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f103 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 102 +; CHECK-NEXT: - Index: 104 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f104 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 103 +; CHECK-NEXT: - Index: 105 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f105 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 104 +; CHECK-NEXT: - Index: 106 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f106 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 105 +; CHECK-NEXT: - Index: 107 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f107 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 106 +; CHECK-NEXT: - Index: 108 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f108 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 107 +; CHECK-NEXT: - Index: 109 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f109 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 108 +; CHECK-NEXT: - Index: 110 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f110 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 109 +; CHECK-NEXT: - Index: 111 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f111 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 110 +; CHECK-NEXT: - Index: 112 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f112 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 111 +; CHECK-NEXT: - Index: 113 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f113 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 112 +; CHECK-NEXT: - Index: 114 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f114 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 113 +; CHECK-NEXT: - Index: 115 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f115 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 114 +; CHECK-NEXT: - Index: 116 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f116 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 115 +; CHECK-NEXT: - Index: 117 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f117 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 116 +; CHECK-NEXT: - Index: 118 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f118 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 117 +; CHECK-NEXT: - Index: 119 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f119 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 118 +; CHECK-NEXT: - Index: 120 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f120 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 119 +; CHECK-NEXT: - Index: 121 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f121 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 120 +; CHECK-NEXT: - Index: 122 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f122 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 121 +; CHECK-NEXT: - Index: 123 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f123 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 122 +; CHECK-NEXT: - Index: 124 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f124 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 123 +; CHECK-NEXT: - Index: 125 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f125 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 124 +; CHECK-NEXT: - Index: 126 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f126 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 125 +; CHECK-NEXT: - Index: 127 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f127 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 126 +; CHECK-NEXT: - Index: 128 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f128 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 127 +; CHECK-NEXT: - Index: 129 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: g0 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Segment: 0 +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: - Index: 130 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: f129 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 128 +; CHECK-NEXT: - Index: 131 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: func +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 129 ; CHECK-NEXT: SegmentInfo: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: .data.g0 diff --git a/test/wasm/reloc-addend.ll b/test/wasm/reloc-addend.ll new file mode 100644 index 000000000000..f678a3d4b617 --- /dev/null +++ b/test/wasm/reloc-addend.ll @@ -0,0 +1,19 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -r -o %t.wasm %t.o +; RUN: obj2yaml %t.wasm | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +@foo = hidden global [76 x i32] zeroinitializer, align 16 + +; bar points to the 16th element, which happens to be 64 bytes +; This generates an addend of 64 which, is the value at which +; signed and unsigned LEB encodes will differ. +@bar = hidden local_unnamed_addr global i32* getelementptr inbounds ([76 x i32], [76 x i32]* @foo, i32 0, i32 16), align 4 + +; CHECK: - Type: DATA +; CHECK-NEXT: Relocations: +; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Offset: 0x0000013D +; CHECK-NEXT: Addend: 64 diff --git a/test/wasm/relocatable.ll b/test/wasm/relocatable.ll index d9d2e02bdabb..4e8a887f31d8 100644 --- a/test/wasm/relocatable.ll +++ b/test/wasm/relocatable.ll @@ -1,22 +1,34 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/hello.ll -o %t.hello.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -r -o %t.wasm %t.hello.o %t.o +; RUN: llc -filetype=obj %p/Inputs/hello.ll -o %t.hello.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -r -o %t.wasm %t.hello.o %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + ; Function Attrs: nounwind define hidden i32 @my_func() local_unnamed_addr { entry: %call = tail call i32 @foo_import() + %call2 = tail call i32 @bar_import() ret i32 1 } declare i32 @foo_import() local_unnamed_addr +declare extern_weak i32 @bar_import() local_unnamed_addr @data_import = external global i64 @func_addr1 = hidden global i32()* @my_func, align 4 @func_addr2 = hidden global i32()* @foo_import, align 4 +@func_addr3 = hidden global i32()* @bar_import, align 4 @data_addr1 = hidden global i64* @data_import, align 8 +$func_comdat = comdat any +@data_comdat = weak_odr constant [3 x i8] c"abc", comdat($func_comdat) +define linkonce_odr i32 @func_comdat() comdat { +entry: + ret i32 ptrtoint ([3 x i8]* @data_comdat to i32) +} + ; CHECK: --- !WASM ; CHECK-NEXT: FileHeader: ; CHECK-NEXT: Version: 0x00000001 @@ -26,115 +38,86 @@ declare i32 @foo_import() local_unnamed_addr ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: -; CHECK-NEXT: - I32 ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: IMPORT ; CHECK-NEXT: Imports: ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: puts ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: SigIndex: 1 +; CHECK-NEXT: SigIndex: 0 ; CHECK-NEXT: - Module: env ; CHECK-NEXT: Field: foo_import ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: SigIndex: 2 +; CHECK-NEXT: SigIndex: 1 ; CHECK-NEXT: - Module: env -; CHECK-NEXT: Field: data_import -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: GlobalType: I32 -; CHECK-NEXT: GlobalMutable: false +; CHECK-NEXT: Field: bar_import +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: SigIndex: 1 ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 2 ] +; CHECK-NEXT: FunctionTypes: [ 2, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] -; CHECK-NEXT: Initial: 0x00000002 -; CHECK-NEXT: Maximum: 0x00000002 +; CHECK-NEXT: Initial: 0x00000004 +; CHECK-NEXT: Maximum: 0x00000004 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: ; CHECK-NEXT: - Initial: 0x00000001 -; CHECK-NEXT: - Type: GLOBAL -; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: false -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 0 -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: false -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 8 -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: false -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 12 -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: false -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 16 -; CHECK-NEXT: - Type: EXPORT -; CHECK-NEXT: Exports: -; CHECK-NEXT: - Name: hello -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: my_func -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 -; CHECK-NEXT: - Name: hello_str -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Name: func_addr1 -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 2 -; CHECK-NEXT: - Name: func_addr2 -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 3 -; CHECK-NEXT: - Name: data_addr1 -; CHECK-NEXT: Kind: GLOBAL -; CHECK-NEXT: Index: 4 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 0 -; CHECK-NEXT: Functions: [ 3, 1 ] +; CHECK-NEXT: Value: 1 +; CHECK-NEXT: Functions: [ 4, 1, 2 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB ; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000004 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: Offset: 0x0000000A ; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 4 ; CHECK-NEXT: Offset: 0x00000013 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; CHECK-NEXT: Index: 5 +; CHECK-NEXT: Offset: 0x0000001A +; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_SLEB +; CHECK-NEXT: Index: 7 +; CHECK-NEXT: Offset: 0x00000026 ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4180808080001080808080000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1081808080001A41010B +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1081808080001A1082808080001A41010B +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 419C808080000B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: Offset: 0x00000012 ; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 4 ; CHECK-NEXT: Offset: 0x0000001B -; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_I32 +; CHECK-NEXT: Index: 5 ; CHECK-NEXT: Offset: 0x00000024 +; CHECK-NEXT: - Type: R_WEBASSEMBLY_MEMORY_ADDR_I32 +; CHECK-NEXT: Index: 12 +; CHECK-NEXT: Offset: 0x0000002D ; CHECK-NEXT: Segments: ; CHECK-NEXT: - SectionOffset: 6 ; CHECK-NEXT: MemoryIndex: 0 @@ -147,39 +130,137 @@ declare i32 @foo_import() local_unnamed_addr ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 8 -; CHECK-NEXT: Content: '00000000' +; CHECK-NEXT: Content: '01000000' ; CHECK-NEXT: - SectionOffset: 27 ; CHECK-NEXT: MemoryIndex: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 12 -; CHECK-NEXT: Content: '01000000' +; CHECK-NEXT: Content: '02000000' ; CHECK-NEXT: - SectionOffset: 36 ; CHECK-NEXT: MemoryIndex: 0 ; CHECK-NEXT: Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 16 -; CHECK-NEXT: Content: FFFFFFFF +; CHECK-NEXT: Content: '03000000' +; CHECK-NEXT: - SectionOffset: 45 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 24 +; CHECK-NEXT: Content: '00000000' +; CHECK-NEXT: - SectionOffset: 54 +; CHECK-NEXT: MemoryIndex: 0 +; CHECK-NEXT: Offset: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 28 +; CHECK-NEXT: Content: '616263' ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 20 +; CHECK-NEXT: Version: 1 +; CHECK-NEXT: SymbolTable: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: hello +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: Function: 3 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: hello_str +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Segment: 0 +; CHECK-NEXT: Size: 7 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: puts +; CHECK-NEXT: Flags: [ UNDEFINED ] +; CHECK-NEXT: Function: 0 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: my_func +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: Function: 4 +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: foo_import +; CHECK-NEXT: Flags: [ UNDEFINED ] +; CHECK-NEXT: Function: 1 +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: bar_import +; CHECK-NEXT: Flags: [ BINDING_WEAK, UNDEFINED ] +; CHECK-NEXT: Function: 2 +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: func_comdat +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: Function: 5 +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: data_comdat +; CHECK-NEXT: Flags: [ BINDING_WEAK ] +; CHECK-NEXT: Segment: 5 +; CHECK-NEXT: Size: 3 +; CHECK-NEXT: - Index: 8 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: func_addr1 +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: Segment: 1 +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: - Index: 9 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: func_addr2 +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: Segment: 2 +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: - Index: 10 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: func_addr3 +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: Segment: 3 +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: - Index: 11 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: data_addr1 +; CHECK-NEXT: Flags: [ VISIBILITY_HIDDEN ] +; CHECK-NEXT: Segment: 4 +; CHECK-NEXT: Size: 4 +; CHECK-NEXT: - Index: 12 +; CHECK-NEXT: Kind: DATA +; CHECK-NEXT: Name: data_import +; CHECK-NEXT: Flags: [ UNDEFINED ] ; CHECK-NEXT: SegmentInfo: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: Name: .rodata.hello_str ; CHECK-NEXT: Alignment: 1 -; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: .data.func_addr1 ; CHECK-NEXT: Alignment: 4 -; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Index: 2 ; CHECK-NEXT: Name: .data.func_addr2 ; CHECK-NEXT: Alignment: 4 -; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Flags: [ ] ; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: .data.func_addr3 +; CHECK-NEXT: Alignment: 4 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Name: .data.data_addr1 ; CHECK-NEXT: Alignment: 8 -; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: .rodata.data_comdat +; CHECK-NEXT: Alignment: 1 +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Comdats: +; CHECK-NEXT: - Name: func_comdat +; CHECK-NEXT: Entries: +; CHECK-NEXT: - Kind: FUNCTION +; CHECK-NEXT: Index: 5 +; CHECK-NEXT: - Kind: DATA +; CHECK-NEXT: Index: 5 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: @@ -188,7 +269,11 @@ declare i32 @foo_import() local_unnamed_addr ; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: foo_import ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: hello +; CHECK-NEXT: Name: bar_import ; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: hello +; CHECK-NEXT: - Index: 4 ; CHECK-NEXT: Name: my_func +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: func_comdat ; CHECK-NEXT: ... diff --git a/test/wasm/responsefile.test b/test/wasm/responsefile.test new file mode 100644 index 000000000000..11f805997b26 --- /dev/null +++ b/test/wasm/responsefile.test @@ -0,0 +1,10 @@ +RUN: llc -filetype=obj -o %t.o %p/Inputs/ret32.ll + +RUN: echo "%/t.o -o %/t.wasm -e ret32" > %t.rsp +RUN: wasm-ld @%t.rsp --initial-memory=655360 +RUN: llvm-readobj --sections %t.wasm | FileCheck %s +CHECK: InitialPages: 10 + +RUN: echo "blah\foo" > %t.rsp +RUN: not wasm-ld @%t.rsp 2>&1 | FileCheck --check-prefix=ESCAPE %s +ESCAPE: error: cannot open blahfoo: {{[Nn]}}o such file or directory diff --git a/test/wasm/signature-mismatch-weak.ll b/test/wasm/signature-mismatch-weak.ll new file mode 100644 index 000000000000..dbf73d1aa46e --- /dev/null +++ b/test/wasm/signature-mismatch-weak.ll @@ -0,0 +1,18 @@ +; RUN: llc -filetype=obj %p/Inputs/weak-symbol1.ll -o %t.weak.o +; RUN: llc -filetype=obj %p/Inputs/strong-symbol.ll -o %t.strong.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.o %t.strong.o %t.weak.o 2>&1 | FileCheck %s + +target triple = "wasm32-unknown-unknown" + +declare i32 @weakFn() local_unnamed_addr + +define void @_start() local_unnamed_addr { +entry: + %call = call i32 @weakFn() + ret void +} + +; CHECK: warning: function signature mismatch: weakFn +; CHECK-NEXT: >>> defined as () -> I32 in {{.*}}signature-mismatch-weak.ll.tmp.o +; CHECK-NEXT: >>> defined as () -> I64 in {{.*}}signature-mismatch-weak.ll.tmp.strong.o diff --git a/test/wasm/signature-mismatch.ll b/test/wasm/signature-mismatch.ll index 842b8289afd9..d750d4f6b359 100644 --- a/test/wasm/signature-mismatch.ll +++ b/test/wasm/signature-mismatch.ll @@ -1,6 +1,12 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.main.o -; RUN: not lld -flavor wasm --check-signatures -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s +; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: llc -filetype=obj %s -o %t.main.o +; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.main.o %t.ret32.o 2>&1 | FileCheck %s +; Run the test again by with the object files in the other order to verify +; the check works when the undefined symbol is resolved by an existing defined +; one. +; RUN: not wasm-ld --fatal-warnings -o %t.wasm %t.ret32.o %t.main.o 2>&1 | FileCheck %s -check-prefix=REVERSE + +target triple = "wasm32-unknown-unknown" ; Function Attrs: nounwind define hidden void @_start() local_unnamed_addr #0 { @@ -14,3 +20,7 @@ declare i32 @ret32(i32, i64, i32) local_unnamed_addr #1 ; CHECK: error: function signature mismatch: ret32 ; CHECK-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o ; CHECK-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o + +; REVERSE: error: function signature mismatch: ret32 +; REVERSE-NEXT: >>> defined as (F32) -> I32 in {{.*}}.ret32.o +; REVERSE-NEXT: >>> defined as (I32, I64, I32) -> I32 in {{.*}}.main.o diff --git a/test/wasm/stack-first.test b/test/wasm/stack-first.test new file mode 100644 index 000000000000..71d1e9dde858 --- /dev/null +++ b/test/wasm/stack-first.test @@ -0,0 +1,42 @@ +; Test that the --stack-first option places the stack at the start of linear +; memory. In this case the --stack-first option is being passed along with a +; stack size of 512. This means (since the stack grows down) the stack pointer +; global should be initialized to 512. + +RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o + +RUN: wasm-ld -z stack-size=512 --stack-first --allow-undefined -o %t.wasm %t.o +RUN: obj2yaml %t.wasm | FileCheck %s + +CHECK: - Type: GLOBAL +CHECK-NEXT: Globals: +CHECK-NEXT: - Index: 0 +CHECK-NEXT: Type: I32 +CHECK-NEXT: Mutable: true +CHECK-NEXT: InitExpr: +CHECK-NEXT: Opcode: I32_CONST +CHECK-NEXT: Value: 512 +CHECK-NEXT: - Index: 1 +CHECK-NEXT: Type: I32 +CHECK-NEXT: Mutable: false +CHECK-NEXT: InitExpr: +CHECK-NEXT: Opcode: I32_CONST +CHECK-NEXT: Value: 512 +CHECK-NEXT: - Index: 2 +CHECK-NEXT: Type: I32 +CHECK-NEXT: Mutable: false +CHECK-NEXT: InitExpr: +CHECK-NEXT: Opcode: I32_CONST +CHECK-NEXT: Value: 512 +CHECK-NEXT: - Type: EXPORT +CHECK-NEXT: Exports: +CHECK-NEXT: - Name: memory +CHECK-NEXT: Kind: MEMORY +CHECK-NEXT: Index: 0 +CHECK-NEXT: - Name: __heap_base +CHECK-NEXT: Kind: GLOBAL +CHECK-NEXT: Index: 1 +CHECK-NEXT: - Name: __data_end +CHECK-NEXT: Kind: GLOBAL +CHECK-NEXT: Index: 2 + diff --git a/test/wasm/stack-pointer.ll b/test/wasm/stack-pointer.ll index c5be94af4e39..888c938881de 100644 --- a/test/wasm/stack-pointer.ll +++ b/test/wasm/stack-pointer.ll @@ -1,9 +1,11 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm --emit-relocs -o %t.wasm %t.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld --relocatable -o %t.wasm %t.o ; RUN: obj2yaml %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + ; Function Attrs: nounwind -define hidden i32 @_start() local_unnamed_addr { +define i32 @_start() local_unnamed_addr { entry: %retval = alloca i32, align 4 ret i32 0 @@ -18,6 +20,13 @@ entry: ; CHECK-NEXT: - Index: 0 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Type: IMPORT +; CHECK-NEXT: Imports: +; CHECK-NEXT: - Module: env +; CHECK-NEXT: Field: __stack_pointer +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: GlobalType: I32 +; CHECK-NEXT: GlobalMutable: true ; CHECK-NEXT: - Type: FUNCTION ; CHECK-NEXT: FunctionTypes: [ 0 ] ; CHECK-NEXT: - Type: TABLE @@ -29,33 +38,30 @@ entry: ; CHECK-NEXT: Maximum: 0x00000001 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: -; CHECK-NEXT: - Initial: 0x00000002 -; CHECK-NEXT: - Type: GLOBAL -; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 -; CHECK-NEXT: Mutable: true -; CHECK-NEXT: InitExpr: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 66560 -; CHECK-NEXT: - Type: EXPORT -; CHECK-NEXT: Exports: -; CHECK-NEXT: - Name: memory -; CHECK-NEXT: Kind: MEMORY -; CHECK-NEXT: Index: 0 -; CHECK-NEXT: - Name: _start -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Initial: 0x00000000 ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Relocations: ; CHECK-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: Offset: 0x00000004 ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 23808080800041106B1A41000B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: Version: 1 +; CHECK-NEXT: SymbolTable: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Name: _start +; CHECK-NEXT: Flags: [ ] +; CHECK-NEXT: Function: 0 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Name: __stack_pointer +; CHECK-NEXT: Flags: [ UNDEFINED ] +; CHECK-NEXT: Global: 0 ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: diff --git a/test/wasm/strip-debug.test b/test/wasm/strip-debug.test index ca4b02a4a5fb..be5ba700e258 100644 --- a/test/wasm/strip-debug.test +++ b/test/wasm/strip-debug.test @@ -1,5 +1,5 @@ -RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -RUN: lld -flavor wasm --strip-debug --entry=ret32 -o %t.wasm %t.ret32.o +RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.start.o +RUN: wasm-ld --strip-debug -o %t.wasm %t.start.o RUN: obj2yaml %t.wasm | FileCheck %s # Check that there is no name section diff --git a/test/wasm/symbol-type-mismatch.ll b/test/wasm/symbol-type-mismatch.ll index b7e37c142549..4738c4bd00b9 100644 --- a/test/wasm/symbol-type-mismatch.ll +++ b/test/wasm/symbol-type-mismatch.ll @@ -1,9 +1,11 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -; RUN: not lld -flavor wasm -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s +; RUN: llc -filetype=obj %s -o %t.o +; RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +; RUN: not wasm-ld -o %t.wasm %t.o %t.ret32.o 2>&1 | FileCheck %s + +target triple = "wasm32-unknown-unknown" @ret32 = extern_weak global i32, align 4 ; CHECK: error: symbol type mismatch: ret32 -; CHECK: >>> defined as Global in {{.*}}symbol-type-mismatch.ll.tmp.o -; CHECK: >>> defined as Function in {{.*}}.ret32.o +; CHECK: >>> defined as WASM_SYMBOL_TYPE_DATA in {{.*}}symbol-type-mismatch.ll.tmp.o +; CHECK: >>> defined as WASM_SYMBOL_TYPE_FUNCTION in {{.*}}.ret32.o diff --git a/test/wasm/undefined-entry.test b/test/wasm/undefined-entry.test index 55f7d6fb7843..ffa079ca638b 100644 --- a/test/wasm/undefined-entry.test +++ b/test/wasm/undefined-entry.test @@ -1,4 +1,11 @@ -RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/ret32.ll -o %t.ret32.o -RUN: not lld -flavor wasm -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s +RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +RUN: not wasm-ld -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s +RUN: not wasm-ld -entry=foo -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-CUSTOM +RUN: not wasm-ld --allow-undefined -o %t.wasm %t.ret32.o 2>&1 | FileCheck %s -check-prefix=CHECK-ALLOW CHECK: error: undefined symbol: _start +CHECK-CUSTOM: error: undefined symbol: foo +CHECK-ALLOW: error: entry symbol not defined (pass --no-entry to supress): +_start + +RUN: wasm-ld --no-entry -o %t.wasm %t.ret32.o diff --git a/test/wasm/undefined-weak-call.ll b/test/wasm/undefined-weak-call.ll new file mode 100644 index 000000000000..c13f5c1ae3f1 --- /dev/null +++ b/test/wasm/undefined-weak-call.ll @@ -0,0 +1,120 @@ +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld --no-entry --print-gc-sections %t.o \ +; RUN: -o %t.wasm 2>&1 | FileCheck -check-prefix=CHECK-GC %s +; RUN: obj2yaml %t.wasm | FileCheck %s + +; Check that calling an undefined weak function generates an appropriate stub +; that will fail at runtime with "unreachable". + +target triple = "wasm32-unknown-unknown" + +declare extern_weak void @weakFunc1() +declare extern_weak void @weakFunc2() ; same signature +declare extern_weak void @weakFunc3(i32 %arg) ; different +declare extern_weak void @weakFunc4() ; should be GC'd as not called + +; CHECK-GC: removing unused section {{.*}}:(weakFunc4) + +define i32 @callWeakFuncs() { + call void @weakFunc1() + call void @weakFunc2() + call void @weakFunc3(i32 2) + %addr1 = ptrtoint void ()* @weakFunc1 to i32 + %addr4 = ptrtoint void ()* @weakFunc4 to i32 + %sum = add i32 %addr1, %addr4 + ret i32 %sum +} + +; CHECK: --- !WASM +; CHECK-NEXT: FileHeader: +; CHECK-NEXT: Version: 0x00000001 +; CHECK-NEXT: Sections: +; CHECK-NEXT: - Type: TYPE +; CHECK-NEXT: Signatures: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - I32 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Type: FUNCTION +; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 1, 2 ] +; CHECK-NEXT: - Type: TABLE +; CHECK-NEXT: Tables: +; CHECK-NEXT: - ElemType: ANYFUNC +; CHECK-NEXT: Limits: +; CHECK-NEXT: Flags: [ HAS_MAX ] +; CHECK-NEXT: Initial: 0x00000001 +; CHECK-NEXT: Maximum: 0x00000001 +; CHECK-NEXT: - Type: MEMORY +; CHECK-NEXT: Memories: +; CHECK-NEXT: - Initial: 0x00000002 +; CHECK-NEXT: - Type: GLOBAL +; CHECK-NEXT: Globals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: true +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 +; CHECK-NEXT: - Type: EXPORT +; CHECK-NEXT: Exports: +; CHECK-NEXT: - Name: memory +; CHECK-NEXT: Kind: MEMORY +; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 +; CHECK-NEXT: - Name: callWeakFuncs +; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 4 +; CHECK-NEXT: - Type: CODE +; CHECK-NEXT: Functions: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 000B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 000B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 000B +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 10818080800010828080800041021083808080004180808080004180808080006A0B +; CHECK-NEXT: - Type: CUSTOM +; CHECK-NEXT: Name: name +; CHECK-NEXT: FunctionNames: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Name: undefined function weakFunc1 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: undefined function weakFunc2 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Name: undefined function weakFunc3 +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: callWeakFuncs +; CHECK-NEXT: ... diff --git a/test/wasm/undefined.ll b/test/wasm/undefined.ll index 249afe243b07..7d2161d2bcc6 100644 --- a/test/wasm/undefined.ll +++ b/test/wasm/undefined.ll @@ -1,13 +1,19 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm --allow-undefined -o %t.wasm %t.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld --allow-undefined -o %t.wasm %t.o -; Fails due to undefined 'foo' -; RUN: not lld -flavor wasm -o %t.wasm %t.o 2>&1 | FileCheck %s +; Fails due to undefined 'foo' and also 'baz' +; RUN: not wasm-ld --undefined=baz -o %t.wasm %t.o 2>&1 | FileCheck %s ; CHECK: error: {{.*}}.o: undefined symbol: foo +; CHECK: error: undefined symbol: baz -; But succeeds if we pass a file containing 'foo' as --allow-undefined-file. +; Succeeds if we pass a file containing 'foo' as --allow-undefined-file. ; RUN: echo 'foo' > %t.txt -; RUN: lld -flavor wasm --allow-undefined-file=%t.txt -o %t.wasm %t.o +; RUN: wasm-ld --allow-undefined-file=%t.txt -o %t.wasm %t.o + +; Succeeds even if a missing symbol is added via --export +; RUN: wasm-ld --allow-undefined --export=xxx -o %t.wasm %t.o + +target triple = "wasm32-unknown-unknown" ; Takes the address of the external foo() resulting in undefined external @bar = hidden local_unnamed_addr global i8* bitcast (i32 ()* @foo to i8*), align 4 diff --git a/test/wasm/version.ll b/test/wasm/version.ll index 2ae65d9ad37f..ea5b41ff9b0d 100644 --- a/test/wasm/version.ll +++ b/test/wasm/version.ll @@ -1,7 +1,9 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -o %t.wasm %t.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -o %t.wasm %t.o ; RUN: llvm-readobj -file-headers %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + define hidden void @_start() local_unnamed_addr #0 { entry: ret void diff --git a/test/wasm/visibility-hidden.ll b/test/wasm/visibility-hidden.ll index 9960b952492b..af973df0751a 100644 --- a/test/wasm/visibility-hidden.ll +++ b/test/wasm/visibility-hidden.ll @@ -1,12 +1,14 @@ -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/hidden.ll -o %t2.o +; RUN: llc -filetype=obj -o %t.o %s +; RUN: llc -filetype=obj %S/Inputs/hidden.ll -o %t2.o ; RUN: llvm-ar rcs %t2.a %t2.o -; RUN: lld -flavor wasm %t.o %t2.a -o %t.wasm +; RUN: wasm-ld %t.o %t2.a -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s ; Test that hidden symbols are not exported, whether pulled in from an archive ; or directly. +target triple = "wasm32-unknown-unknown" + define hidden i32 @objectHidden() { entry: ret i32 0 @@ -20,13 +22,13 @@ entry: declare i32 @archiveHidden() declare i32 @archiveDefault() -define i32 @_start() { +define void @_start() { entry: %call1 = call i32 @objectHidden() %call2 = call i32 @objectDefault() %call3 = call i32 @archiveHidden() %call4 = call i32 @archiveDefault() - ret i32 0 + ret void } ; CHECK: - Type: EXPORT @@ -34,13 +36,19 @@ entry: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: objectDefault +; CHECK-NEXT: Kind: FUNCTION ; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: archiveDefault ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 4 -; CHECK-NEXT: - Name: objectDefault -; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 5 ; CHECK-NEXT: - Type: diff --git a/test/wasm/weak-alias-overide.ll b/test/wasm/weak-alias-overide.ll index c2f673a52725..8b98f3347a1c 100644 --- a/test/wasm/weak-alias-overide.ll +++ b/test/wasm/weak-alias-overide.ll @@ -1,11 +1,13 @@ -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o -; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm +; RUN: llc -filetype=obj -o %t.o %s +; RUN: llc -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o +; RUN: wasm-ld %t.o %t2.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s ; Test that the strongly defined alias_fn from this file is used both here ; and in call_alias. +target triple = "wasm32-unknown-unknown" + define i32 @alias_fn() local_unnamed_addr #1 { ret i32 1 } @@ -24,13 +26,13 @@ entry: ; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: ReturnType: I32 +; CHECK-NEXT: ReturnType: NORESULT ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 0, 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 0, 1, 1, 1, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -43,81 +45,109 @@ entry: ; CHECK-NEXT: - Initial: 0x00000002 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: alias_fn ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: direct_fn ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: call_direct ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 +; CHECK-NEXT: Index: 4 ; CHECK-NEXT: - Name: call_alias ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 4 +; CHECK-NEXT: Index: 5 ; CHECK-NEXT: - Name: call_alias_ptr ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 5 +; CHECK-NEXT: Index: 6 ; CHECK-NEXT: - Name: call_direct_ptr ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 6 +; CHECK-NEXT: Index: 7 ; CHECK-NEXT: - Type: ELEM -; CHECK-NEXT: Segments: -; CHECK-NEXT: - Offset: +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 0, 2 ] +; CHECK-NEXT: Functions: [ 1, 3 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41010B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1080808080001A0B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1081808080001A0B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1082808080000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1080808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1083808080000B +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1081808080000B +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Locals: ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Count: 2 -; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081080808080002101200041106A24808080800020010B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B +; CHECK-NEXT: - Index: 7 +; CHECK-NEXT: Locals: ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Count: 2 -; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081082808080002101200041106A24808080800020010B -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081083808080002101200041106A24808080800020010B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: alias_fn +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: _start +; CHECK-NEXT: Name: alias_fn ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: direct_fn +; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Name: call_direct +; CHECK-NEXT: Name: direct_fn ; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: Name: call_alias +; CHECK-NEXT: Name: call_direct ; CHECK-NEXT: - Index: 5 -; CHECK-NEXT: Name: call_alias_ptr +; CHECK-NEXT: Name: call_alias ; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Name: call_alias_ptr +; CHECK-NEXT: - Index: 7 ; CHECK-NEXT: Name: call_direct_ptr ; CHECK-NEXT: ... diff --git a/test/wasm/weak-alias.ll b/test/wasm/weak-alias.ll index 6a345ec0c63e..227906a55504 100644 --- a/test/wasm/weak-alias.ll +++ b/test/wasm/weak-alias.ll @@ -1,17 +1,19 @@ -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o -; RUN: lld -flavor wasm %t.o %t2.o -o %t.wasm +; RUN: llc -filetype=obj -o %t.o %s +; RUN: llc -filetype=obj %S/Inputs/weak-alias.ll -o %t2.o +; RUN: wasm-ld %t.o %t2.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s ; Test that weak aliases (alias_fn is a weak alias of direct_fn) are linked correctly +target triple = "wasm32-unknown-unknown" + declare i32 @alias_fn() local_unnamed_addr #1 ; Function Attrs: nounwind uwtable -define i32 @_start() local_unnamed_addr #1 { +define void @_start() local_unnamed_addr #1 { entry: %call = tail call i32 @alias_fn() #2 - ret i32 %call + ret void } ; CHECK: --- !WASM @@ -21,93 +23,288 @@ entry: ; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] -; CHECK-NEXT: Initial: 0x00000003 -; CHECK-NEXT: Maximum: 0x00000003 +; CHECK-NEXT: Initial: 0x00000002 +; CHECK-NEXT: Maximum: 0x00000002 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: ; CHECK-NEXT: - Initial: 0x00000002 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: alias_fn ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: direct_fn ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: call_direct ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: call_alias ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 3 +; CHECK-NEXT: Index: 4 ; CHECK-NEXT: - Name: call_alias_ptr ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 4 +; CHECK-NEXT: Index: 5 ; CHECK-NEXT: - Name: call_direct_ptr ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 5 +; CHECK-NEXT: Index: 6 ; CHECK-NEXT: - Type: ELEM -; CHECK-NEXT: Segments: -; CHECK-NEXT: - Offset: +; CHECK-NEXT: Segments: +; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 1, 1 ] +; CHECK-NEXT: Functions: [ 2 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1081808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1082808080001A0B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1081808080000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1081808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1082808080000B +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1082808080000B +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Count: 2 -; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081082808080002101200041106A24808080800020010B +; CHECK-NEXT: - Index: 6 +; CHECK-NEXT: Locals: ; CHECK-NEXT: - Type: I32 ; CHECK-NEXT: Count: 2 -; CHECK-NEXT: Body: 23808080800041106B220024808080800020004182808080003602081081808080002101200041106A24808080800020010B -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081082808080002101200041106A24808080800020010B ; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 -; CHECK-NEXT: Name: _start +; CHECK-NEXT: Name: __wasm_call_ctors ; CHECK-NEXT: - Index: 1 -; CHECK-NEXT: Name: direct_fn +; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 2 -; CHECK-NEXT: Name: call_direct +; CHECK-NEXT: Name: direct_fn ; CHECK-NEXT: - Index: 3 -; CHECK-NEXT: Name: call_alias +; CHECK-NEXT: Name: call_direct ; CHECK-NEXT: - Index: 4 -; CHECK-NEXT: Name: call_alias_ptr +; CHECK-NEXT: Name: call_alias ; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Name: call_alias_ptr +; CHECK-NEXT: - Index: 6 ; CHECK-NEXT: Name: call_direct_ptr ; CHECK-NEXT: ... + +; RUN: wasm-ld --relocatable %t.o %t2.o -o %t.reloc.o +; RUN: obj2yaml %t.reloc.o | FileCheck %s -check-prefix=RELOC + +; RELOC: --- !WASM +; RELOC-NEXT: FileHeader: +; RELOC-NEXT: Version: 0x00000001 +; RELOC-NEXT: Sections: +; RELOC-NEXT: - Type: TYPE +; RELOC-NEXT: Signatures: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: ReturnType: NORESULT +; RELOC-NEXT: ParamTypes: +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: ReturnType: I32 +; RELOC-NEXT: ParamTypes: +; RELOC-NEXT: - Type: IMPORT +; RELOC-NEXT: Imports: +; RELOC-NEXT: - Module: env +; RELOC-NEXT: Field: __stack_pointer +; RELOC-NEXT: Kind: GLOBAL +; RELOC-NEXT: GlobalType: I32 +; RELOC-NEXT: GlobalMutable: true +; RELOC-NEXT: - Type: FUNCTION +; RELOC-NEXT: FunctionTypes: [ 0, 1, 1, 1, 1, 1 ] +; RELOC-NEXT: - Type: TABLE +; RELOC-NEXT: Tables: +; RELOC-NEXT: - ElemType: ANYFUNC +; RELOC-NEXT: Limits: +; RELOC-NEXT: Flags: [ HAS_MAX ] +; RELOC-NEXT: Initial: 0x00000002 +; RELOC-NEXT: Maximum: 0x00000002 +; RELOC-NEXT: - Type: MEMORY +; RELOC-NEXT: Memories: +; RELOC-NEXT: - Initial: 0x00000000 +; RELOC-NEXT: - Type: ELEM +; RELOC-NEXT: Segments: +; RELOC-NEXT: - Offset: +; RELOC-NEXT: Opcode: I32_CONST +; RELOC-NEXT: Value: 1 +; RELOC-NEXT: Functions: [ 1 ] +; RELOC-NEXT: - Type: CODE +; RELOC-NEXT: Relocations: +; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; RELOC-NEXT: Index: 4 +; RELOC-NEXT: Offset: 0x00000004 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; RELOC-NEXT: Index: 1 +; RELOC-NEXT: Offset: 0x00000013 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; RELOC-NEXT: Index: 4 +; RELOC-NEXT: Offset: 0x0000001C +; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x00000027 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x00000032 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 4 +; RELOC-NEXT: Offset: 0x0000003A +; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; RELOC-NEXT: Index: 4 +; RELOC-NEXT: Offset: 0x00000043 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x00000050 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x0000005D +; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x00000068 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_TABLE_INDEX_SLEB +; RELOC-NEXT: Index: 1 +; RELOC-NEXT: Offset: 0x00000070 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_FUNCTION_INDEX_LEB +; RELOC-NEXT: Index: 1 +; RELOC-NEXT: Offset: 0x00000079 +; RELOC-NEXT: - Type: R_WEBASSEMBLY_GLOBAL_INDEX_LEB +; RELOC-NEXT: Index: 6 +; RELOC-NEXT: Offset: 0x00000086 +; RELOC-NEXT: Functions: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 1081808080001A0B +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 41000B +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 1081808080000B +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Locals: +; RELOC-NEXT: Body: 1081808080000B +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Locals: +; RELOC-NEXT: - Type: I32 +; RELOC-NEXT: Count: 2 +; RELOC-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Locals: +; RELOC-NEXT: - Type: I32 +; RELOC-NEXT: Count: 2 +; RELOC-NEXT: Body: 23808080800041106B220024808080800020004181808080003602081081808080002101200041106A24808080800020010B +; RELOC-NEXT: - Type: CUSTOM +; RELOC-NEXT: Name: linking +; RELOC-NEXT: Version: 1 +; RELOC-NEXT: SymbolTable: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: _start +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 0 +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: direct_fn +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 1 +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: call_direct +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 2 +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: call_alias +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 3 +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: alias_fn +; RELOC-NEXT: Flags: [ BINDING_WEAK ] +; RELOC-NEXT: Function: 1 +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: call_alias_ptr +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 4 +; RELOC-NEXT: - Index: 6 +; RELOC-NEXT: Kind: GLOBAL +; RELOC-NEXT: Name: __stack_pointer +; RELOC-NEXT: Flags: [ UNDEFINED ] +; RELOC-NEXT: Global: 0 +; RELOC-NEXT: - Index: 7 +; RELOC-NEXT: Kind: FUNCTION +; RELOC-NEXT: Name: call_direct_ptr +; RELOC-NEXT: Flags: [ ] +; RELOC-NEXT: Function: 5 +; RELOC-NEXT: - Type: CUSTOM +; RELOC-NEXT: Name: name +; RELOC-NEXT: FunctionNames: +; RELOC-NEXT: - Index: 0 +; RELOC-NEXT: Name: _start +; RELOC-NEXT: - Index: 1 +; RELOC-NEXT: Name: direct_fn +; RELOC-NEXT: - Index: 2 +; RELOC-NEXT: Name: call_direct +; RELOC-NEXT: - Index: 3 +; RELOC-NEXT: Name: call_alias +; RELOC-NEXT: - Index: 4 +; RELOC-NEXT: Name: call_alias_ptr +; RELOC-NEXT: - Index: 5 +; RELOC-NEXT: Name: call_direct_ptr +; RELOC-NEXT: ... diff --git a/test/wasm/weak-symbols.ll b/test/wasm/weak-symbols.ll index 4e4e2edfa9b2..bd45de39ca35 100644 --- a/test/wasm/weak-symbols.ll +++ b/test/wasm/weak-symbols.ll @@ -1,17 +1,19 @@ -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/weak-symbol1.ll -o %t1.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %p/Inputs/weak-symbol2.ll -o %t2.o -; RUN: llc -filetype=obj -mtriple=wasm32-unknown-unknown-wasm %s -o %t.o -; RUN: lld -flavor wasm -o %t.wasm %t.o %t1.o %t2.o +; RUN: llc -filetype=obj %p/Inputs/weak-symbol1.ll -o %t1.o +; RUN: llc -filetype=obj %p/Inputs/weak-symbol2.ll -o %t2.o +; RUN: llc -filetype=obj %s -o %t.o +; RUN: wasm-ld -no-gc-sections -o %t.wasm %t.o %t1.o %t2.o ; RUN: obj2yaml %t.wasm | FileCheck %s +target triple = "wasm32-unknown-unknown" + declare i32 @weakFn() local_unnamed_addr @weakGlobal = external global i32 -define i32 @_start() local_unnamed_addr { +define void @_start() local_unnamed_addr { entry: %call = call i32 @weakFn() %val = load i32, i32* @weakGlobal, align 4 - ret i32 %val + ret void } ; CHECK: --- !WASM @@ -21,10 +23,13 @@ entry: ; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 0, 1, 1, 1, 1 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC @@ -37,45 +42,81 @@ entry: ; CHECK-NEXT: - Initial: 0x00000002 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66576 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1032 +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: weakFn ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: exportWeak1 ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Index: 3 +; CHECK-NEXT: - Name: weakGlobal +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: exportWeak2 ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 4 +; CHECK-NEXT: Index: 5 ; CHECK-NEXT: - Type: ELEM ; CHECK-NEXT: Segments: ; CHECK-NEXT: - Offset: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 1 ] +; CHECK-NEXT: Functions: [ 2 ] ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 1081808080001A4100280280888080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1082808080001A0B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41010B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4181808080000B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 41020B -; CHECK-NEXT: - Locals: +; CHECK-NEXT: - Index: 5 +; CHECK-NEXT: Locals: ; CHECK-NEXT: Body: 4181808080000B ; CHECK-NEXT: - Type: DATA ; CHECK-NEXT: Segments: @@ -86,15 +127,18 @@ entry: ; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: Content: '0100000002000000' ; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 8 -; CHECK-NEXT: - Type: CUSTOM ; CHECK-NEXT: Name: name ; CHECK-NEXT: FunctionNames: ; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Name: __wasm_call_ctors +; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: Name: _start ; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Name: weakFn +; CHECK-NEXT: - Index: 3 ; CHECK-NEXT: Name: exportWeak1 ; CHECK-NEXT: - Index: 4 +; CHECK-NEXT: Name: weakFn +; CHECK-NEXT: - Index: 5 ; CHECK-NEXT: Name: exportWeak2 ; CHECK-NEXT: ... diff --git a/test/wasm/weak-external.ll b/test/wasm/weak-undefined.ll index e5025db53693..53b38bc32c3e 100644 --- a/test/wasm/weak-external.ll +++ b/test/wasm/weak-undefined.ll @@ -1,10 +1,12 @@ -; RUN: llc -mtriple=wasm32-unknown-unknown-wasm -filetype=obj -o %t.o %s -; RUN: lld -flavor wasm -strip-debug %t.o -o %t.wasm +; RUN: llc -filetype=obj -o %t.o %s +; RUN: wasm-ld -strip-debug %t.o -o %t.wasm ; RUN: obj2yaml %t.wasm | FileCheck %s ; Test that undefined weak externals (global_var) and (foo) don't cause ; link failures and resolve to zero. +target triple = "wasm32-unknown-unknown" + @global_var = extern_weak global i32, align 4 declare extern_weak i32 @foo() @@ -18,10 +20,10 @@ define i32* @get_address_of_global_var() #0 { ret i32* @global_var } -define i32 @_start() #0 { +define void @_start() #0 { entry: - %0 = load i32, i32* @global_var, align 4 - ret i32 %0 + %call = call i32* @get_address_of_global_var() + ret void } ; CHECK: --- !WASM @@ -31,56 +33,75 @@ entry: ; CHECK-NEXT: - Type: TYPE ; CHECK-NEXT: Signatures: ; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: ReturnType: NORESULT +; CHECK-NEXT: ParamTypes: +; CHECK-NEXT: - Index: 1 ; CHECK-NEXT: ReturnType: I32 ; CHECK-NEXT: ParamTypes: ; CHECK-NEXT: - Type: FUNCTION -; CHECK-NEXT: FunctionTypes: [ 0, 0, 0 ] +; CHECK-NEXT: FunctionTypes: [ 0, 1, 1, 0 ] ; CHECK-NEXT: - Type: TABLE ; CHECK-NEXT: Tables: ; CHECK-NEXT: - ElemType: ANYFUNC ; CHECK-NEXT: Limits: ; CHECK-NEXT: Flags: [ HAS_MAX ] -; CHECK-NEXT: Initial: 0x00000002 -; CHECK-NEXT: Maximum: 0x00000002 +; CHECK-NEXT: Initial: 0x00000001 +; CHECK-NEXT: Maximum: 0x00000001 ; CHECK-NEXT: - Type: MEMORY ; CHECK-NEXT: Memories: ; CHECK-NEXT: - Initial: 0x00000002 ; CHECK-NEXT: - Type: GLOBAL ; CHECK-NEXT: Globals: -; CHECK-NEXT: - Type: I32 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Type: I32 ; CHECK-NEXT: Mutable: true ; CHECK-NEXT: InitExpr: ; CHECK-NEXT: Opcode: I32_CONST ; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 66560 +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Type: I32 +; CHECK-NEXT: Mutable: false +; CHECK-NEXT: InitExpr: +; CHECK-NEXT: Opcode: I32_CONST +; CHECK-NEXT: Value: 1024 ; CHECK-NEXT: - Type: EXPORT ; CHECK-NEXT: Exports: ; CHECK-NEXT: - Name: memory ; CHECK-NEXT: Kind: MEMORY ; CHECK-NEXT: Index: 0 +; CHECK-NEXT: - Name: __heap_base +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 1 +; CHECK-NEXT: - Name: __data_end +; CHECK-NEXT: Kind: GLOBAL +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Name: _start ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 2 +; CHECK-NEXT: Index: 3 ; CHECK-NEXT: - Name: get_address_of_foo ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 0 +; CHECK-NEXT: Index: 1 ; CHECK-NEXT: - Name: get_address_of_global_var ; CHECK-NEXT: Kind: FUNCTION -; CHECK-NEXT: Index: 1 -; CHECK-NEXT: - Type: ELEM -; CHECK-NEXT: Segments: -; CHECK-NEXT: - Offset: -; CHECK-NEXT: Opcode: I32_CONST -; CHECK-NEXT: Value: 1 -; CHECK-NEXT: Functions: [ 0 ] +; CHECK-NEXT: Index: 2 ; CHECK-NEXT: - Type: CODE ; CHECK-NEXT: Functions: -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 4181808080000B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41FFFFFFFF7F0B -; CHECK-NEXT: - Locals: -; CHECK-NEXT: Body: 41002802FFFFFFFF0F0B -; CHECK-NEXT: - Type: CUSTOM -; CHECK-NEXT: Name: linking -; CHECK-NEXT: DataSize: 0 +; CHECK-NEXT: - Index: 0 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 0B +; CHECK-NEXT: - Index: 1 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4180808080000B +; CHECK-NEXT: - Index: 2 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 4180808080000B +; CHECK-NEXT: - Index: 3 +; CHECK-NEXT: Locals: +; CHECK-NEXT: Body: 1082808080001A0B ; CHECK-NEXT: ... diff --git a/test/wasm/whole-archive.test b/test/wasm/whole-archive.test new file mode 100644 index 000000000000..814acbf432e7 --- /dev/null +++ b/test/wasm/whole-archive.test @@ -0,0 +1,34 @@ +RUN: llc -filetype=obj %p/Inputs/start.ll -o %t.o +RUN: llc -filetype=obj %p/Inputs/ret32.ll -o %t.ret32.o +RUN: rm -f %t.a +RUN: llvm-ar rcs %t.a %t.ret32.o + +Should not add symbols from the archive by default as they are not required +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o %t.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s +NOTADDED: FunctionNames: +NOTADDED-NOT: Name: ret32 +NOTADDED: ... + +Should add symbols from the archive if --whole-archive is used +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %t.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s +ADDED: FunctionNames: +ADDED: Name: ret32 +ADDED: ... + +--no-whole-archive should restore default behaviour +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive --no-whole-archive %t.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s + +--whole-archive and --no-whole-archive should affect only archives which follow them +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o %t.a --whole-archive --no-whole-archive +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=NOTADDED %s +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %t.a --no-whole-archive +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s + +--whole-archive should also work with thin archives +RUN: rm -f %tthin.a +RUN: llvm-ar --format=gnu rcsT %tthin.a %t.ret32.o +RUN: wasm-ld --no-gc-sections -o %t.wasm %t.o --whole-archive %tthin.a +RUN: obj2yaml %t.wasm | FileCheck --check-prefix=ADDED %s diff --git a/tools/lld/lld.cpp b/tools/lld/lld.cpp index 64e9aea25e39..4a8e3f7ec34a 100644 --- a/tools/lld/lld.cpp +++ b/tools/lld/lld.cpp @@ -7,12 +7,22 @@ // //===----------------------------------------------------------------------===// // -// This is the entry point to the lld driver. This is a thin wrapper which -// dispatches to the given platform specific driver. +// This file contains the main function of the lld executable. The main +// function is a thin wrapper which dispatches to the platform specific +// driver. // -// If there is -flavor option, it is dispatched according to the arguments. -// If the flavor parameter is not present, then it is dispatched according -// to argv[0]. +// lld is a single executable that contains four different linkers for ELF, +// COFF, WebAssembly and Mach-O. The main function dispatches according to +// argv[0] (i.e. command name). The most common name for each target is shown +// below: +// +// - ld.lld: ELF (Unix) +// - ld64: Mach-O (macOS) +// - lld-link: COFF (Windows) +// - ld-wasm: WebAssembly +// +// lld can be invoked as "lld" along with "-flavor" option. This is for +// backward compatibility and not recommended. // //===----------------------------------------------------------------------===// @@ -20,10 +30,9 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" +#include <cstdlib> using namespace lld; using namespace llvm; @@ -102,28 +111,34 @@ static Flavor parseFlavor(std::vector<const char *> &V) { return parseProgname(Arg0); } +// If this function returns true, lld calls _exit() so that it quickly +// exits without invoking destructors of globally allocated objects. +// +// We don't want to do that if we are running tests though, because +// doing that breaks leak sanitizer. So, lit sets this environment variable, +// and we use it to detect whether we are running tests or not. +static bool canExitEarly() { return StringRef(getenv("LLD_IN_TEST")) != "1"; } + /// Universal linker main(). This linker emulates the gnu, darwin, or /// windows linker based on the argv[0] or -flavor option. int main(int Argc, const char **Argv) { - // Standard set up, so program fails gracefully. - sys::PrintStackTraceOnErrorSignal(Argv[0]); - PrettyStackTraceProgram StackPrinter(Argc, Argv); - llvm_shutdown_obj Shutdown; + InitLLVM X(Argc, Argv); std::vector<const char *> Args(Argv, Argv + Argc); switch (parseFlavor(Args)) { case Gnu: if (isPETarget(Args)) return !mingw::link(Args); - return !elf::link(Args, true); + return !elf::link(Args, canExitEarly()); case WinLink: - return !coff::link(Args, true); + return !coff::link(Args, canExitEarly()); case Darwin: - return !mach_o::link(Args); + return !mach_o::link(Args, canExitEarly()); case Wasm: - return !wasm::link(Args, true); + return !wasm::link(Args, canExitEarly()); default: die("lld is a generic driver.\n" - "Invoke ld.lld (Unix), ld (macOS) or lld-link (Windows) instead."); + "Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-lld" + " (WebAssembly) instead"); } } diff --git a/unittests/DriverTests/DarwinLdDriverTest.cpp b/unittests/DriverTests/DarwinLdDriverTest.cpp index 696be69bc269..e2e634a4cb2d 100644 --- a/unittests/DriverTests/DarwinLdDriverTest.cpp +++ b/unittests/DriverTests/DarwinLdDriverTest.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief Darwin's ld driver tests. +/// Darwin's ld driver tests. /// //===----------------------------------------------------------------------===// @@ -23,8 +23,7 @@ using namespace lld; namespace lld { namespace mach_o { -bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx, - raw_ostream &diagnostics); +bool parse(llvm::ArrayRef<const char *> args, MachOLinkingContext &ctx); } } @@ -42,9 +41,7 @@ protected: bool parse(std::vector<const char *> args) { args.insert(args.begin(), "ld"); - std::string errorMessage; - raw_string_ostream os(errorMessage); - return mach_o::parse(args, _ctx, os); + return mach_o::parse(args, _ctx); } MachOLinkingContext _ctx; diff --git a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp index 3e8793a0ef48..336bbdba6269 100644 --- a/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp +++ b/unittests/MachOTests/MachONormalizedFileBinaryReaderTests.cpp @@ -12,14 +12,17 @@ #include "llvm/ADT/StringRef.h" #include "llvm/BinaryFormat/MachO.h" #include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/YAMLTraits.h" #include "gtest/gtest.h" #include <cstdint> #include <memory> +using llvm::SmallString; using llvm::StringRef; using llvm::MemoryBuffer; +using llvm::Twine; using namespace lld::mach_o::normalized; using namespace llvm::MachO; @@ -741,9 +744,11 @@ TEST(BinaryReaderTest, hello_obj_ppc) { EXPECT_EQ(printfLabel.type, N_UNDF); EXPECT_EQ(printfLabel.scope, SymbolScope(N_EXT)); - auto ec = writeBinary(*f, "/tmp/foo.o"); - // FIXME: We want to do EXPECT_FALSE(ec) but that fails on some Windows bots, - // probably due to /tmp not being available. - // For now just consume the error without checking it. - consumeError(std::move(ec)); + SmallString<128> tmpFl; + std::error_code ec = + llvm::sys::fs::createTemporaryFile(Twine("xx"), "o", tmpFl); + EXPECT_FALSE(ec); + llvm::Error ec2 = writeBinary(*f, tmpFl); + EXPECT_FALSE(ec2); + llvm::sys::fs::remove(tmpFl); } diff --git a/wasm/CMakeLists.txt b/wasm/CMakeLists.txt index 19b0d168437c..1a9e09b38429 100644 --- a/wasm/CMakeLists.txt +++ b/wasm/CMakeLists.txt @@ -2,10 +2,16 @@ set(LLVM_TARGET_DEFINITIONS Options.td) tablegen(LLVM Options.inc -gen-opt-parser-defs) add_public_tablegen_target(WasmOptionsTableGen) +if(NOT LLD_BUILT_STANDALONE) + set(tablegen_deps intrinsics_gen) +endif() + add_lld_library(lldWasm Driver.cpp + InputChunks.cpp InputFiles.cpp - InputSegment.cpp + LTO.cpp + MarkLive.cpp OutputSections.cpp SymbolTable.cpp Symbols.cpp @@ -17,10 +23,16 @@ add_lld_library(lldWasm BinaryFormat Core Demangle + LTO + MC Object Option Support LINK_LIBS lldCommon - ) + + DEPENDS + WasmOptionsTableGen + ${tablegen_deps} + )
\ No newline at end of file diff --git a/wasm/Config.h b/wasm/Config.h index 82f49ce175bb..76a780567072 100644 --- a/wasm/Config.h +++ b/wasm/Config.h @@ -13,33 +13,43 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/BinaryFormat/Wasm.h" - -#include "Symbols.h" - -using llvm::wasm::WasmGlobal; +#include "llvm/Support/CachePruning.h" namespace lld { namespace wasm { struct Configuration { bool AllowUndefined; - bool CheckSignatures; + bool CompressRelocTargets; bool Demangle; - bool EmitRelocs; + bool DisableVerify; + bool ExportAll; + bool ExportTable; + bool GcSections; bool ImportMemory; + bool ImportTable; + bool MergeDataSegments; + bool PrintGcSections; bool Relocatable; + bool SaveTemps; bool StripAll; bool StripDebug; + bool StackFirst; uint32_t GlobalBase; uint32_t InitialMemory; uint32_t MaxMemory; uint32_t ZStackSize; + unsigned LTOPartitions; + unsigned LTOO; + unsigned Optimize; + unsigned ThinLTOJobs; llvm::StringRef Entry; llvm::StringRef OutputFile; + llvm::StringRef ThinLTOCacheDir; llvm::StringSet<> AllowUndefinedSymbols; std::vector<llvm::StringRef> SearchPaths; - Symbol *StackPointerSymbol = nullptr; + llvm::CachePruningPolicy ThinLTOCachePolicy; }; // The only instance of Configuration struct. diff --git a/wasm/Driver.cpp b/wasm/Driver.cpp index 97ec262be308..329b5ae80a9c 100644 --- a/wasm/Driver.cpp +++ b/wasm/Driver.cpp @@ -9,11 +9,15 @@ #include "lld/Common/Driver.h" #include "Config.h" +#include "InputChunks.h" +#include "InputGlobal.h" +#include "MarkLive.h" #include "SymbolTable.h" #include "Writer.h" #include "lld/Common/Args.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" #include "lld/Common/Version.h" #include "llvm/ADT/Twine.h" @@ -22,6 +26,9 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Path.h" #include "llvm/Support/Process.h" +#include "llvm/Support/TargetSelect.h" + +#define DEBUG_TYPE "lld" using namespace llvm; using namespace llvm::sys; @@ -30,14 +37,9 @@ using namespace llvm::wasm; using namespace lld; using namespace lld::wasm; -namespace { +Configuration *lld::wasm::Config; -// Parses command line options. -class WasmOptTable : public llvm::opt::OptTable { -public: - WasmOptTable(); - llvm::opt::InputArgList parse(ArrayRef<const char *> Argv); -}; +namespace { // Create enum with OPT_xxx values for each option in Options.td enum { @@ -47,24 +49,36 @@ enum { #undef OPTION }; +// This function is called on startup. We need this for LTO since +// LTO calls LLVM functions to compile bitcode files to native code. +// Technically this can be delayed until we read bitcode files, but +// we don't bother to do lazily because the initialization is fast. +static void initLLVM() { + InitializeAllTargets(); + InitializeAllTargetMCs(); + InitializeAllAsmPrinters(); + InitializeAllAsmParsers(); +} + class LinkerDriver { public: void link(ArrayRef<const char *> ArgsArr); private: - void createFiles(llvm::opt::InputArgList &Args); + void createFiles(opt::InputArgList &Args); void addFile(StringRef Path); void addLibrary(StringRef Name); + + // True if we are in --whole-archive and --no-whole-archive. + bool InWholeArchive = false; + std::vector<InputFile *> Files; }; - } // anonymous namespace -Configuration *lld::wasm::Config; - bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Error) { - errorHandler().LogName = Args[0]; + errorHandler().LogName = sys::path::filename(Args[0]); errorHandler().ErrorOS = &Error; errorHandler().ColorDiagnostics = Error.has_colors(); errorHandler().ErrorLimitExceededMsg = @@ -74,6 +88,7 @@ bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly, Config = make<Configuration>(); Symtab = make<SymbolTable>(); + initLLVM(); LinkerDriver().link(Args); // Exit immediately if we don't need to return to the caller. @@ -86,8 +101,6 @@ bool lld::wasm::link(ArrayRef<const char *> Args, bool CanExitEarly, return !errorCount(); } -// Create OptTable - // Create prefix string literals used in Options.td #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; #include "Options.inc" @@ -102,6 +115,14 @@ static const opt::OptTable::Info OptInfo[] = { #undef OPTION }; +namespace { +class WasmOptTable : public llvm::opt::OptTable { +public: + WasmOptTable() : OptTable(OptInfo) {} + opt::InputArgList parse(ArrayRef<const char *> Argv); +}; +} // namespace + // Set color diagnostics according to -color-diagnostics={auto,always,never} // or -no-color-diagnostics flags. static void handleColorDiagnostics(opt::InputArgList &Args) { @@ -109,19 +130,18 @@ static void handleColorDiagnostics(opt::InputArgList &Args) { OPT_no_color_diagnostics); if (!Arg) return; - - if (Arg->getOption().getID() == OPT_color_diagnostics) + if (Arg->getOption().getID() == OPT_color_diagnostics) { errorHandler().ColorDiagnostics = true; - else if (Arg->getOption().getID() == OPT_no_color_diagnostics) + } else if (Arg->getOption().getID() == OPT_no_color_diagnostics) { errorHandler().ColorDiagnostics = false; - else { + } else { StringRef S = Arg->getValue(); if (S == "always") errorHandler().ColorDiagnostics = true; - if (S == "never") + else if (S == "never") errorHandler().ColorDiagnostics = false; - if (S != "auto") - error("unknown option: -color-diagnostics=" + S); + else if (S != "auto") + error("unknown option: --color-diagnostics=" + S); } } @@ -134,25 +154,15 @@ static Optional<std::string> findFile(StringRef Path1, const Twine &Path2) { return None; } -// Inject a new undefined symbol into the link. This will cause the link to -// fail unless this symbol can be found. -static void addSyntheticUndefinedFunction(StringRef Name, - const WasmSignature *Type) { - log("injecting undefined func: " + Name); - Symtab->addUndefinedFunction(Name, Type); -} - -static void printHelp(const char *Argv0) { - WasmOptTable().PrintHelp(outs(), Argv0, "LLVM Linker", false); -} - -WasmOptTable::WasmOptTable() : OptTable(OptInfo) {} - opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) { SmallVector<const char *, 256> Vec(Argv.data(), Argv.data() + Argv.size()); unsigned MissingIndex; unsigned MissingCount; + + // Expand response files (arguments in the form of @<filename>) + cl::ExpandResponseFiles(Saver, cl::TokenizeGNUCommandLine, Vec); + opt::InputArgList Args = this->ParseArgs(Vec, MissingIndex, MissingCount); handleColorDiagnostics(Args); @@ -161,16 +171,80 @@ opt::InputArgList WasmOptTable::parse(ArrayRef<const char *> Argv) { return Args; } +// Currently we allow a ".imports" to live alongside a library. This can +// be used to specify a list of symbols which can be undefined at link +// time (imported from the environment. For example libc.a include an +// import file that lists the syscall functions it relies on at runtime. +// In the long run this information would be better stored as a symbol +// attribute/flag in the object file itself. +// See: https://github.com/WebAssembly/tool-conventions/issues/35 +static void readImportFile(StringRef Filename) { + if (Optional<MemoryBufferRef> Buf = readFile(Filename)) + for (StringRef Sym : args::getLines(*Buf)) + Config->AllowUndefinedSymbols.insert(Sym); +} + +// Returns slices of MB by parsing MB as an archive file. +// Each slice consists of a member file in the archive. +std::vector<MemoryBufferRef> static getArchiveMembers( + MemoryBufferRef MB) { + std::unique_ptr<Archive> File = + CHECK(Archive::create(MB), + MB.getBufferIdentifier() + ": failed to parse archive"); + + std::vector<MemoryBufferRef> V; + Error Err = Error::success(); + for (const ErrorOr<Archive::Child> &COrErr : File->children(Err)) { + Archive::Child C = + CHECK(COrErr, MB.getBufferIdentifier() + + ": could not get the child of the archive"); + MemoryBufferRef MBRef = + CHECK(C.getMemoryBufferRef(), + MB.getBufferIdentifier() + + ": could not get the buffer for a child of the archive"); + V.push_back(MBRef); + } + if (Err) + fatal(MB.getBufferIdentifier() + ": Archive::children failed: " + + toString(std::move(Err))); + + // Take ownership of memory buffers created for members of thin archives. + for (std::unique_ptr<MemoryBuffer> &MB : File->takeThinBuffers()) + make<std::unique_ptr<MemoryBuffer>>(std::move(MB)); + + return V; +} + void LinkerDriver::addFile(StringRef Path) { Optional<MemoryBufferRef> Buffer = readFile(Path); if (!Buffer.hasValue()) return; MemoryBufferRef MBRef = *Buffer; - if (identify_magic(MBRef.getBuffer()) == file_magic::archive) + switch (identify_magic(MBRef.getBuffer())) { + case file_magic::archive: { + // Handle -whole-archive. + if (InWholeArchive) { + for (MemoryBufferRef &M : getArchiveMembers(MBRef)) + Files.push_back(createObjectFile(M)); + return; + } + + SmallString<128> ImportFile = Path; + path::replace_extension(ImportFile, ".imports"); + if (fs::exists(ImportFile)) + readImportFile(ImportFile.str()); + Files.push_back(make<ArchiveFile>(MBRef)); - else - Files.push_back(make<ObjFile>(MBRef)); + return; + } + case file_magic::bitcode: + case file_magic::wasm_object: + Files.push_back(createObjectFile(MBRef)); + break; + default: + error("unknown file type: " + MBRef.getBufferIdentifier()); + } } // Add a given library by searching it from input search paths. @@ -194,11 +268,14 @@ void LinkerDriver::createFiles(opt::InputArgList &Args) { case OPT_INPUT: addFile(Arg->getValue()); break; + case OPT_whole_archive: + InWholeArchive = true; + break; + case OPT_no_whole_archive: + InWholeArchive = false; + break; } } - - if (Files.empty()) - error("no input files"); } static StringRef getEntry(opt::InputArgList &Args, StringRef Default) { @@ -210,13 +287,71 @@ static StringRef getEntry(opt::InputArgList &Args, StringRef Default) { return Arg->getValue(); } +static const uint8_t UnreachableFn[] = { + 0x03 /* ULEB length */, 0x00 /* ULEB num locals */, + 0x00 /* opcode unreachable */, 0x0b /* opcode end */ +}; + +// For weak undefined functions, there may be "call" instructions that reference +// the symbol. In this case, we need to synthesise a dummy/stub function that +// will abort at runtime, so that relocations can still provided an operand to +// the call instruction that passes Wasm validation. +static void handleWeakUndefines() { + for (Symbol *Sym : Symtab->getSymbols()) { + if (!Sym->isUndefined() || !Sym->isWeak()) + continue; + auto *FuncSym = dyn_cast<FunctionSymbol>(Sym); + if (!FuncSym) + continue; + + // It is possible for undefined functions not to have a signature (eg. if + // added via "--undefined"), but weak undefined ones do have a signature. + assert(FuncSym->FunctionType); + const WasmSignature &Sig = *FuncSym->FunctionType; + + // Add a synthetic dummy for weak undefined functions. These dummies will + // be GC'd if not used as the target of any "call" instructions. + Optional<std::string> SymName = demangleItanium(Sym->getName()); + StringRef DebugName = + Saver.save("undefined function " + + (SymName ? StringRef(*SymName) : Sym->getName())); + SyntheticFunction *Func = + make<SyntheticFunction>(Sig, Sym->getName(), DebugName); + Func->setBody(UnreachableFn); + // Ensure it compares equal to the null pointer, and so that table relocs + // don't pull in the stub body (only call-operand relocs should do that). + Func->setTableIndex(0); + Symtab->SyntheticFunctions.emplace_back(Func); + // Hide our dummy to prevent export. + uint32_t Flags = WASM_SYMBOL_VISIBILITY_HIDDEN; + replaceSymbol<DefinedFunction>(Sym, Sym->getName(), Flags, nullptr, Func); + } +} + +// Force Sym to be entered in the output. Used for -u or equivalent. +static Symbol *addUndefined(StringRef Name) { + Symbol *S = Symtab->addUndefinedFunction(Name, 0, nullptr, nullptr); + + // Since symbol S may not be used inside the program, LTO may + // eliminate it. Mark the symbol as "used" to prevent it. + S->IsUsedInRegularObj = true; + + return S; +} + void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { WasmOptTable Parser; opt::InputArgList Args = Parser.parse(ArgsArr.slice(1)); // Handle --help if (Args.hasArg(OPT_help)) { - printHelp(ArgsArr[0]); + Parser.PrintHelp(outs(), ArgsArr[0], "LLVM Linker", false); + return; + } + + // Handle --version + if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) { + outs() << getLLDVersion() << "\n"; return; } @@ -229,26 +364,40 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { errorHandler().ErrorLimit = args::getInteger(Args, OPT_error_limit, 20); - if (Args.hasArg(OPT_version) || Args.hasArg(OPT_v)) { - outs() << getLLDVersion() << "\n"; - return; - } - Config->AllowUndefined = Args.hasArg(OPT_allow_undefined); - Config->CheckSignatures = - Args.hasFlag(OPT_check_signatures, OPT_no_check_signatures, false); - Config->EmitRelocs = Args.hasArg(OPT_emit_relocs); + Config->Demangle = Args.hasFlag(OPT_demangle, OPT_no_demangle, true); + Config->DisableVerify = Args.hasArg(OPT_disable_verify); Config->Entry = getEntry(Args, Args.hasArg(OPT_relocatable) ? "" : "_start"); + Config->ExportAll = Args.hasArg(OPT_export_all); + Config->ExportTable = Args.hasArg(OPT_export_table); + errorHandler().FatalWarnings = + Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); Config->ImportMemory = Args.hasArg(OPT_import_memory); + Config->ImportTable = Args.hasArg(OPT_import_table); + Config->LTOO = args::getInteger(Args, OPT_lto_O, 2); + Config->LTOPartitions = args::getInteger(Args, OPT_lto_partitions, 1); + Config->Optimize = args::getInteger(Args, OPT_O, 0); Config->OutputFile = Args.getLastArgValue(OPT_o); Config->Relocatable = Args.hasArg(OPT_relocatable); + Config->GcSections = + Args.hasFlag(OPT_gc_sections, OPT_no_gc_sections, !Config->Relocatable); + Config->MergeDataSegments = + Args.hasFlag(OPT_merge_data_segments, OPT_no_merge_data_segments, + !Config->Relocatable); + Config->PrintGcSections = + Args.hasFlag(OPT_print_gc_sections, OPT_no_print_gc_sections, false); + Config->SaveTemps = Args.hasArg(OPT_save_temps); Config->SearchPaths = args::getStrings(Args, OPT_L); Config->StripAll = Args.hasArg(OPT_strip_all); Config->StripDebug = Args.hasArg(OPT_strip_debug); + Config->StackFirst = Args.hasArg(OPT_stack_first); + Config->ThinLTOCacheDir = Args.getLastArgValue(OPT_thinlto_cache_dir); + Config->ThinLTOCachePolicy = CHECK( + parseCachePruningPolicy(Args.getLastArgValue(OPT_thinlto_cache_policy)), + "--thinlto-cache-policy: invalid cache policy"); + Config->ThinLTOJobs = args::getInteger(Args, OPT_thinlto_jobs, -1u); errorHandler().Verbose = Args.hasArg(OPT_verbose); ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); - if (Config->Relocatable) - Config->EmitRelocs = true; Config->InitialMemory = args::getInteger(Args, OPT_initial_memory, 0); Config->GlobalBase = args::getInteger(Args, OPT_global_base, 1024); @@ -256,33 +405,72 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { Config->ZStackSize = args::getZOptionValue(Args, OPT_z, "stack-size", WasmPageSize); + Config->CompressRelocTargets = Config->Optimize > 0 && !Config->Relocatable; + + if (Config->LTOO > 3) + error("invalid optimization level for LTO: " + Twine(Config->LTOO)); + if (Config->LTOPartitions == 0) + error("--lto-partitions: number of threads must be > 0"); + if (Config->ThinLTOJobs == 0) + error("--thinlto-jobs: number of threads must be > 0"); + if (auto *Arg = Args.getLastArg(OPT_allow_undefined_file)) - if (Optional<MemoryBufferRef> Buf = readFile(Arg->getValue())) - for (StringRef Sym : args::getLines(*Buf)) - Config->AllowUndefinedSymbols.insert(Sym); + readImportFile(Arg->getValue()); + + if (!Args.hasArg(OPT_INPUT)) { + error("no input files"); + return; + } if (Config->OutputFile.empty()) error("no output file specified"); - if (!Args.hasArg(OPT_INPUT)) - error("no input files"); + if (Config->ImportTable && Config->ExportTable) + error("--import-table and --export-table may not be used together"); - if (Config->Relocatable && !Config->Entry.empty()) - error("entry point specified for relocatable output file"); - if (Config->Relocatable && Args.hasArg(OPT_undefined)) - error("undefined symbols specified for relocatable output file"); + if (Config->Relocatable) { + if (!Config->Entry.empty()) + error("entry point specified for relocatable output file"); + if (Config->GcSections) + error("-r and --gc-sections may not be used together"); + if (Args.hasArg(OPT_undefined)) + error("-r -and --undefined may not be used together"); + } + Symbol *EntrySym = nullptr; if (!Config->Relocatable) { - if (!Config->Entry.empty()) { - static WasmSignature Signature = {{}, WASM_TYPE_NORESULT}; - addSyntheticUndefinedFunction(Config->Entry, &Signature); - } + llvm::wasm::WasmGlobal Global; + Global.Type = {WASM_TYPE_I32, true}; + Global.InitExpr.Value.Int32 = 0; + Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; + Global.SymbolName = "__stack_pointer"; + InputGlobal *StackPointer = make<InputGlobal>(Global, nullptr); + StackPointer->Live = true; + + static WasmSignature NullSignature = {{}, WASM_TYPE_NORESULT}; + + // Add synthetic symbols before any others + WasmSym::CallCtors = Symtab->addSyntheticFunction( + "__wasm_call_ctors", WASM_SYMBOL_VISIBILITY_HIDDEN, + make<SyntheticFunction>(NullSignature, "__wasm_call_ctors")); + // TODO(sbc): Remove WASM_SYMBOL_VISIBILITY_HIDDEN when the mutable global + // spec proposal is implemented in all major browsers. + // See: https://github.com/WebAssembly/mutable-global + WasmSym::StackPointer = Symtab->addSyntheticGlobal( + "__stack_pointer", WASM_SYMBOL_VISIBILITY_HIDDEN, StackPointer); + WasmSym::HeapBase = Symtab->addSyntheticDataSymbol("__heap_base", 0); + WasmSym::DsoHandle = Symtab->addSyntheticDataSymbol( + "__dso_handle", WASM_SYMBOL_VISIBILITY_HIDDEN); + WasmSym::DataEnd = Symtab->addSyntheticDataSymbol("__data_end", 0); + + // For now, since we don't actually use the start function as the + // wasm start symbol, we don't need to care about it signature. + if (!Config->Entry.empty()) + EntrySym = addUndefined(Config->Entry); // Handle the `--undefined <sym>` options. - for (StringRef S : args::getStrings(Args, OPT_undefined)) - addSyntheticUndefinedFunction(S, nullptr); - - Config->StackPointerSymbol = Symtab->addDefinedGlobal("__stack_pointer"); + for (auto *Arg : Args.filtered(OPT_undefined)) + addUndefined(Arg->getValue()); } createFiles(Args); @@ -293,29 +481,59 @@ void LinkerDriver::link(ArrayRef<const char *> ArgsArr) { // symbols that we need to the symbol table. for (InputFile *F : Files) Symtab->addFile(F); + if (errorCount()) + return; + + // Add synthetic dummies for weak undefined functions. + if (!Config->Relocatable) + handleWeakUndefines(); + + // Handle --export. + for (auto *Arg : Args.filtered(OPT_export)) { + StringRef Name = Arg->getValue(); + Symbol *Sym = Symtab->find(Name); + if (Sym && Sym->isDefined()) + Sym->ForceExport = true; + else if (!Config->AllowUndefined) + error("symbol exported via --export not found: " + Name); + } + + // Do link-time optimization if given files are LLVM bitcode files. + // This compiles bitcode files into real object files. + Symtab->addCombinedLTOObject(); + if (errorCount()) + return; // Make sure we have resolved all symbols. if (!Config->Relocatable && !Config->AllowUndefined) { Symtab->reportRemainingUndefines(); } else { - // When we allow undefined symbols we cannot include those defined in - // -u/--undefined since these undefined symbols have only names and no - // function signature, which means they cannot be written to the final - // output. - for (StringRef S : args::getStrings(Args, OPT_undefined)) { - Symbol *Sym = Symtab->find(S); + // Even when using --allow-undefined we still want to report the absence of + // our initial set of undefined symbols (i.e. the entry point and symbols + // specified via --undefined). + // Part of the reason for this is that these function don't have signatures + // so which means they cannot be written as wasm function imports. + for (auto *Arg : Args.filtered(OPT_undefined)) { + Symbol *Sym = Symtab->find(Arg->getValue()); if (!Sym->isDefined()) - error("function forced with --undefined not found: " + Sym->getName()); + error("symbol forced with --undefined not found: " + Sym->getName()); } + if (EntrySym && !EntrySym->isDefined()) + error("entry symbol not defined (pass --no-entry to supress): " + + EntrySym->getName()); } if (errorCount()) return; - if (!Config->Entry.empty() && !Symtab->find(Config->Entry)->isDefined()) - error("entry point not found: " + Config->Entry); + if (EntrySym) + EntrySym->setHidden(false); + if (errorCount()) return; + // Do size optimizations: garbage collection + markLive(); + // Write the result to the file. writeResult(); } diff --git a/wasm/InputChunks.cpp b/wasm/InputChunks.cpp new file mode 100644 index 000000000000..fcefac7d99b8 --- /dev/null +++ b/wasm/InputChunks.cpp @@ -0,0 +1,295 @@ +//===- InputChunks.cpp ----------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "InputChunks.h" +#include "Config.h" +#include "OutputSegment.h" +#include "WriterUtils.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/LLVM.h" +#include "llvm/Support/LEB128.h" + +#define DEBUG_TYPE "lld" + +using namespace llvm; +using namespace llvm::wasm; +using namespace llvm::support::endian; +using namespace lld; +using namespace lld::wasm; + +static StringRef ReloctTypeToString(uint8_t RelocType) { + switch (RelocType) { +#define WASM_RELOC(NAME, REL) case REL: return #NAME; +#include "llvm/BinaryFormat/WasmRelocs.def" +#undef WASM_RELOC + } + llvm_unreachable("unknown reloc type"); +} + +std::string lld::toString(const InputChunk *C) { + return (toString(C->File) + ":(" + C->getName() + ")").str(); +} + +StringRef InputChunk::getComdatName() const { + uint32_t Index = getComdat(); + if (Index == UINT32_MAX) + return StringRef(); + return File->getWasmObj()->linkingData().Comdats[Index]; +} + +void InputChunk::copyRelocations(const WasmSection &Section) { + if (Section.Relocations.empty()) + return; + size_t Start = getInputSectionOffset(); + size_t Size = getInputSize(); + for (const WasmRelocation &R : Section.Relocations) + if (R.Offset >= Start && R.Offset < Start + Size) + Relocations.push_back(R); +} + +void InputChunk::verifyRelocTargets() const { + for (const WasmRelocation &Rel : Relocations) { + uint32_t ExistingValue; + unsigned BytesRead = 0; + uint32_t Offset = Rel.Offset - getInputSectionOffset(); + const uint8_t *Loc = data().data() + Offset; + switch (Rel.Type) { + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + ExistingValue = decodeULEB128(Loc, &BytesRead); + break; + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + ExistingValue = static_cast<uint32_t>(decodeSLEB128(Loc, &BytesRead)); + break; + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + ExistingValue = static_cast<uint32_t>(read32le(Loc)); + break; + default: + llvm_unreachable("unknown relocation type"); + } + + if (BytesRead && BytesRead != 5) + warn("expected LEB at relocation site be 5-byte padded"); + uint32_t ExpectedValue = File->calcExpectedValue(Rel); + if (ExpectedValue != ExistingValue) + warn("unexpected existing value for " + ReloctTypeToString(Rel.Type) + + ": existing=" + Twine(ExistingValue) + + " expected=" + Twine(ExpectedValue)); + } +} + +// Copy this input chunk to an mmap'ed output file and apply relocations. +void InputChunk::writeTo(uint8_t *Buf) const { + // Copy contents + memcpy(Buf + OutputOffset, data().data(), data().size()); + + // Apply relocations + if (Relocations.empty()) + return; + +#ifndef NDEBUG + verifyRelocTargets(); +#endif + + LLVM_DEBUG(dbgs() << "applying relocations: " << getName() + << " count=" << Relocations.size() << "\n"); + int32_t Off = OutputOffset - getInputSectionOffset(); + + for (const WasmRelocation &Rel : Relocations) { + uint8_t *Loc = Buf + Rel.Offset + Off; + uint32_t Value = File->calcNewValue(Rel); + LLVM_DEBUG(dbgs() << "apply reloc: type=" << ReloctTypeToString(Rel.Type) + << " addend=" << Rel.Addend << " index=" << Rel.Index + << " value=" << Value << " offset=" << Rel.Offset + << "\n"); + + switch (Rel.Type) { + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + encodeULEB128(Value, Loc, 5); + break; + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + encodeSLEB128(static_cast<int32_t>(Value), Loc, 5); + break; + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + write32le(Loc, Value); + break; + default: + llvm_unreachable("unknown relocation type"); + } + } +} + +// Copy relocation entries to a given output stream. +// This function is used only when a user passes "-r". For a regular link, +// we consume relocations instead of copying them to an output file. +void InputChunk::writeRelocations(raw_ostream &OS) const { + if (Relocations.empty()) + return; + + int32_t Off = OutputOffset - getInputSectionOffset(); + LLVM_DEBUG(dbgs() << "writeRelocations: " << File->getName() + << " offset=" << Twine(Off) << "\n"); + + for (const WasmRelocation &Rel : Relocations) { + writeUleb128(OS, Rel.Type, "reloc type"); + writeUleb128(OS, Rel.Offset + Off, "reloc offset"); + writeUleb128(OS, File->calcNewIndex(Rel), "reloc index"); + + switch (Rel.Type) { + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + writeSleb128(OS, File->calcNewAddend(Rel), "reloc addend"); + break; + } + } +} + +void InputFunction::setFunctionIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "InputFunction::setFunctionIndex: " << getName() + << " -> " << Index << "\n"); + assert(!hasFunctionIndex()); + FunctionIndex = Index; +} + +void InputFunction::setTableIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "InputFunction::setTableIndex: " << getName() << " -> " + << Index << "\n"); + assert(!hasTableIndex()); + TableIndex = Index; +} + +// Write a relocation value without padding and return the number of bytes +// witten. +static unsigned writeCompressedReloc(uint8_t *Buf, const WasmRelocation &Rel, + uint32_t Value) { + switch (Rel.Type) { + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + return encodeULEB128(Value, Buf); + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + return encodeSLEB128(static_cast<int32_t>(Value), Buf); + default: + llvm_unreachable("unexpected relocation type"); + } +} + +static unsigned getRelocWidthPadded(const WasmRelocation &Rel) { + switch (Rel.Type) { + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + return 5; + default: + llvm_unreachable("unexpected relocation type"); + } +} + +static unsigned getRelocWidth(const WasmRelocation &Rel, uint32_t Value) { + uint8_t Buf[5]; + return writeCompressedReloc(Buf, Rel, Value); +} + +// Relocations of type LEB and SLEB in the code section are padded to 5 bytes +// so that a fast linker can blindly overwrite them without needing to worry +// about the number of bytes needed to encode the values. +// However, for optimal output the code section can be compressed to remove +// the padding then outputting non-relocatable files. +// In this case we need to perform a size calculation based on the value at each +// relocation. At best we end up saving 4 bytes for each relocation entry. +// +// This function only computes the final output size. It must be called +// before getSize() is used to calculate of layout of the code section. +void InputFunction::calculateSize() { + if (!File || !Config->CompressRelocTargets) + return; + + LLVM_DEBUG(dbgs() << "calculateSize: " << getName() << "\n"); + + const uint8_t *SecStart = File->CodeSection->Content.data(); + const uint8_t *FuncStart = SecStart + getInputSectionOffset(); + uint32_t FunctionSizeLength; + decodeULEB128(FuncStart, &FunctionSizeLength); + + uint32_t Start = getInputSectionOffset(); + uint32_t End = Start + Function->Size; + + uint32_t LastRelocEnd = Start + FunctionSizeLength; + for (WasmRelocation &Rel : Relocations) { + LLVM_DEBUG(dbgs() << " region: " << (Rel.Offset - LastRelocEnd) << "\n"); + CompressedFuncSize += Rel.Offset - LastRelocEnd; + CompressedFuncSize += getRelocWidth(Rel, File->calcNewValue(Rel)); + LastRelocEnd = Rel.Offset + getRelocWidthPadded(Rel); + } + LLVM_DEBUG(dbgs() << " final region: " << (End - LastRelocEnd) << "\n"); + CompressedFuncSize += End - LastRelocEnd; + + // Now we know how long the resulting function is we can add the encoding + // of its length + uint8_t Buf[5]; + CompressedSize = CompressedFuncSize + encodeULEB128(CompressedFuncSize, Buf); + + LLVM_DEBUG(dbgs() << " calculateSize orig: " << Function->Size << "\n"); + LLVM_DEBUG(dbgs() << " calculateSize new: " << CompressedSize << "\n"); +} + +// Override the default writeTo method so that we can (optionally) write the +// compressed version of the function. +void InputFunction::writeTo(uint8_t *Buf) const { + if (!File || !Config->CompressRelocTargets) + return InputChunk::writeTo(Buf); + + Buf += OutputOffset; + uint8_t *Orig = Buf; (void)Orig; + + const uint8_t *SecStart = File->CodeSection->Content.data(); + const uint8_t *FuncStart = SecStart + getInputSectionOffset(); + const uint8_t *End = FuncStart + Function->Size; + uint32_t Count; + decodeULEB128(FuncStart, &Count); + FuncStart += Count; + + LLVM_DEBUG(dbgs() << "write func: " << getName() << "\n"); + Buf += encodeULEB128(CompressedFuncSize, Buf); + const uint8_t *LastRelocEnd = FuncStart; + for (const WasmRelocation &Rel : Relocations) { + unsigned ChunkSize = (SecStart + Rel.Offset) - LastRelocEnd; + LLVM_DEBUG(dbgs() << " write chunk: " << ChunkSize << "\n"); + memcpy(Buf, LastRelocEnd, ChunkSize); + Buf += ChunkSize; + Buf += writeCompressedReloc(Buf, Rel, File->calcNewValue(Rel)); + LastRelocEnd = SecStart + Rel.Offset + getRelocWidthPadded(Rel); + } + + unsigned ChunkSize = End - LastRelocEnd; + LLVM_DEBUG(dbgs() << " write final chunk: " << ChunkSize << "\n"); + memcpy(Buf, LastRelocEnd, ChunkSize); + LLVM_DEBUG(dbgs() << " total: " << (Buf + ChunkSize - Orig) << "\n"); +} diff --git a/wasm/InputChunks.h b/wasm/InputChunks.h new file mode 100644 index 000000000000..526e29870b21 --- /dev/null +++ b/wasm/InputChunks.h @@ -0,0 +1,236 @@ +//===- InputChunks.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// An InputChunks represents an indivisible opaque region of a input wasm file. +// i.e. a single wasm data segment or a single wasm function. +// +// They are written directly to the mmap'd output file after which relocations +// are applied. Because each Chunk is independent they can be written in +// parallel. +// +// Chunks are also unit on which garbage collection (--gc-sections) operates. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_INPUT_CHUNKS_H +#define LLD_WASM_INPUT_CHUNKS_H + +#include "Config.h" +#include "InputFiles.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/Wasm.h" + +using llvm::object::WasmSection; +using llvm::object::WasmSegment; +using llvm::wasm::WasmFunction; +using llvm::wasm::WasmRelocation; +using llvm::wasm::WasmSignature; + +namespace llvm { +class raw_ostream; +} + +namespace lld { +namespace wasm { + +class ObjFile; +class OutputSegment; + +class InputChunk { +public: + enum Kind { DataSegment, Function, SyntheticFunction, Section }; + + Kind kind() const { return SectionKind; } + + virtual uint32_t getSize() const { return data().size(); } + + void copyRelocations(const WasmSection &Section); + + virtual void writeTo(uint8_t *SectionStart) const; + + ArrayRef<WasmRelocation> getRelocations() const { return Relocations; } + + virtual StringRef getName() const = 0; + virtual StringRef getDebugName() const = 0; + virtual uint32_t getComdat() const = 0; + StringRef getComdatName() const; + + size_t NumRelocations() const { return Relocations.size(); } + void writeRelocations(llvm::raw_ostream &OS) const; + + ObjFile *File; + int32_t OutputOffset = 0; + + // Signals that the section is part of the output. The garbage collector, + // and COMDAT handling can set a sections' Live bit. + // If GC is disabled, all sections start out as live by default. + unsigned Live : 1; + +protected: + InputChunk(ObjFile *F, Kind K) + : File(F), Live(!Config->GcSections), SectionKind(K) {} + virtual ~InputChunk() = default; + virtual ArrayRef<uint8_t> data() const = 0; + virtual uint32_t getInputSectionOffset() const = 0; + virtual uint32_t getInputSize() const { return getSize(); }; + + // Verifies the existing data at relocation targets matches our expectations. + // This is performed only debug builds as an extra sanity check. + void verifyRelocTargets() const; + + std::vector<WasmRelocation> Relocations; + Kind SectionKind; +}; + +// Represents a WebAssembly data segment which can be included as part of +// an output data segments. Note that in WebAssembly, unlike ELF and other +// formats, used the term "data segment" to refer to the continous regions of +// memory that make on the data section. See: +// https://webassembly.github.io/spec/syntax/modules.html#syntax-data +// +// For example, by default, clang will produce a separate data section for +// each global variable. +class InputSegment : public InputChunk { +public: + InputSegment(const WasmSegment &Seg, ObjFile *F) + : InputChunk(F, InputChunk::DataSegment), Segment(Seg) {} + + static bool classof(const InputChunk *C) { return C->kind() == DataSegment; } + + uint32_t getAlignment() const { return Segment.Data.Alignment; } + StringRef getName() const override { return Segment.Data.Name; } + StringRef getDebugName() const override { return StringRef(); } + uint32_t getComdat() const override { return Segment.Data.Comdat; } + + const OutputSegment *OutputSeg = nullptr; + int32_t OutputSegmentOffset = 0; + +protected: + ArrayRef<uint8_t> data() const override { return Segment.Data.Content; } + uint32_t getInputSectionOffset() const override { + return Segment.SectionOffset; + } + + const WasmSegment &Segment; +}; + +// Represents a single wasm function within and input file. These are +// combined to create the final output CODE section. +class InputFunction : public InputChunk { +public: + InputFunction(const WasmSignature &S, const WasmFunction *Func, ObjFile *F) + : InputChunk(F, InputChunk::Function), Signature(S), Function(Func) {} + + static bool classof(const InputChunk *C) { + return C->kind() == InputChunk::Function || + C->kind() == InputChunk::SyntheticFunction; + } + + void writeTo(uint8_t *SectionStart) const override; + StringRef getName() const override { return Function->SymbolName; } + StringRef getDebugName() const override { return Function->DebugName; } + uint32_t getComdat() const override { return Function->Comdat; } + uint32_t getFunctionInputOffset() const { return getInputSectionOffset(); } + uint32_t getFunctionCodeOffset() const { return Function->CodeOffset; } + uint32_t getSize() const override { + if (Config->CompressRelocTargets && File) { + assert(CompressedSize); + return CompressedSize; + } + return data().size(); + } + uint32_t getFunctionIndex() const { return FunctionIndex.getValue(); } + bool hasFunctionIndex() const { return FunctionIndex.hasValue(); } + void setFunctionIndex(uint32_t Index); + uint32_t getTableIndex() const { return TableIndex.getValue(); } + bool hasTableIndex() const { return TableIndex.hasValue(); } + void setTableIndex(uint32_t Index); + + // The size of a given input function can depend on the values of the + // LEB relocations within it. This finalizeContents method is called after + // all the symbol values have be calcualted but before getSize() is ever + // called. + void calculateSize(); + + const WasmSignature &Signature; + +protected: + ArrayRef<uint8_t> data() const override { + assert(!Config->CompressRelocTargets); + return File->CodeSection->Content.slice(getInputSectionOffset(), + Function->Size); + } + + uint32_t getInputSize() const override { return Function->Size; } + + uint32_t getInputSectionOffset() const override { + return Function->CodeSectionOffset; + } + + const WasmFunction *Function; + llvm::Optional<uint32_t> FunctionIndex; + llvm::Optional<uint32_t> TableIndex; + uint32_t CompressedFuncSize = 0; + uint32_t CompressedSize = 0; +}; + +class SyntheticFunction : public InputFunction { +public: + SyntheticFunction(const WasmSignature &S, StringRef Name, + StringRef DebugName = {}) + : InputFunction(S, nullptr, nullptr), Name(Name), DebugName(DebugName) { + SectionKind = InputChunk::SyntheticFunction; + } + + static bool classof(const InputChunk *C) { + return C->kind() == InputChunk::SyntheticFunction; + } + + StringRef getName() const override { return Name; } + StringRef getDebugName() const override { return DebugName; } + uint32_t getComdat() const override { return UINT32_MAX; } + + void setBody(ArrayRef<uint8_t> Body_) { Body = Body_; } + +protected: + ArrayRef<uint8_t> data() const override { return Body; } + + StringRef Name; + StringRef DebugName; + ArrayRef<uint8_t> Body; +}; + +// Represents a single Wasm Section within an input file. +class InputSection : public InputChunk { +public: + InputSection(const WasmSection &S, ObjFile *F) + : InputChunk(F, InputChunk::Section), Section(S) { + assert(Section.Type == llvm::wasm::WASM_SEC_CUSTOM); + } + + StringRef getName() const override { return Section.Name; } + StringRef getDebugName() const override { return StringRef(); } + uint32_t getComdat() const override { return UINT32_MAX; } + +protected: + ArrayRef<uint8_t> data() const override { return Section.Content; } + + // Offset within the input section. This is only zero since this chunk + // type represents an entire input section, not part of one. + uint32_t getInputSectionOffset() const override { return 0; } + + const WasmSection &Section; +}; + +} // namespace wasm + +std::string toString(const wasm::InputChunk *); +} // namespace lld + +#endif // LLD_WASM_INPUT_CHUNKS_H diff --git a/wasm/InputFiles.cpp b/wasm/InputFiles.cpp index 1a1a6812c48e..53a24c3cffd4 100644 --- a/wasm/InputFiles.cpp +++ b/wasm/InputFiles.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "InputFiles.h" - #include "Config.h" -#include "InputSegment.h" +#include "InputChunks.h" +#include "InputGlobal.h" #include "SymbolTable.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" @@ -42,64 +42,126 @@ Optional<MemoryBufferRef> lld::wasm::readFile(StringRef Path) { return MBRef; } -void ObjFile::dumpInfo() const { - log("reloc info for: " + getName() + "\n" + - " FunctionIndexOffset : " + Twine(FunctionIndexOffset) + "\n" + - " NumFunctionImports : " + Twine(NumFunctionImports()) + "\n" + - " NumGlobalImports : " + Twine(NumGlobalImports()) + "\n"); -} +InputFile *lld::wasm::createObjectFile(MemoryBufferRef MB) { + file_magic Magic = identify_magic(MB.getBuffer()); + if (Magic == file_magic::wasm_object) + return make<ObjFile>(MB); -bool ObjFile::isImportedFunction(uint32_t Index) const { - return Index < NumFunctionImports(); -} + if (Magic == file_magic::bitcode) + return make<BitcodeFile>(MB); -Symbol *ObjFile::getFunctionSymbol(uint32_t Index) const { - return FunctionSymbols[Index]; + fatal("unknown file type: " + MB.getBufferIdentifier()); } -Symbol *ObjFile::getTableSymbol(uint32_t Index) const { - return TableSymbols[Index]; -} - -Symbol *ObjFile::getGlobalSymbol(uint32_t Index) const { - return GlobalSymbols[Index]; -} - -uint32_t ObjFile::getRelocatedAddress(uint32_t Index) const { - return getGlobalSymbol(Index)->getVirtualAddress(); +void ObjFile::dumpInfo() const { + log("info for: " + getName() + + "\n Symbols : " + Twine(Symbols.size()) + + "\n Function Imports : " + Twine(WasmObj->getNumImportedFunctions()) + + "\n Global Imports : " + Twine(WasmObj->getNumImportedGlobals())); } -uint32_t ObjFile::relocateFunctionIndex(uint32_t Original) const { - Symbol *Sym = getFunctionSymbol(Original); - uint32_t Index = Sym->getOutputIndex(); - DEBUG(dbgs() << "relocateFunctionIndex: " << toString(*Sym) << ": " - << Original << " -> " << Index << "\n"); - return Index; +// Relocations contain either symbol or type indices. This function takes a +// relocation and returns relocated index (i.e. translates from the input +// sybmol/type space to the output symbol/type space). +uint32_t ObjFile::calcNewIndex(const WasmRelocation &Reloc) const { + if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) { + assert(TypeIsUsed[Reloc.Index]); + return TypeMap[Reloc.Index]; + } + return Symbols[Reloc.Index]->getOutputSymbolIndex(); } -uint32_t ObjFile::relocateTypeIndex(uint32_t Original) const { - return TypeMap[Original]; +// Relocations can contain addend for combined sections. This function takes a +// relocation and returns updated addend by offset in the output section. +uint32_t ObjFile::calcNewAddend(const WasmRelocation &Reloc) const { + switch (Reloc.Type) { + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + return Reloc.Addend; + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend; + default: + llvm_unreachable("unexpected relocation type"); + } } -uint32_t ObjFile::relocateTableIndex(uint32_t Original) const { - Symbol *Sym = getTableSymbol(Original); - uint32_t Index = Sym->getTableIndex(); - DEBUG(dbgs() << "relocateTableIndex: " << toString(*Sym) << ": " << Original - << " -> " << Index << "\n"); - return Index; +// Calculate the value we expect to find at the relocation location. +// This is used as a sanity check before applying a relocation to a given +// location. It is useful for catching bugs in the compiler and linker. +uint32_t ObjFile::calcExpectedValue(const WasmRelocation &Reloc) const { + switch (Reloc.Type) { + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: { + const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index]; + return TableEntries[Sym.Info.ElementIndex]; + } + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: { + const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index]; + if (Sym.isUndefined()) + return 0; + const WasmSegment& Segment = WasmObj->dataSegments()[Sym.Info.DataRef.Segment]; + return Segment.Data.Offset.Value.Int32 + Sym.Info.DataRef.Offset + + Reloc.Addend; + } + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) { + return Sym->Function->getFunctionInputOffset() + + Sym->Function->getFunctionCodeOffset() + Reloc.Addend; + } + return 0; + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + return Reloc.Addend; + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + return Reloc.Index; + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: { + const WasmSymbol& Sym = WasmObj->syms()[Reloc.Index]; + return Sym.Info.ElementIndex; + } + default: + llvm_unreachable("unknown relocation type"); + } } -uint32_t ObjFile::relocateGlobalIndex(uint32_t Original) const { - Symbol *Sym = getGlobalSymbol(Original); - uint32_t Index = Sym->getOutputIndex(); - DEBUG(dbgs() << "relocateGlobalIndex: " << toString(*Sym) << ": " << Original - << " -> " << Index << "\n"); - return Index; +// Translate from the relocation's index into the final linked output value. +uint32_t ObjFile::calcNewValue(const WasmRelocation &Reloc) const { + switch (Reloc.Type) { + case R_WEBASSEMBLY_TABLE_INDEX_I32: + case R_WEBASSEMBLY_TABLE_INDEX_SLEB: + return getFunctionSymbol(Reloc.Index)->getTableIndex(); + case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case R_WEBASSEMBLY_MEMORY_ADDR_I32: + case R_WEBASSEMBLY_MEMORY_ADDR_LEB: + if (auto *Sym = dyn_cast<DefinedData>(getDataSymbol(Reloc.Index))) + if (Sym->isLive()) + return Sym->getVirtualAddress() + Reloc.Addend; + return 0; + case R_WEBASSEMBLY_TYPE_INDEX_LEB: + return TypeMap[Reloc.Index]; + case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: + return getFunctionSymbol(Reloc.Index)->getFunctionIndex(); + case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: + return getGlobalSymbol(Reloc.Index)->getGlobalIndex(); + case R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + if (auto *Sym = dyn_cast<DefinedFunction>(getFunctionSymbol(Reloc.Index))) { + return Sym->Function->OutputOffset + + Sym->Function->getFunctionCodeOffset() + Reloc.Addend; + } + return 0; + case R_WEBASSEMBLY_SECTION_OFFSET_I32: + return getSectionSymbol(Reloc.Index)->Section->OutputOffset + Reloc.Addend; + default: + llvm_unreachable("unknown relocation type"); + } } void ObjFile::parse() { // Parse a memory buffer as a wasm file. - DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); + LLVM_DEBUG(dbgs() << "Parsing object: " << toString(this) << "\n"); std::unique_ptr<Binary> Bin = CHECK(createBinary(MB), toString(this)); auto *Obj = dyn_cast<WasmObjectFile>(Bin.get()); @@ -111,156 +173,175 @@ void ObjFile::parse() { Bin.release(); WasmObj.reset(Obj); + // Build up a map of function indices to table indices for use when + // verifying the existing table index relocations + uint32_t TotalFunctions = + WasmObj->getNumImportedFunctions() + WasmObj->functions().size(); + TableEntries.resize(TotalFunctions); + for (const WasmElemSegment &Seg : WasmObj->elements()) { + if (Seg.Offset.Opcode != WASM_OPCODE_I32_CONST) + fatal(toString(this) + ": invalid table elements"); + uint32_t Offset = Seg.Offset.Value.Int32; + for (uint32_t Index = 0; Index < Seg.Functions.size(); Index++) { + + uint32_t FunctionIndex = Seg.Functions[Index]; + TableEntries[FunctionIndex] = Offset + Index; + } + } + // Find the code and data sections. Wasm objects can have at most one code // and one data section. + uint32_t SectionIndex = 0; for (const SectionRef &Sec : WasmObj->sections()) { const WasmSection &Section = WasmObj->getWasmSection(Sec); - if (Section.Type == WASM_SEC_CODE) + if (Section.Type == WASM_SEC_CODE) { CodeSection = &Section; - else if (Section.Type == WASM_SEC_DATA) + } else if (Section.Type == WASM_SEC_DATA) { DataSection = &Section; + } else if (Section.Type == WASM_SEC_CUSTOM) { + CustomSections.emplace_back(make<InputSection>(Section, this)); + CustomSections.back()->copyRelocations(Section); + CustomSectionsByIndex[SectionIndex] = CustomSections.back(); + } + SectionIndex++; } - initializeSymbols(); -} + TypeMap.resize(getWasmObj()->types().size()); + TypeIsUsed.resize(getWasmObj()->types().size(), false); -// Return the InputSegment in which a given symbol is defined. -InputSegment *ObjFile::getSegment(const WasmSymbol &WasmSym) { - uint32_t Address = WasmObj->getWasmSymbolValue(WasmSym); - for (InputSegment *Segment : Segments) { - if (Address >= Segment->startVA() && Address < Segment->endVA()) { - DEBUG(dbgs() << "Found symbol in segment: " << WasmSym.Name << " -> " - << Segment->getName() << "\n"); + ArrayRef<StringRef> Comdats = WasmObj->linkingData().Comdats; + UsedComdats.resize(Comdats.size()); + for (unsigned I = 0; I < Comdats.size(); ++I) + UsedComdats[I] = Symtab->addComdat(Comdats[I]); - return Segment; - } + // Populate `Segments`. + for (const WasmSegment &S : WasmObj->dataSegments()) { + InputSegment *Seg = make<InputSegment>(S, this); + Seg->copyRelocations(*DataSection); + Segments.emplace_back(Seg); + } + + // Populate `Functions`. + ArrayRef<WasmFunction> Funcs = WasmObj->functions(); + ArrayRef<uint32_t> FuncTypes = WasmObj->functionTypes(); + ArrayRef<WasmSignature> Types = WasmObj->types(); + Functions.reserve(Funcs.size()); + + for (size_t I = 0, E = Funcs.size(); I != E; ++I) { + InputFunction *F = + make<InputFunction>(Types[FuncTypes[I]], &Funcs[I], this); + F->copyRelocations(*CodeSection); + Functions.emplace_back(F); + } + + // Populate `Globals`. + for (const WasmGlobal &G : WasmObj->globals()) + Globals.emplace_back(make<InputGlobal>(G, this)); + + // Populate `Symbols` based on the WasmSymbols in the object. + Symbols.reserve(WasmObj->getNumberOfSymbols()); + for (const SymbolRef &Sym : WasmObj->symbols()) { + const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl()); + if (Symbol *Sym = createDefined(WasmSym)) + Symbols.push_back(Sym); + else + Symbols.push_back(createUndefined(WasmSym)); } - error("symbol not found in any segment: " + WasmSym.Name); - return nullptr; } -static void copyRelocationsRange(std::vector<WasmRelocation> &To, - ArrayRef<WasmRelocation> From, size_t Start, - size_t End) { - for (const WasmRelocation &R : From) - if (R.Offset >= Start && R.Offset < End) - To.push_back(R); +bool ObjFile::isExcludedByComdat(InputChunk *Chunk) const { + uint32_t C = Chunk->getComdat(); + if (C == UINT32_MAX) + return false; + return !UsedComdats[C]; } -void ObjFile::initializeSymbols() { - Symbols.reserve(WasmObj->getNumberOfSymbols()); +FunctionSymbol *ObjFile::getFunctionSymbol(uint32_t Index) const { + return cast<FunctionSymbol>(Symbols[Index]); +} - for (const WasmImport &Import : WasmObj->imports()) { - switch (Import.Kind) { - case WASM_EXTERNAL_FUNCTION: - ++FunctionImports; - break; - case WASM_EXTERNAL_GLOBAL: - ++GlobalImports; - break; - } - } +GlobalSymbol *ObjFile::getGlobalSymbol(uint32_t Index) const { + return cast<GlobalSymbol>(Symbols[Index]); +} - FunctionSymbols.resize(FunctionImports + WasmObj->functions().size()); - GlobalSymbols.resize(GlobalImports + WasmObj->globals().size()); +SectionSymbol *ObjFile::getSectionSymbol(uint32_t Index) const { + return cast<SectionSymbol>(Symbols[Index]); +} - for (const WasmSegment &S : WasmObj->dataSegments()) { - InputSegment *Seg = make<InputSegment>(&S, this); - copyRelocationsRange(Seg->Relocations, DataSection->Relocations, - Seg->getInputSectionOffset(), - Seg->getInputSectionOffset() + Seg->getSize()); - Segments.emplace_back(Seg); - } +DataSymbol *ObjFile::getDataSymbol(uint32_t Index) const { + return cast<DataSymbol>(Symbols[Index]); +} - // Populate `FunctionSymbols` and `GlobalSymbols` based on the WasmSymbols - // in the object - for (const SymbolRef &Sym : WasmObj->symbols()) { - const WasmSymbol &WasmSym = WasmObj->getWasmSymbol(Sym.getRawDataRefImpl()); - Symbol *S; - switch (WasmSym.Type) { - case WasmSymbol::SymbolType::FUNCTION_IMPORT: - case WasmSymbol::SymbolType::GLOBAL_IMPORT: - S = createUndefined(WasmSym); - break; - case WasmSymbol::SymbolType::GLOBAL_EXPORT: - S = createDefined(WasmSym, getSegment(WasmSym)); - break; - case WasmSymbol::SymbolType::FUNCTION_EXPORT: - S = createDefined(WasmSym); - break; - case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: - // These are for debugging only, no need to create linker symbols for them - continue; - } +Symbol *ObjFile::createDefined(const WasmSymbol &Sym) { + if (!Sym.isDefined()) + return nullptr; - Symbols.push_back(S); - if (WasmSym.isFunction()) { - DEBUG(dbgs() << "Function: " << WasmSym.ElementIndex << " -> " - << toString(*S) << "\n"); - FunctionSymbols[WasmSym.ElementIndex] = S; - if (WasmSym.HasAltIndex) - FunctionSymbols[WasmSym.AltIndex] = S; - } else { - DEBUG(dbgs() << "Global: " << WasmSym.ElementIndex << " -> " - << toString(*S) << "\n"); - GlobalSymbols[WasmSym.ElementIndex] = S; - if (WasmSym.HasAltIndex) - GlobalSymbols[WasmSym.AltIndex] = S; + StringRef Name = Sym.Info.Name; + uint32_t Flags = Sym.Info.Flags; + + switch (Sym.Info.Kind) { + case WASM_SYMBOL_TYPE_FUNCTION: { + InputFunction *Func = + Functions[Sym.Info.ElementIndex - WasmObj->getNumImportedFunctions()]; + if (isExcludedByComdat(Func)) { + Func->Live = false; + return nullptr; } - } - DEBUG(for (size_t I = 0; I < FunctionSymbols.size(); ++I) - assert(FunctionSymbols[I] != nullptr); - for (size_t I = 0; I < GlobalSymbols.size(); ++I) - assert(GlobalSymbols[I] != nullptr);); - - // Populate `TableSymbols` with all symbols that are called indirectly - uint32_t SegmentCount = WasmObj->elements().size(); - if (SegmentCount) { - if (SegmentCount > 1) - fatal(getName() + ": contains more than one element segment"); - const WasmElemSegment &Segment = WasmObj->elements()[0]; - if (Segment.Offset.Opcode != WASM_OPCODE_I32_CONST) - fatal(getName() + ": unsupported element segment"); - if (Segment.TableIndex != 0) - fatal(getName() + ": unsupported table index in elem segment"); - if (Segment.Offset.Value.Int32 != 0) - fatal(getName() + ": unsupported element segment offset"); - TableSymbols.reserve(Segment.Functions.size()); - for (uint64_t FunctionIndex : Segment.Functions) - TableSymbols.push_back(getFunctionSymbol(FunctionIndex)); + if (Sym.isBindingLocal()) + return make<DefinedFunction>(Name, Flags, this, Func); + return Symtab->addDefinedFunction(Name, Flags, this, Func); } + case WASM_SYMBOL_TYPE_DATA: { + InputSegment *Seg = Segments[Sym.Info.DataRef.Segment]; + if (isExcludedByComdat(Seg)) { + Seg->Live = false; + return nullptr; + } - DEBUG(dbgs() << "TableSymbols: " << TableSymbols.size() << "\n"); - DEBUG(dbgs() << "Functions : " << FunctionSymbols.size() << "\n"); - DEBUG(dbgs() << "Globals : " << GlobalSymbols.size() << "\n"); -} + uint32_t Offset = Sym.Info.DataRef.Offset; + uint32_t Size = Sym.Info.DataRef.Size; -Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { - return Symtab->addUndefined(this, &Sym); + if (Sym.isBindingLocal()) + return make<DefinedData>(Name, Flags, this, Seg, Offset, Size); + return Symtab->addDefinedData(Name, Flags, this, Seg, Offset, Size); + } + case WASM_SYMBOL_TYPE_GLOBAL: { + InputGlobal *Global = + Globals[Sym.Info.ElementIndex - WasmObj->getNumImportedGlobals()]; + if (Sym.isBindingLocal()) + return make<DefinedGlobal>(Name, Flags, this, Global); + return Symtab->addDefinedGlobal(Name, Flags, this, Global); + } + case WASM_SYMBOL_TYPE_SECTION: { + InputSection *Section = CustomSectionsByIndex[Sym.Info.ElementIndex]; + assert(Sym.isBindingLocal()); + return make<SectionSymbol>(Name, Flags, Section, this); + } + } + llvm_unreachable("unknown symbol kind"); } -Symbol *ObjFile::createDefined(const WasmSymbol &Sym, - const InputSegment *Segment) { - Symbol *S; - if (Sym.isLocal()) { - S = make<Symbol>(Sym.Name, true); - Symbol::Kind Kind; - if (Sym.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT) - Kind = Symbol::Kind::DefinedFunctionKind; - else if (Sym.Type == WasmSymbol::SymbolType::GLOBAL_EXPORT) - Kind = Symbol::Kind::DefinedGlobalKind; - else - llvm_unreachable("invalid local symbol type"); - S->update(Kind, this, &Sym, Segment); - return S; +Symbol *ObjFile::createUndefined(const WasmSymbol &Sym) { + StringRef Name = Sym.Info.Name; + uint32_t Flags = Sym.Info.Flags; + + switch (Sym.Info.Kind) { + case WASM_SYMBOL_TYPE_FUNCTION: + return Symtab->addUndefinedFunction(Name, Flags, this, Sym.FunctionType); + case WASM_SYMBOL_TYPE_DATA: + return Symtab->addUndefinedData(Name, Flags, this); + case WASM_SYMBOL_TYPE_GLOBAL: + return Symtab->addUndefinedGlobal(Name, Flags, this, Sym.GlobalType); + case WASM_SYMBOL_TYPE_SECTION: + llvm_unreachable("section symbols cannot be undefined"); } - return Symtab->addDefined(this, &Sym, Segment); + llvm_unreachable("unknown symbol kind"); } void ArchiveFile::parse() { // Parse a MemoryBufferRef as an archive file. - DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n"); + LLVM_DEBUG(dbgs() << "Parsing library: " << toString(this) << "\n"); File = CHECK(Archive::create(MB), toString(this)); // Read the symbol table to construct Lazy symbols. @@ -269,7 +350,7 @@ void ArchiveFile::parse() { Symtab->addLazy(this, &Sym); ++Count; } - DEBUG(dbgs() << "Read " << Count << " symbols\n"); + LLVM_DEBUG(dbgs() << "Read " << Count << " symbols\n"); } void ArchiveFile::addMember(const Archive::Symbol *Sym) { @@ -282,22 +363,59 @@ void ArchiveFile::addMember(const Archive::Symbol *Sym) { if (!Seen.insert(C.getChildOffset()).second) return; - DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n"); - DEBUG(dbgs() << "from archive: " << toString(this) << "\n"); + LLVM_DEBUG(dbgs() << "loading lazy: " << Sym->getName() << "\n"); + LLVM_DEBUG(dbgs() << "from archive: " << toString(this) << "\n"); MemoryBufferRef MB = CHECK(C.getMemoryBufferRef(), "could not get the buffer for the member defining symbol " + Sym->getName()); - if (identify_magic(MB.getBuffer()) != file_magic::wasm_object) { - error("unknown file type: " + MB.getBufferIdentifier()); + InputFile *Obj = createObjectFile(MB); + Obj->ArchiveName = getName(); + Symtab->addFile(Obj); +} + +static uint8_t mapVisibility(GlobalValue::VisibilityTypes GvVisibility) { + switch (GvVisibility) { + case GlobalValue::DefaultVisibility: + return WASM_SYMBOL_VISIBILITY_DEFAULT; + case GlobalValue::HiddenVisibility: + case GlobalValue::ProtectedVisibility: + return WASM_SYMBOL_VISIBILITY_HIDDEN; + } + llvm_unreachable("unknown visibility"); +} + +static Symbol *createBitcodeSymbol(const lto::InputFile::Symbol &ObjSym, + BitcodeFile &F) { + StringRef Name = Saver.save(ObjSym.getName()); + + uint32_t Flags = ObjSym.isWeak() ? WASM_SYMBOL_BINDING_WEAK : 0; + Flags |= mapVisibility(ObjSym.getVisibility()); + + if (ObjSym.isUndefined()) { + if (ObjSym.isExecutable()) + return Symtab->addUndefinedFunction(Name, Flags, &F, nullptr); + return Symtab->addUndefinedData(Name, Flags, &F); + } + + if (ObjSym.isExecutable()) + return Symtab->addDefinedFunction(Name, Flags, &F, nullptr); + return Symtab->addDefinedData(Name, Flags, &F, nullptr, 0, 0); +} + +void BitcodeFile::parse() { + Obj = check(lto::InputFile::create(MemoryBufferRef( + MB.getBuffer(), Saver.save(ArchiveName + MB.getBufferIdentifier())))); + Triple T(Obj->getTargetTriple()); + if (T.getArch() != Triple::wasm32) { + error(toString(MB.getBufferIdentifier()) + ": machine type must be wasm32"); return; } - InputFile *Obj = make<ObjFile>(MB); - Obj->ParentName = ParentName; - Symtab->addFile(Obj); + for (const lto::InputFile::Symbol &ObjSym : Obj->symbols()) + Symbols.push_back(createBitcodeSymbol(ObjSym, *this)); } // Returns a string in the format of "foo.o" or "foo.a(bar.o)". @@ -305,8 +423,8 @@ std::string lld::toString(const wasm::InputFile *File) { if (!File) return "<internal>"; - if (File->ParentName.empty()) + if (File->ArchiveName.empty()) return File->getName(); - return (File->ParentName + "(" + File->getName() + ")").str(); + return (File->ArchiveName + "(" + File->getName() + ")").str(); } diff --git a/wasm/InputFiles.h b/wasm/InputFiles.h index 158cc53cafb1..ec77446e6308 100644 --- a/wasm/InputFiles.h +++ b/wasm/InputFiles.h @@ -10,34 +10,46 @@ #ifndef LLD_WASM_INPUT_FILES_H #define LLD_WASM_INPUT_FILES_H +#include "Symbols.h" #include "lld/Common/LLVM.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/LTO/LTO.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Wasm.h" #include "llvm/Support/MemoryBuffer.h" - -#include "WriterUtils.h" - #include <vector> using llvm::object::Archive; using llvm::object::WasmObjectFile; using llvm::object::WasmSection; using llvm::object::WasmSymbol; +using llvm::wasm::WasmGlobal; using llvm::wasm::WasmImport; +using llvm::wasm::WasmRelocation; +using llvm::wasm::WasmSignature; + +namespace llvm { +namespace lto { +class InputFile; +} +} // namespace llvm namespace lld { namespace wasm { -class Symbol; +class InputChunk; +class InputFunction; class InputSegment; +class InputGlobal; +class InputSection; class InputFile { public: enum Kind { ObjectKind, ArchiveKind, + BitcodeKind, }; virtual ~InputFile() {} @@ -51,12 +63,17 @@ public: Kind kind() const { return FileKind; } // An archive file name if this file is created from an archive. - StringRef ParentName; + StringRef ArchiveName; + + ArrayRef<Symbol *> getSymbols() const { return Symbols; } protected: InputFile(Kind K, MemoryBufferRef M) : MB(M), FileKind(K) {} MemoryBufferRef MB; + // List of all symbols referenced or defined by this file. + std::vector<Symbol *> Symbols; + private: const Kind FileKind; }; @@ -89,58 +106,54 @@ public: void dumpInfo() const; - uint32_t relocateTypeIndex(uint32_t Original) const; - uint32_t relocateFunctionIndex(uint32_t Original) const; - uint32_t relocateGlobalIndex(uint32_t Original) const; - uint32_t relocateTableIndex(uint32_t Original) const; - uint32_t getRelocatedAddress(uint32_t Index) const; - - // Returns true if the given function index is an imported function, - // as opposed to the locally defined function. - bool isImportedFunction(uint32_t Index) const; - - size_t NumFunctionImports() const { return FunctionImports; } - size_t NumGlobalImports() const { return GlobalImports; } + uint32_t calcNewIndex(const WasmRelocation &Reloc) const; + uint32_t calcNewValue(const WasmRelocation &Reloc) const; + uint32_t calcNewAddend(const WasmRelocation &Reloc) const; + uint32_t calcExpectedValue(const WasmRelocation &Reloc) const; - int32_t FunctionIndexOffset = 0; const WasmSection *CodeSection = nullptr; - std::vector<OutputRelocation> CodeRelocations; - int32_t CodeOffset = 0; const WasmSection *DataSection = nullptr; + // Maps input type indices to output type indices std::vector<uint32_t> TypeMap; + std::vector<bool> TypeIsUsed; + // Maps function indices to table indices + std::vector<uint32_t> TableEntries; + std::vector<bool> UsedComdats; std::vector<InputSegment *> Segments; + std::vector<InputFunction *> Functions; + std::vector<InputGlobal *> Globals; + std::vector<InputSection *> CustomSections; + llvm::DenseMap<uint32_t, InputSection *> CustomSectionsByIndex; - ArrayRef<Symbol *> getSymbols() { return Symbols; } - ArrayRef<Symbol *> getTableSymbols() { return TableSymbols; } + Symbol *getSymbol(uint32_t Index) const { return Symbols[Index]; } + FunctionSymbol *getFunctionSymbol(uint32_t Index) const; + DataSymbol *getDataSymbol(uint32_t Index) const; + GlobalSymbol *getGlobalSymbol(uint32_t Index) const; + SectionSymbol *getSectionSymbol(uint32_t Index) const; private: - Symbol *createDefined(const WasmSymbol &Sym, - const InputSegment *Segment = nullptr); + Symbol *createDefined(const WasmSymbol &Sym); Symbol *createUndefined(const WasmSymbol &Sym); - void initializeSymbols(); - InputSegment *getSegment(const WasmSymbol &WasmSym); - Symbol *getFunctionSymbol(uint32_t FunctionIndex) const; - Symbol *getTableSymbol(uint32_t TableIndex) const; - Symbol *getGlobalSymbol(uint32_t GlobalIndex) const; - // List of all symbols referenced or defined by this file. - std::vector<Symbol *> Symbols; - - // List of all function symbols indexed by the function index space - std::vector<Symbol *> FunctionSymbols; + bool isExcludedByComdat(InputChunk *Chunk) const; - // List of all global symbols indexed by the global index space - std::vector<Symbol *> GlobalSymbols; + std::unique_ptr<WasmObjectFile> WasmObj; +}; - // List of all indirect symbols indexed by table index space. - std::vector<Symbol *> TableSymbols; +class BitcodeFile : public InputFile { +public: + explicit BitcodeFile(MemoryBufferRef M) : InputFile(BitcodeKind, M) {} + static bool classof(const InputFile *F) { return F->kind() == BitcodeKind; } - uint32_t GlobalImports = 0; - uint32_t FunctionImports = 0; - std::unique_ptr<WasmObjectFile> WasmObj; + void parse() override; + std::unique_ptr<llvm::lto::InputFile> Obj; }; +// Will report a fatal() error if the input buffer is not a valid bitcode +// or was object file. +InputFile *createObjectFile(MemoryBufferRef MB); + // Opens a given file. llvm::Optional<MemoryBufferRef> readFile(StringRef Path); diff --git a/wasm/InputGlobal.h b/wasm/InputGlobal.h new file mode 100644 index 000000000000..37d0ab903706 --- /dev/null +++ b/wasm/InputGlobal.h @@ -0,0 +1,59 @@ +//===- InputGlobal.h --------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_INPUT_GLOBAL_H +#define LLD_WASM_INPUT_GLOBAL_H + +#include "Config.h" +#include "InputFiles.h" +#include "WriterUtils.h" +#include "lld/Common/ErrorHandler.h" +#include "llvm/Object/Wasm.h" + +using llvm::wasm::WasmGlobal; +using llvm::wasm::WasmInitExpr; + +namespace lld { +namespace wasm { + +// Represents a single Wasm Global Variable within an input file. These are +// combined to form the final GLOBALS section. +class InputGlobal { +public: + InputGlobal(const WasmGlobal &G, ObjFile *F) + : File(F), Global(G), Live(!Config->GcSections) {} + + StringRef getName() const { return Global.SymbolName; } + const WasmGlobalType &getType() const { return Global.Type; } + + uint32_t getGlobalIndex() const { return GlobalIndex.getValue(); } + bool hasGlobalIndex() const { return GlobalIndex.hasValue(); } + void setGlobalIndex(uint32_t Index) { + assert(!hasGlobalIndex()); + GlobalIndex = Index; + } + + ObjFile *File; + WasmGlobal Global; + + bool Live = false; + +protected: + llvm::Optional<uint32_t> GlobalIndex; +}; + +} // namespace wasm + +inline std::string toString(const wasm::InputGlobal *G) { + return (toString(G->File) + ":(" + G->getName() + ")").str(); +} + +} // namespace lld + +#endif // LLD_WASM_INPUT_GLOBAL_H diff --git a/wasm/InputSegment.cpp b/wasm/InputSegment.cpp deleted file mode 100644 index 650914386259..000000000000 --- a/wasm/InputSegment.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//===- InputSegment.cpp ---------------------------------------------------===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "InputSegment.h" -#include "OutputSegment.h" -#include "lld/Common/LLVM.h" - -#define DEBUG_TYPE "lld" - -using namespace llvm; -using namespace lld::wasm; - -uint32_t InputSegment::translateVA(uint32_t Address) const { - assert(Address >= startVA() && Address < endVA()); - int32_t Delta = OutputSeg->StartVA + OutputSegmentOffset - startVA(); - DEBUG(dbgs() << "translateVA: " << getName() << " Delta=" << Delta - << " Address=" << Address << "\n"); - return Address + Delta; -} diff --git a/wasm/InputSegment.h b/wasm/InputSegment.h deleted file mode 100644 index f70a3ded895e..000000000000 --- a/wasm/InputSegment.h +++ /dev/null @@ -1,76 +0,0 @@ -//===- InputSegment.h -------------------------------------------*- C++ -*-===// -// -// The LLVM Linker -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// Represents a WebAssembly data segment which can be included as part of -// an output data segments. Note that in WebAssembly, unlike ELF and other -// formats, used the term "data segment" to refer to the continous regions of -// memory that make on the data section. See: -// https://webassembly.github.io/spec/syntax/modules.html#syntax-data -// -// For example, by default, clang will produce a separate data section for -// each global variable. -// -//===----------------------------------------------------------------------===// - -#ifndef LLD_WASM_INPUT_SEGMENT_H -#define LLD_WASM_INPUT_SEGMENT_H - -#include "WriterUtils.h" -#include "lld/Common/ErrorHandler.h" -#include "llvm/Object/Wasm.h" - -using llvm::object::WasmSegment; -using llvm::wasm::WasmRelocation; - -namespace lld { -namespace wasm { - -class ObjFile; -class OutputSegment; - -class InputSegment { -public: - InputSegment(const WasmSegment *Seg, const ObjFile *F) - : Segment(Seg), File(F) {} - - // Translate an offset in the input segment to an offset in the output - // segment. - uint32_t translateVA(uint32_t Address) const; - - const OutputSegment *getOutputSegment() const { return OutputSeg; } - - uint32_t getOutputSegmentOffset() const { return OutputSegmentOffset; } - - uint32_t getInputSectionOffset() const { return Segment->SectionOffset; } - - void setOutputSegment(const OutputSegment *Segment, uint32_t Offset) { - OutputSeg = Segment; - OutputSegmentOffset = Offset; - } - - uint32_t getSize() const { return Segment->Data.Content.size(); } - uint32_t getAlignment() const { return Segment->Data.Alignment; } - uint32_t startVA() const { return Segment->Data.Offset.Value.Int32; } - uint32_t endVA() const { return startVA() + getSize(); } - StringRef getName() const { return Segment->Data.Name; } - - const WasmSegment *Segment; - const ObjFile *File; - std::vector<WasmRelocation> Relocations; - std::vector<OutputRelocation> OutRelocations; - -protected: - const OutputSegment *OutputSeg = nullptr; - uint32_t OutputSegmentOffset = 0; -}; - -} // namespace wasm -} // namespace lld - -#endif // LLD_WASM_INPUT_SEGMENT_H diff --git a/wasm/LTO.cpp b/wasm/LTO.cpp new file mode 100644 index 000000000000..f15551da8b80 --- /dev/null +++ b/wasm/LTO.cpp @@ -0,0 +1,155 @@ +//===- LTO.cpp ------------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "LTO.h" +#include "Config.h" +#include "InputFiles.h" +#include "Symbols.h" +#include "lld/Common/ErrorHandler.h" +#include "lld/Common/Strings.h" +#include "lld/Common/TargetOptionsCommandFlags.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/LTO/Caching.h" +#include "llvm/LTO/Config.h" +#include "llvm/LTO/LTO.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include <algorithm> +#include <cstddef> +#include <memory> +#include <string> +#include <system_error> +#include <vector> + +using namespace llvm; +using namespace llvm::object; + +using namespace lld; +using namespace lld::wasm; + +static std::unique_ptr<lto::LTO> createLTO() { + lto::Config C; + C.Options = InitTargetOptionsFromCodeGenFlags(); + + // Always emit a section per function/data with LTO. + C.Options.FunctionSections = true; + C.Options.DataSections = true; + + // Wasm currently only supports ThreadModel::Single + C.Options.ThreadModel = ThreadModel::Single; + + C.DisableVerify = Config->DisableVerify; + C.DiagHandler = diagnosticHandler; + C.OptLevel = Config->LTOO; + + if (Config->SaveTemps) + checkError(C.addSaveTemps(Config->OutputFile.str() + ".", + /*UseInputModulePath*/ true)); + + lto::ThinBackend Backend; + if (Config->ThinLTOJobs != -1U) + Backend = lto::createInProcessThinBackend(Config->ThinLTOJobs); + return llvm::make_unique<lto::LTO>(std::move(C), Backend, + Config->LTOPartitions); +} + +BitcodeCompiler::BitcodeCompiler() : LTOObj(createLTO()) {} + +BitcodeCompiler::~BitcodeCompiler() = default; + +static void undefine(Symbol *S) { + if (isa<DefinedFunction>(S)) + replaceSymbol<UndefinedFunction>(S, S->getName(), 0); + else if (isa<DefinedData>(S)) + replaceSymbol<UndefinedData>(S, S->getName(), 0); + else + llvm_unreachable("unexpected symbol kind"); +} + +void BitcodeCompiler::add(BitcodeFile &F) { + lto::InputFile &Obj = *F.Obj; + unsigned SymNum = 0; + ArrayRef<Symbol *> Syms = F.getSymbols(); + std::vector<lto::SymbolResolution> Resols(Syms.size()); + + // Provide a resolution to the LTO API for each symbol. + for (const lto::InputFile::Symbol &ObjSym : Obj.symbols()) { + Symbol *Sym = Syms[SymNum]; + lto::SymbolResolution &R = Resols[SymNum]; + ++SymNum; + + // Ideally we shouldn't check for SF_Undefined but currently IRObjectFile + // reports two symbols for module ASM defined. Without this check, lld + // flags an undefined in IR with a definition in ASM as prevailing. + // Once IRObjectFile is fixed to report only one symbol this hack can + // be removed. + R.Prevailing = !ObjSym.isUndefined() && Sym->getFile() == &F; + R.VisibleToRegularObj = Config->Relocatable || Sym->IsUsedInRegularObj || + (R.Prevailing && Sym->isExported()); + if (R.Prevailing) + undefine(Sym); + } + checkError(LTOObj->add(std::move(F.Obj), Resols)); +} + +// Merge all the bitcode files we have seen, codegen the result +// and return the resulting objects. +std::vector<StringRef> BitcodeCompiler::compile() { + unsigned MaxTasks = LTOObj->getMaxTasks(); + Buf.resize(MaxTasks); + Files.resize(MaxTasks); + + // The --thinlto-cache-dir option specifies the path to a directory in which + // to cache native object files for ThinLTO incremental builds. If a path was + // specified, configure LTO to use it as the cache directory. + lto::NativeObjectCache Cache; + if (!Config->ThinLTOCacheDir.empty()) + Cache = check( + lto::localCache(Config->ThinLTOCacheDir, + [&](size_t Task, std::unique_ptr<MemoryBuffer> MB) { + Files[Task] = std::move(MB); + })); + + checkError(LTOObj->run( + [&](size_t Task) { + return llvm::make_unique<lto::NativeObjectStream>( + llvm::make_unique<raw_svector_ostream>(Buf[Task])); + }, + Cache)); + + if (!Config->ThinLTOCacheDir.empty()) + pruneCache(Config->ThinLTOCacheDir, Config->ThinLTOCachePolicy); + + std::vector<StringRef> Ret; + for (unsigned I = 0; I != MaxTasks; ++I) { + if (Buf[I].empty()) + continue; + if (Config->SaveTemps) { + if (I == 0) + saveBuffer(Buf[I], Config->OutputFile + ".lto.o"); + else + saveBuffer(Buf[I], Config->OutputFile + Twine(I) + ".lto.o"); + } + Ret.emplace_back(Buf[I].data(), Buf[I].size()); + } + + for (std::unique_ptr<MemoryBuffer> &File : Files) + if (File) + Ret.push_back(File->getBuffer()); + + return Ret; +} diff --git a/wasm/LTO.h b/wasm/LTO.h new file mode 100644 index 000000000000..cf726de5643a --- /dev/null +++ b/wasm/LTO.h @@ -0,0 +1,57 @@ +//===- LTO.h ----------------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides a way to combine bitcode files into one wasm +// file by compiling them using LLVM. +// +// If LTO is in use, your input files are not in regular wasm files +// but instead LLVM bitcode files. In that case, the linker has to +// convert bitcode files into the native format so that we can create +// a wasm file that contains native code. This file provides that +// functionality. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_LTO_H +#define LLD_WASM_LTO_H + +#include "lld/Common/LLVM.h" +#include "llvm/ADT/SmallString.h" +#include <memory> +#include <vector> + +namespace llvm { +namespace lto { +class LTO; +} +} // namespace llvm + +namespace lld { +namespace wasm { + +class BitcodeFile; +class InputFile; + +class BitcodeCompiler { +public: + BitcodeCompiler(); + ~BitcodeCompiler(); + + void add(BitcodeFile &F); + std::vector<StringRef> compile(); + +private: + std::unique_ptr<llvm::lto::LTO> LTOObj; + std::vector<SmallString<0>> Buf; + std::vector<std::unique_ptr<MemoryBuffer>> Files; +}; +} // namespace wasm +} // namespace lld + +#endif diff --git a/wasm/MarkLive.cpp b/wasm/MarkLive.cpp new file mode 100644 index 000000000000..dfaa712c3296 --- /dev/null +++ b/wasm/MarkLive.cpp @@ -0,0 +1,118 @@ +//===- MarkLive.cpp -------------------------------------------------------===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements --gc-sections, which is a feature to remove unused +// chunks from the output. Unused chunks are those that are not reachable from +// known root symbols or chunks. This feature is implemented as a mark-sweep +// garbage collector. +// +// Here's how it works. Each InputChunk has a "Live" bit. The bit is off by +// default. Starting with the GC-roots, visit all reachable chunks and set their +// Live bits. The Writer will then ignore chunks whose Live bits are off, so +// that such chunk are not appear in the output. +// +//===----------------------------------------------------------------------===// + +#include "MarkLive.h" +#include "Config.h" +#include "InputChunks.h" +#include "InputGlobal.h" +#include "SymbolTable.h" +#include "Symbols.h" + +#define DEBUG_TYPE "lld" + +using namespace llvm; +using namespace llvm::wasm; +using namespace lld; +using namespace lld::wasm; + +void lld::wasm::markLive() { + if (!Config->GcSections) + return; + + LLVM_DEBUG(dbgs() << "markLive\n"); + SmallVector<InputChunk *, 256> Q; + + auto Enqueue = [&](Symbol *Sym) { + if (!Sym || Sym->isLive()) + return; + LLVM_DEBUG(dbgs() << "markLive: " << Sym->getName() << "\n"); + Sym->markLive(); + if (InputChunk *Chunk = Sym->getChunk()) + Q.push_back(Chunk); + }; + + // Add GC root symbols. + if (!Config->Entry.empty()) + Enqueue(Symtab->find(Config->Entry)); + Enqueue(WasmSym::CallCtors); + + // We need to preserve any exported symbol + for (Symbol *Sym : Symtab->getSymbols()) + if (Sym->isExported()) + Enqueue(Sym); + + // The ctor functions are all used in the synthetic __wasm_call_ctors + // function, but since this function is created in-place it doesn't contain + // relocations which mean we have to manually mark the ctors. + for (const ObjFile *Obj : Symtab->ObjectFiles) { + const WasmLinkingData &L = Obj->getWasmObj()->linkingData(); + for (const WasmInitFunc &F : L.InitFunctions) + Enqueue(Obj->getFunctionSymbol(F.Symbol)); + } + + // Follow relocations to mark all reachable chunks. + while (!Q.empty()) { + InputChunk *C = Q.pop_back_val(); + + for (const WasmRelocation Reloc : C->getRelocations()) { + if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) + continue; + Symbol *Sym = C->File->getSymbol(Reloc.Index); + + // If the function has been assigned the special index zero in the table, + // the relocation doesn't pull in the function body, since the function + // won't actually go in the table (the runtime will trap attempts to call + // that index, since we don't use it). A function with a table index of + // zero is only reachable via "call", not via "call_indirect". The stub + // functions used for weak-undefined symbols have this behaviour (compare + // equal to null pointer, only reachable via direct call). + if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB || + Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32) { + FunctionSymbol *FuncSym = cast<FunctionSymbol>(Sym); + if (FuncSym->hasTableIndex() && FuncSym->getTableIndex() == 0) + continue; + } + + Enqueue(Sym); + } + } + + // Report garbage-collected sections. + if (Config->PrintGcSections) { + for (const ObjFile *Obj : Symtab->ObjectFiles) { + for (InputChunk *C : Obj->Functions) + if (!C->Live) + message("removing unused section " + toString(C)); + for (InputChunk *C : Obj->Segments) + if (!C->Live) + message("removing unused section " + toString(C)); + for (InputGlobal *G : Obj->Globals) + if (!G->Live) + message("removing unused section " + toString(G)); + } + for (InputChunk *C : Symtab->SyntheticFunctions) + if (!C->Live) + message("removing unused section " + toString(C)); + for (InputGlobal *G : Symtab->SyntheticGlobals) + if (!G->Live) + message("removing unused section " + toString(G)); + } +} diff --git a/wasm/MarkLive.h b/wasm/MarkLive.h new file mode 100644 index 000000000000..0b58f153ce45 --- /dev/null +++ b/wasm/MarkLive.h @@ -0,0 +1,21 @@ +//===- MarkLive.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Linker +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLD_WASM_MARKLIVE_H +#define LLD_WASM_MARKLIVE_H + +namespace lld { +namespace wasm { + +void markLive(); + +} // namespace wasm +} // namespace lld + +#endif // LLD_WASM_MARKLIVE_H diff --git a/wasm/Options.td b/wasm/Options.td index df0c6d708072..43588a830e31 100644 --- a/wasm/Options.td +++ b/wasm/Options.td @@ -11,21 +11,47 @@ multiclass Eq<string name> { def _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>; } -def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, - HelpText<"Add a directory to the library search path">; +multiclass B<string name, string help1, string help2> { + def NAME: Flag<["--", "-"], name>, HelpText<help1>; + def no_ # NAME: Flag<["--", "-"], "no-" # name>, HelpText<help2>; +} +// The follow flags are shared with the ELF linker def color_diagnostics: F<"color-diagnostics">, HelpText<"Use colors in diagnostics">; def color_diagnostics_eq: J<"color-diagnostics=">, - HelpText<"Use colors in diagnostics">; + HelpText<"Use colors in diagnostics; one of 'always', 'never', 'auto'">; + +defm demangle: B<"demangle", + "Demangle symbol names", + "Do not demangle symbol names">; + +def entry: S<"entry">, MetaVarName<"<entry>">, + HelpText<"Name of entry point symbol">; + +def error_limit: J<"error-limit=">, + HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">; + +def fatal_warnings: F<"fatal-warnings">, + HelpText<"Treat warnings as errors">; + +defm gc_sections: B<"gc-sections", + "Enable garbage collection of unused sections", + "Disable garbage collection of unused sections">; + +defm merge_data_segments: B<"merge-data-segments", + "Enable merging data segments", + "Disable merging data segments">; -// The follow flags are shared with the ELF linker def help: F<"help">, HelpText<"Print option help">; def l: JoinedOrSeparate<["-"], "l">, MetaVarName<"<libName>">, HelpText<"Root name of library to use">; +def L: JoinedOrSeparate<["-"], "L">, MetaVarName<"<dir>">, + HelpText<"Add a directory to the library search path">; + def mllvm: S<"mllvm">, HelpText<"Options to pass to LLVM">; def no_threads: F<"no-threads">, @@ -34,70 +60,99 @@ def no_threads: F<"no-threads">, def no_color_diagnostics: F<"no-color-diagnostics">, HelpText<"Do not use colors in diagnostics">; -def no_check_signatures: F<"no-check-signatures">, HelpText<"Don't check function signatures">; +def no_fatal_warnings: F<"no-fatal-warnings">; def o: JoinedOrSeparate<["-"], "o">, MetaVarName<"<path>">, HelpText<"Path to file to write output">; -def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; +def O: JoinedOrSeparate<["-"], "O">, HelpText<"Optimize output file size">; -def check_signatures: F<"check-signatures">, HelpText<"Check function signatures">; - -def v: Flag<["-"], "v">, HelpText<"Display the version number">; - -def version: F<"version">, HelpText<"Display the version number and exit">; - -def verbose: F<"verbose">, HelpText<"Verbose mode">; +defm print_gc_sections: B<"print-gc-sections", + "List removed unused sections", + "Do not list removed unused sections">; def relocatable: F<"relocatable">, HelpText<"Create relocatable object file">; -def emit_relocs: F<"emit-relocs">, HelpText<"Generate relocations in output">; - def strip_all: F<"strip-all">, HelpText<"Strip all symbols">; def strip_debug: F<"strip-debug">, HelpText<"Strip debugging information">; +def threads: F<"threads">, HelpText<"Run the linker multi-threaded">; + defm undefined: Eq<"undefined">, HelpText<"Force undefined symbol during linking">; +def v: Flag<["-"], "v">, HelpText<"Display the version number">; + +def verbose: F<"verbose">, HelpText<"Verbose mode">; + +def version: F<"version">, HelpText<"Display the version number and exit">; + def z: JoinedOrSeparate<["-"], "z">, MetaVarName<"<option>">, HelpText<"Linker option extensions">; -def entry: S<"entry">, MetaVarName<"<entry>">, - HelpText<"Name of entry point symbol">; +// The follow flags are unique to wasm -def no_entry: F<"no-entry">, - HelpText<"Do not output any entry point">; +def allow_undefined: F<"allow-undefined">, + HelpText<"Allow undefined symbols in linked binary">; -def error_limit: J<"error-limit=">, - HelpText<"Maximum number of errors to emit before stopping (0 = no limit)">; +def allow_undefined_file: J<"allow-undefined-file=">, + HelpText<"Allow symbols listed in <file> to be undefined in linked binary">; -// The follow flags are unique to wasm +def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">, + Alias<allow_undefined_file>; + +defm export: Eq<"export">, + HelpText<"Force a symbol to be exported">; + +def export_all: F<"export-all">, + HelpText<"Export all symbols (normally combined with --no-gc-sections)">; + +def export_table: F<"export-table">, + HelpText<"Export function table to the environment">; def global_base: J<"global-base=">, HelpText<"Where to start to place global data">; +def import_memory: F<"import-memory">, + HelpText<"Import memory from the environment">; + +def import_table: F<"import-table">, + HelpText<"Import function table from the environment">; + def initial_memory: J<"initial-memory=">, HelpText<"Initial size of the linear memory">; def max_memory: J<"max-memory=">, HelpText<"Maximum size of the linear memory">; -def import_memory: F<"import-memory">, - HelpText<"Import memory from the environment">; - -def allow_undefined: F<"allow-undefined">, - HelpText<"Allow undefined symbols in linked binary">; +def no_entry: F<"no-entry">, + HelpText<"Do not output any entry point">; -def allow_undefined_file: J<"allow-undefined-file=">, - HelpText<"Allow symbols listed in <file> to be undefined in linked binary">; +def stack_first: F<"stack-first">, + HelpText<"Place stack at start of linear memory rather than after data">; -def allow_undefined_file_s: Separate<["-"], "allow-undefined-file">, Alias<allow_undefined_file>; +defm whole_archive: B<"whole-archive", + "Force load of all members in a static library", + "Do not force load of all members in a static library (default)">; // Aliases +def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; +def alias_entry_entry: J<"entry=">, Alias<entry>; def alias_initial_memory_i: Flag<["-"], "i">, Alias<initial_memory>; def alias_max_memory_m: Flag<["-"], "m">, Alias<max_memory>; def alias_relocatable_r: Flag<["-"], "r">, Alias<relocatable>; -def alias_entry_e: JoinedOrSeparate<["-"], "e">, Alias<entry>; -def alias_entry_entry: J<"entry=">, Alias<entry>; def alias_undefined_u: JoinedOrSeparate<["-"], "u">, Alias<undefined>; + +// LTO-related options. +def lto_O: J<"lto-O">, MetaVarName<"<opt-level>">, + HelpText<"Optimization level for LTO">; +def lto_partitions: J<"lto-partitions=">, + HelpText<"Number of LTO codegen partitions">; +def disable_verify: F<"disable-verify">; +def save_temps: F<"save-temps">; +def thinlto_cache_dir: J<"thinlto-cache-dir=">, + HelpText<"Path to ThinLTO cached object file directory">; +defm thinlto_cache_policy: Eq<"thinlto-cache-policy">, + HelpText<"Pruning policy for the ThinLTO cache">; +def thinlto_jobs: J<"thinlto-jobs=">, HelpText<"Number of ThinLTO jobs">; diff --git a/wasm/OutputSections.cpp b/wasm/OutputSections.cpp index a55538269065..256a9884f947 100644 --- a/wasm/OutputSections.cpp +++ b/wasm/OutputSections.cpp @@ -8,13 +8,11 @@ //===----------------------------------------------------------------------===// #include "OutputSections.h" - -#include "Config.h" +#include "InputChunks.h" #include "InputFiles.h" #include "OutputSegment.h" -#include "SymbolTable.h" +#include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" -#include "lld/Common/Memory.h" #include "lld/Common/Threads.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/LEB128.h" @@ -26,12 +24,6 @@ using namespace llvm::wasm; using namespace lld; using namespace lld::wasm; -enum class RelocEncoding { - Uleb128, - Sleb128, - I32, -}; - static StringRef sectionTypeToString(uint32_t SectionType) { switch (SectionType) { case WASM_SEC_CUSTOM: @@ -63,159 +55,40 @@ static StringRef sectionTypeToString(uint32_t SectionType) { } } -std::string lld::toString(const OutputSection &Section) { - std::string rtn = Section.getSectionName(); - if (!Section.Name.empty()) - rtn += "(" + Section.Name + ")"; - return rtn; -} - -static void applyRelocation(uint8_t *Buf, const OutputRelocation &Reloc) { - DEBUG(dbgs() << "write reloc: type=" << Reloc.Reloc.Type - << " index=" << Reloc.Reloc.Index << " value=" << Reloc.Value - << " offset=" << Reloc.Reloc.Offset << "\n"); - Buf += Reloc.Reloc.Offset; - int64_t ExistingValue; - switch (Reloc.Reloc.Type) { - case R_WEBASSEMBLY_TYPE_INDEX_LEB: - case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - ExistingValue = decodeULEB128(Buf); - if (ExistingValue != Reloc.Reloc.Index) { - DEBUG(dbgs() << "existing value: " << decodeULEB128(Buf) << "\n"); - assert(decodeULEB128(Buf) == Reloc.Reloc.Index); - } - LLVM_FALLTHROUGH; - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - encodeULEB128(Reloc.Value, Buf, 5); - break; - case R_WEBASSEMBLY_TABLE_INDEX_SLEB: - ExistingValue = decodeSLEB128(Buf); - if (ExistingValue != Reloc.Reloc.Index) { - DEBUG(dbgs() << "existing value: " << decodeSLEB128(Buf) << "\n"); - assert(decodeSLEB128(Buf) == Reloc.Reloc.Index); - } - LLVM_FALLTHROUGH; - case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - encodeSLEB128(static_cast<int32_t>(Reloc.Value), Buf, 5); - break; - case R_WEBASSEMBLY_TABLE_INDEX_I32: - case R_WEBASSEMBLY_MEMORY_ADDR_I32: - support::endian::write32<support::little>(Buf, Reloc.Value); - break; - default: - llvm_unreachable("unknown relocation type"); - } -} - -static void applyRelocations(uint8_t *Buf, ArrayRef<OutputRelocation> Relocs) { - if (!Relocs.size()) - return; - log("applyRelocations: count=" + Twine(Relocs.size())); - for (const OutputRelocation &Reloc : Relocs) - applyRelocation(Buf, Reloc); -} - -// Relocations contain an index into the function, global or table index -// space of the input file. This function takes a relocation and returns the -// relocated index (i.e. translates from the input index space to the output -// index space). -static uint32_t calcNewIndex(const ObjFile &File, const WasmRelocation &Reloc) { - switch (Reloc.Type) { - case R_WEBASSEMBLY_TYPE_INDEX_LEB: - return File.relocateTypeIndex(Reloc.Index); - case R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - return File.relocateFunctionIndex(Reloc.Index); - case R_WEBASSEMBLY_TABLE_INDEX_I32: - case R_WEBASSEMBLY_TABLE_INDEX_SLEB: - return File.relocateTableIndex(Reloc.Index); - case R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case R_WEBASSEMBLY_MEMORY_ADDR_I32: - return File.relocateGlobalIndex(Reloc.Index); - default: - llvm_unreachable("unknown relocation type"); - } -} - -// Take a vector of relocations from an input file and create output -// relocations based on them. Calculates the updated index and offset for -// each relocation as well as the value to write out in the final binary. -static void calcRelocations(const ObjFile &File, - ArrayRef<WasmRelocation> Relocs, - std::vector<OutputRelocation> &OutputRelocs, - int32_t OutputOffset) { - log("calcRelocations: " + File.getName() + " offset=" + Twine(OutputOffset)); - for (const WasmRelocation &Reloc : Relocs) { - OutputRelocation NewReloc; - NewReloc.Reloc = Reloc; - NewReloc.Reloc.Offset += OutputOffset; - DEBUG(dbgs() << "reloc: type=" << Reloc.Type << " index=" << Reloc.Index - << " offset=" << Reloc.Offset - << " newOffset=" << NewReloc.Reloc.Offset << "\n"); - - if (Config->EmitRelocs) - NewReloc.NewIndex = calcNewIndex(File, Reloc); - else - NewReloc.NewIndex = UINT32_MAX; - - switch (Reloc.Type) { - case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case R_WEBASSEMBLY_MEMORY_ADDR_I32: - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - NewReloc.Value = File.getRelocatedAddress(Reloc.Index); - if (NewReloc.Value != UINT32_MAX) - NewReloc.Value += Reloc.Addend; - break; - default: - NewReloc.Value = calcNewIndex(File, Reloc); - break; - } - - OutputRelocs.emplace_back(NewReloc); - } +// Returns a string, e.g. "FUNCTION(.text)". +std::string lld::toString(const OutputSection &Sec) { + if (!Sec.Name.empty()) + return (Sec.getSectionName() + "(" + Sec.Name + ")").str(); + return Sec.getSectionName(); } -std::string OutputSection::getSectionName() const { +StringRef OutputSection::getSectionName() const { return sectionTypeToString(Type); } -std::string SubSection::getSectionName() const { - return std::string("subsection <type=") + std::to_string(Type) + ">"; -} - void OutputSection::createHeader(size_t BodySize) { raw_string_ostream OS(Header); - debugWrite(OS.tell(), "section type [" + Twine(getSectionName()) + "]"); - writeUleb128(OS, Type, nullptr); + debugWrite(OS.tell(), "section type [" + getSectionName() + "]"); + encodeULEB128(Type, OS); writeUleb128(OS, BodySize, "section size"); OS.flush(); log("createHeader: " + toString(*this) + " body=" + Twine(BodySize) + " total=" + Twine(getSize())); } -CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs) - : OutputSection(WASM_SEC_CODE), InputObjects(Objs) { +CodeSection::CodeSection(ArrayRef<InputFunction *> Functions) + : OutputSection(WASM_SEC_CODE), Functions(Functions) { + assert(Functions.size() > 0); + raw_string_ostream OS(CodeSectionHeader); - writeUleb128(OS, NumFunctions, "function count"); + writeUleb128(OS, Functions.size(), "function count"); OS.flush(); BodySize = CodeSectionHeader.size(); - for (ObjFile *File : InputObjects) { - if (!File->CodeSection) - continue; - - File->CodeOffset = BodySize; - ArrayRef<uint8_t> Content = File->CodeSection->Content; - unsigned HeaderSize = 0; - decodeULEB128(Content.data(), &HeaderSize); - - calcRelocations(*File, File->CodeSection->Relocations, - File->CodeRelocations, BodySize - HeaderSize); - - size_t PayloadSize = Content.size() - HeaderSize; - BodySize += PayloadSize; + for (InputFunction *Func : Functions) { + Func->OutputOffset = BodySize; + Func->calculateSize(); + BodySize += Func->getSize(); } createHeader(BodySize); @@ -224,49 +97,32 @@ CodeSection::CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs) void CodeSection::writeTo(uint8_t *Buf) { log("writing " + toString(*this)); log(" size=" + Twine(getSize())); + log(" headersize=" + Twine(Header.size())); + log(" codeheadersize=" + Twine(CodeSectionHeader.size())); Buf += Offset; // Write section header memcpy(Buf, Header.data(), Header.size()); Buf += Header.size(); - uint8_t *ContentsStart = Buf; - // Write code section headers memcpy(Buf, CodeSectionHeader.data(), CodeSectionHeader.size()); - Buf += CodeSectionHeader.size(); // Write code section bodies - parallelForEach(InputObjects, [ContentsStart](ObjFile *File) { - if (!File->CodeSection) - return; - - ArrayRef<uint8_t> Content(File->CodeSection->Content); - - // Payload doesn't include the initial header (function count) - unsigned HeaderSize = 0; - decodeULEB128(Content.data(), &HeaderSize); - - size_t PayloadSize = Content.size() - HeaderSize; - memcpy(ContentsStart + File->CodeOffset, Content.data() + HeaderSize, - PayloadSize); - - log("applying relocations for: " + File->getName()); - applyRelocations(ContentsStart, File->CodeRelocations); - }); + parallelForEach(Functions, + [&](const InputChunk *Chunk) { Chunk->writeTo(Buf); }); } uint32_t CodeSection::numRelocations() const { uint32_t Count = 0; - for (ObjFile *File : InputObjects) - Count += File->CodeRelocations.size(); + for (const InputChunk *Func : Functions) + Count += Func->NumRelocations(); return Count; } void CodeSection::writeRelocations(raw_ostream &OS) const { - for (ObjFile *File : InputObjects) - for (const OutputRelocation &Reloc : File->CodeRelocations) - writeReloc(OS, Reloc); + for (const InputChunk *C : Functions) + C->writeRelocations(OS); } DataSection::DataSection(ArrayRef<OutputSegment *> Segments) @@ -285,18 +141,14 @@ DataSection::DataSection(ArrayRef<OutputSegment *> Segments) writeUleb128(OS, WASM_OPCODE_END, "opcode:end"); writeUleb128(OS, Segment->Size, "segment size"); OS.flush(); - Segment->setSectionOffset(BodySize); - BodySize += Segment->Header.size(); + + Segment->SectionOffset = BodySize; + BodySize += Segment->Header.size() + Segment->Size; log("Data segment: size=" + Twine(Segment->Size)); - for (InputSegment *InputSeg : Segment->InputSegments) { - uint32_t InputOffset = InputSeg->getInputSectionOffset(); - uint32_t OutputOffset = Segment->getSectionOffset() + - Segment->Header.size() + - InputSeg->getOutputSegmentOffset(); - calcRelocations(*InputSeg->File, InputSeg->Relocations, - InputSeg->OutRelocations, OutputOffset - InputOffset); - } - BodySize += Segment->Size; + + for (InputSegment *InputSeg : Segment->InputSegments) + InputSeg->OutputOffset = Segment->SectionOffset + Segment->Header.size() + + InputSeg->OutputSegmentOffset; } createHeader(BodySize); @@ -311,38 +163,77 @@ void DataSection::writeTo(uint8_t *Buf) { memcpy(Buf, Header.data(), Header.size()); Buf += Header.size(); - uint8_t *ContentsStart = Buf; - // Write data section headers memcpy(Buf, DataSectionHeader.data(), DataSectionHeader.size()); - parallelForEach(Segments, [ContentsStart](const OutputSegment *Segment) { + parallelForEach(Segments, [&](const OutputSegment *Segment) { // Write data segment header - uint8_t *SegStart = ContentsStart + Segment->getSectionOffset(); + uint8_t *SegStart = Buf + Segment->SectionOffset; memcpy(SegStart, Segment->Header.data(), Segment->Header.size()); // Write segment data payload - for (const InputSegment *Input : Segment->InputSegments) { - ArrayRef<uint8_t> Content(Input->Segment->Data.Content); - memcpy(SegStart + Segment->Header.size() + - Input->getOutputSegmentOffset(), - Content.data(), Content.size()); - applyRelocations(ContentsStart, Input->OutRelocations); - } + for (const InputChunk *Chunk : Segment->InputSegments) + Chunk->writeTo(Buf); }); } uint32_t DataSection::numRelocations() const { uint32_t Count = 0; for (const OutputSegment *Seg : Segments) - for (const InputSegment *InputSeg : Seg->InputSegments) - Count += InputSeg->OutRelocations.size(); + for (const InputChunk *InputSeg : Seg->InputSegments) + Count += InputSeg->NumRelocations(); return Count; } void DataSection::writeRelocations(raw_ostream &OS) const { for (const OutputSegment *Seg : Segments) - for (const InputSegment *InputSeg : Seg->InputSegments) - for (const OutputRelocation &Reloc : InputSeg->OutRelocations) - writeReloc(OS, Reloc); + for (const InputChunk *C : Seg->InputSegments) + C->writeRelocations(OS); +} + +CustomSection::CustomSection(std::string Name, + ArrayRef<InputSection *> InputSections) + : OutputSection(WASM_SEC_CUSTOM, Name), PayloadSize(0), + InputSections(InputSections) { + raw_string_ostream OS(NameData); + encodeULEB128(Name.size(), OS); + OS << Name; + OS.flush(); + + for (InputSection *Section : InputSections) { + Section->OutputOffset = PayloadSize; + PayloadSize += Section->getSize(); + } + + createHeader(PayloadSize + NameData.size()); +} + +void CustomSection::writeTo(uint8_t *Buf) { + log("writing " + toString(*this) + " size=" + Twine(getSize()) + + " chunks=" + Twine(InputSections.size())); + + assert(Offset); + Buf += Offset; + + // Write section header + memcpy(Buf, Header.data(), Header.size()); + Buf += Header.size(); + memcpy(Buf, NameData.data(), NameData.size()); + Buf += NameData.size(); + + // Write custom sections payload + parallelForEach(InputSections, + [&](const InputSection *Section) { Section->writeTo(Buf); }); +} + +uint32_t CustomSection::numRelocations() const { + uint32_t Count = 0; + for (const InputSection *InputSect : InputSections) + Count += InputSect->NumRelocations(); + return Count; +} + +void CustomSection::writeRelocations(raw_ostream &OS) const { + for (const InputSection *S : InputSections) + S->writeRelocations(OS); } diff --git a/wasm/OutputSections.h b/wasm/OutputSections.h index fc73f36ad286..189d6507c4b3 100644 --- a/wasm/OutputSections.h +++ b/wasm/OutputSections.h @@ -10,7 +10,7 @@ #ifndef LLD_WASM_OUTPUT_SECTIONS_H #define LLD_WASM_OUTPUT_SECTIONS_H -#include "InputSegment.h" +#include "InputChunks.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "llvm/ADT/DenseMap.h" @@ -28,7 +28,6 @@ std::string toString(const wasm::OutputSection &Section); namespace wasm { class OutputSegment; -class ObjFile; class OutputSection { public: @@ -36,7 +35,7 @@ public: : Type(Type), Name(Name) {} virtual ~OutputSection() = default; - std::string getSectionName() const; + StringRef getSectionName() const; void setOffset(size_t NewOffset) { log("setOffset: " + toString(*this) + ": " + Twine(NewOffset)); Offset = NewOffset; @@ -61,7 +60,7 @@ public: SyntheticSection(uint32_t Type, std::string Name = "") : OutputSection(Type, Name), BodyOutputStream(Body) { if (!Name.empty()) - writeStr(BodyOutputStream, Name); + writeStr(BodyOutputStream, Name, "section name"); } void writeTo(uint8_t *Buf) override { @@ -86,32 +85,16 @@ protected: raw_string_ostream BodyOutputStream; }; -// Some synthetic sections (e.g. "name" and "linking") have subsections. -// Just like the synthetic sections themselves these need to be created before -// they can be written out (since they are preceded by their length). This -// class is used to create subsections and then write them into the stream -// of the parent section. -class SubSection : public SyntheticSection { -public: - explicit SubSection(uint32_t Type) : SyntheticSection(Type) {} - - std::string getSectionName() const; - void writeToStream(raw_ostream &OS) { - writeBytes(OS, Header.data(), Header.size()); - writeBytes(OS, Body.data(), Body.size()); - } -}; - class CodeSection : public OutputSection { public: - explicit CodeSection(uint32_t NumFunctions, ArrayRef<ObjFile *> Objs); + explicit CodeSection(ArrayRef<InputFunction *> Functions); size_t getSize() const override { return Header.size() + BodySize; } void writeTo(uint8_t *Buf) override; uint32_t numRelocations() const override; void writeRelocations(raw_ostream &OS) const override; protected: - ArrayRef<ObjFile *> InputObjects; + ArrayRef<InputFunction *> Functions; std::string CodeSectionHeader; size_t BodySize = 0; }; @@ -130,6 +113,29 @@ protected: size_t BodySize = 0; }; +// Represents a custom section in the output file. Wasm custom sections are +// used for storing user-defined metadata. Unlike the core sections types +// they are identified by their string name. +// The linker combines custom sections that have the same name by simply +// concatenating them. +// Note that some custom sections such as "name" and "linking" are handled +// separately and are instead synthesized by the linker. +class CustomSection : public OutputSection { +public: + CustomSection(std::string Name, ArrayRef<InputSection *> InputSections); + size_t getSize() const override { + return Header.size() + NameData.size() + PayloadSize; + } + void writeTo(uint8_t *Buf) override; + uint32_t numRelocations() const override; + void writeRelocations(raw_ostream &OS) const override; + +protected: + size_t PayloadSize; + ArrayRef<InputSection *> InputSections; + std::string NameData; +}; + } // namespace wasm } // namespace lld diff --git a/wasm/OutputSegment.h b/wasm/OutputSegment.h index a22c80234420..d5c89cd19f4c 100644 --- a/wasm/OutputSegment.h +++ b/wasm/OutputSegment.h @@ -10,7 +10,7 @@ #ifndef LLD_WASM_OUTPUT_SEGMENT_H #define LLD_WASM_OUTPUT_SEGMENT_H -#include "InputSegment.h" +#include "InputChunks.h" #include "lld/Common/ErrorHandler.h" #include "llvm/Object/Wasm.h" @@ -21,21 +21,20 @@ class InputSegment; class OutputSegment { public: - OutputSegment(StringRef N) : Name(N) {} - - void addInputSegment(InputSegment *Segment) { - Alignment = std::max(Alignment, Segment->getAlignment()); - InputSegments.push_back(Segment); - Size = llvm::alignTo(Size, Segment->getAlignment()); - Segment->setOutputSegment(this, Size); - Size += Segment->getSize(); + OutputSegment(StringRef N, uint32_t Index) : Name(N), Index(Index) {} + + void addInputSegment(InputSegment *InSeg) { + Alignment = std::max(Alignment, InSeg->getAlignment()); + InputSegments.push_back(InSeg); + Size = llvm::alignTo(Size, InSeg->getAlignment()); + InSeg->OutputSeg = this; + InSeg->OutputSegmentOffset = Size; + Size += InSeg->getSize(); } - uint32_t getSectionOffset() const { return SectionOffset; } - - void setSectionOffset(uint32_t Offset) { SectionOffset = Offset; } - StringRef Name; + const uint32_t Index; + uint32_t SectionOffset = 0; uint32_t Alignment = 0; uint32_t StartVA = 0; std::vector<InputSegment *> InputSegments; @@ -45,9 +44,6 @@ public: // Segment header std::string Header; - -private: - uint32_t SectionOffset = 0; }; } // namespace wasm diff --git a/wasm/SymbolTable.cpp b/wasm/SymbolTable.cpp index 751008da0536..e1ba23769738 100644 --- a/wasm/SymbolTable.cpp +++ b/wasm/SymbolTable.cpp @@ -8,17 +8,18 @@ //===----------------------------------------------------------------------===// #include "SymbolTable.h" - #include "Config.h" +#include "InputChunks.h" +#include "InputGlobal.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" - -#include <unordered_set> +#include "llvm/ADT/SetVector.h" #define DEBUG_TYPE "lld" using namespace llvm; +using namespace llvm::wasm; using namespace lld; using namespace lld::wasm; @@ -28,17 +29,46 @@ void SymbolTable::addFile(InputFile *File) { log("Processing: " + toString(File)); File->parse(); - if (auto *F = dyn_cast<ObjFile>(File)) + // LLVM bitcode file + if (auto *F = dyn_cast<BitcodeFile>(File)) + BitcodeFiles.push_back(F); + else if (auto *F = dyn_cast<ObjFile>(File)) ObjectFiles.push_back(F); } +// This function is where all the optimizations of link-time +// optimization happens. When LTO is in use, some input files are +// not in native object file format but in the LLVM bitcode format. +// This function compiles bitcode files into a few big native files +// using LLVM functions and replaces bitcode symbols with the results. +// Because all bitcode files that the program consists of are passed +// to the compiler at once, it can do whole-program optimization. +void SymbolTable::addCombinedLTOObject() { + if (BitcodeFiles.empty()) + return; + + // Compile bitcode files and replace bitcode symbols. + LTO.reset(new BitcodeCompiler); + for (BitcodeFile *F : BitcodeFiles) + LTO->add(*F); + + for (StringRef Filename : LTO->compile()) { + auto *Obj = make<ObjFile>(MemoryBufferRef(Filename, "lto.tmp")); + Obj->parse(); + ObjectFiles.push_back(Obj); + } +} + void SymbolTable::reportRemainingUndefines() { - std::unordered_set<Symbol *> Undefs; + SetVector<Symbol *> Undefs; for (Symbol *Sym : SymVector) { - if (Sym->isUndefined() && !Sym->isWeak() && - Config->AllowUndefinedSymbols.count(Sym->getName()) == 0) { - Undefs.insert(Sym); - } + if (!Sym->isUndefined() || Sym->isWeak()) + continue; + if (Config->AllowUndefinedSymbols.count(Sym->getName()) != 0) + continue; + if (!Sym->IsUsedInRegularObj) + continue; + Undefs.insert(Sym); } if (Undefs.empty()) @@ -55,183 +85,281 @@ void SymbolTable::reportRemainingUndefines() { } Symbol *SymbolTable::find(StringRef Name) { - auto It = SymMap.find(CachedHashStringRef(Name)); - if (It == SymMap.end()) - return nullptr; - return It->second; + return SymMap.lookup(CachedHashStringRef(Name)); } std::pair<Symbol *, bool> SymbolTable::insert(StringRef Name) { Symbol *&Sym = SymMap[CachedHashStringRef(Name)]; if (Sym) return {Sym, false}; - Sym = make<Symbol>(Name, false); + Sym = reinterpret_cast<Symbol *>(make<SymbolUnion>()); + Sym->IsUsedInRegularObj = false; SymVector.emplace_back(Sym); return {Sym, true}; } -void SymbolTable::reportDuplicate(Symbol *Existing, InputFile *NewFile) { - error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + - toString(Existing->getFile()) + "\n>>> defined in " + - toString(NewFile)); +static void reportTypeError(const Symbol *Existing, const InputFile *File, + llvm::wasm::WasmSymbolType Type) { + error("symbol type mismatch: " + toString(*Existing) + "\n>>> defined as " + + toString(Existing->getWasmType()) + " in " + + toString(Existing->getFile()) + "\n>>> defined as " + toString(Type) + + " in " + toString(File)); } -// Get the signature for a given function symbol, either by looking -// it up in function sections (for defined functions), of the imports section -// (for imported functions). -static const WasmSignature *getFunctionSig(const ObjFile &Obj, - const WasmSymbol &Sym) { - DEBUG(dbgs() << "getFunctionSig: " << Sym.Name << "\n"); - const WasmObjectFile *WasmObj = Obj.getWasmObj(); - return &WasmObj->types()[Sym.FunctionType]; +static void checkFunctionType(Symbol *Existing, const InputFile *File, + const WasmSignature *NewSig) { + auto ExistingFunction = dyn_cast<FunctionSymbol>(Existing); + if (!ExistingFunction) { + reportTypeError(Existing, File, WASM_SYMBOL_TYPE_FUNCTION); + return; + } + + if (!NewSig) + return; + + const WasmSignature *OldSig = ExistingFunction->FunctionType; + if (!OldSig) { + ExistingFunction->FunctionType = NewSig; + return; + } + + if (*NewSig != *OldSig) + warn("function signature mismatch: " + Existing->getName() + + "\n>>> defined as " + toString(*OldSig) + " in " + + toString(Existing->getFile()) + "\n>>> defined as " + + toString(*NewSig) + " in " + toString(File)); } // Check the type of new symbol matches that of the symbol is replacing. // For functions this can also involve verifying that the signatures match. -static void checkSymbolTypes(const Symbol &Existing, const InputFile &F, - const WasmSymbol &New, - const WasmSignature *NewSig) { - if (Existing.isLazy()) +static void checkGlobalType(const Symbol *Existing, const InputFile *File, + const WasmGlobalType *NewType) { + if (!isa<GlobalSymbol>(Existing)) { + reportTypeError(Existing, File, WASM_SYMBOL_TYPE_GLOBAL); return; + } - bool NewIsFunction = New.Type == WasmSymbol::SymbolType::FUNCTION_EXPORT || - New.Type == WasmSymbol::SymbolType::FUNCTION_IMPORT; - - // First check the symbol types match (i.e. either both are function - // symbols or both are data symbols). - if (Existing.isFunction() != NewIsFunction) { - error("symbol type mismatch: " + New.Name + "\n>>> defined as " + - (Existing.isFunction() ? "Function" : "Global") + " in " + - toString(Existing.getFile()) + "\n>>> defined as " + - (NewIsFunction ? "Function" : "Global") + " in " + F.getName()); - return; + const WasmGlobalType *OldType = cast<GlobalSymbol>(Existing)->getGlobalType(); + if (*NewType != *OldType) { + error("Global type mismatch: " + Existing->getName() + "\n>>> defined as " + + toString(*OldType) + " in " + toString(Existing->getFile()) + + "\n>>> defined as " + toString(*NewType) + " in " + toString(File)); } +} - // For function symbols, optionally check the function signature matches too. - if (!NewIsFunction || !Config->CheckSignatures) - return; - // Skip the signature check if the existing function has no signature (e.g. - // if it is an undefined symbol generated by --undefined command line flag). - if (!Existing.hasFunctionType()) - return; +static void checkDataType(const Symbol *Existing, const InputFile *File) { + if (!isa<DataSymbol>(Existing)) + reportTypeError(Existing, File, WASM_SYMBOL_TYPE_DATA); +} - DEBUG(dbgs() << "checkSymbolTypes: " << New.Name << "\n"); - assert(NewSig); +DefinedFunction *SymbolTable::addSyntheticFunction(StringRef Name, + uint32_t Flags, + InputFunction *Function) { + LLVM_DEBUG(dbgs() << "addSyntheticFunction: " << Name << "\n"); + assert(!find(Name)); + SyntheticFunctions.emplace_back(Function); + return replaceSymbol<DefinedFunction>(insert(Name).first, Name, Flags, + nullptr, Function); +} - const WasmSignature &OldSig = Existing.getFunctionType(); - if (*NewSig == OldSig) - return; +DefinedData *SymbolTable::addSyntheticDataSymbol(StringRef Name, + uint32_t Flags) { + LLVM_DEBUG(dbgs() << "addSyntheticDataSymbol: " << Name << "\n"); + assert(!find(Name)); + return replaceSymbol<DefinedData>(insert(Name).first, Name, Flags); +} - error("function signature mismatch: " + New.Name + "\n>>> defined as " + - toString(OldSig) + " in " + toString(Existing.getFile()) + - "\n>>> defined as " + toString(*NewSig) + " in " + F.getName()); +DefinedGlobal *SymbolTable::addSyntheticGlobal(StringRef Name, uint32_t Flags, + InputGlobal *Global) { + LLVM_DEBUG(dbgs() << "addSyntheticGlobal: " << Name << " -> " << Global + << "\n"); + assert(!find(Name)); + SyntheticGlobals.emplace_back(Global); + return replaceSymbol<DefinedGlobal>(insert(Name).first, Name, Flags, nullptr, + Global); } -Symbol *SymbolTable::addDefinedGlobal(StringRef Name) { - DEBUG(dbgs() << "addDefinedGlobal: " << Name << "\n"); +static bool shouldReplace(const Symbol *Existing, InputFile *NewFile, + uint32_t NewFlags) { + // If existing symbol is undefined, replace it. + if (!Existing->isDefined()) { + LLVM_DEBUG(dbgs() << "resolving existing undefined symbol: " + << Existing->getName() << "\n"); + return true; + } + + // Now we have two defined symbols. If the new one is weak, we can ignore it. + if ((NewFlags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { + LLVM_DEBUG(dbgs() << "existing symbol takes precedence\n"); + return false; + } + + // If the existing symbol is weak, we should replace it. + if (Existing->isWeak()) { + LLVM_DEBUG(dbgs() << "replacing existing weak symbol\n"); + return true; + } + + // Neither symbol is week. They conflict. + error("duplicate symbol: " + toString(*Existing) + "\n>>> defined in " + + toString(Existing->getFile()) + "\n>>> defined in " + + toString(NewFile)); + return true; +} + +Symbol *SymbolTable::addDefinedFunction(StringRef Name, uint32_t Flags, + InputFile *File, + InputFunction *Function) { + LLVM_DEBUG(dbgs() << "addDefinedFunction: " << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted) - S->update(Symbol::DefinedGlobalKind); - else if (!S->isGlobal()) - error("symbol type mismatch: " + Name); + + if (!File || File->kind() == InputFile::ObjectKind) + S->IsUsedInRegularObj = true; + + if (WasInserted || S->isLazy()) { + replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); + return S; + } + + if (Function) + checkFunctionType(S, File, &Function->Signature); + + if (shouldReplace(S, File, Flags)) + replaceSymbol<DefinedFunction>(S, Name, Flags, File, Function); return S; } -Symbol *SymbolTable::addDefined(InputFile *F, const WasmSymbol *Sym, - const InputSegment *Segment) { - DEBUG(dbgs() << "addDefined: " << Sym->Name << "\n"); +Symbol *SymbolTable::addDefinedData(StringRef Name, uint32_t Flags, + InputFile *File, InputSegment *Segment, + uint32_t Address, uint32_t Size) { + LLVM_DEBUG(dbgs() << "addDefinedData:" << Name << " addr:" << Address + << "\n"); Symbol *S; bool WasInserted; - Symbol::Kind Kind = Symbol::DefinedFunctionKind; - const WasmSignature *NewSig = nullptr; - if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_EXPORT) - Kind = Symbol::DefinedGlobalKind; - else - NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym); + std::tie(S, WasInserted) = insert(Name); - std::tie(S, WasInserted) = insert(Sym->Name); - if (WasInserted) { - S->update(Kind, F, Sym, Segment, NewSig); - } else if (S->isLazy()) { - // The existing symbol is lazy. Replace it without checking types since - // lazy symbols don't have any type information. - DEBUG(dbgs() << "replacing existing lazy symbol: " << Sym->Name << "\n"); - S->update(Kind, F, Sym, Segment, NewSig); - } else if (!S->isDefined()) { - // The existing symbol table entry is undefined. The new symbol replaces - // it, after checking the type matches - DEBUG(dbgs() << "resolving existing undefined symbol: " << Sym->Name - << "\n"); - checkSymbolTypes(*S, *F, *Sym, NewSig); - S->update(Kind, F, Sym, Segment, NewSig); - } else if (Sym->isWeak()) { - // the new symbol is weak we can ignore it - DEBUG(dbgs() << "existing symbol takes precedence\n"); - } else if (S->isWeak()) { - // the new symbol is not weak and the existing symbol is, so we replace - // it - DEBUG(dbgs() << "replacing existing weak symbol\n"); - checkSymbolTypes(*S, *F, *Sym, NewSig); - S->update(Kind, F, Sym, Segment, NewSig); - } else { - // neither symbol is week. They conflict. - reportDuplicate(S, F); + if (!File || File->kind() == InputFile::ObjectKind) + S->IsUsedInRegularObj = true; + + if (WasInserted || S->isLazy()) { + replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); + return S; } + + checkDataType(S, File); + + if (shouldReplace(S, File, Flags)) + replaceSymbol<DefinedData>(S, Name, Flags, File, Segment, Address, Size); return S; } -Symbol *SymbolTable::addUndefinedFunction(StringRef Name, - const WasmSignature *Type) { +Symbol *SymbolTable::addDefinedGlobal(StringRef Name, uint32_t Flags, + InputFile *File, InputGlobal *Global) { + LLVM_DEBUG(dbgs() << "addDefinedGlobal:" << Name << "\n"); Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); - if (WasInserted) { - S->update(Symbol::UndefinedFunctionKind, nullptr, nullptr, nullptr, Type); - } else if (!S->isFunction()) { - error("symbol type mismatch: " + Name); + + if (!File || File->kind() == InputFile::ObjectKind) + S->IsUsedInRegularObj = true; + + if (WasInserted || S->isLazy()) { + replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); + return S; } + + checkGlobalType(S, File, &Global->getType()); + + if (shouldReplace(S, File, Flags)) + replaceSymbol<DefinedGlobal>(S, Name, Flags, File, Global); return S; } -Symbol *SymbolTable::addUndefined(InputFile *F, const WasmSymbol *Sym) { - DEBUG(dbgs() << "addUndefined: " << Sym->Name << "\n"); +Symbol *SymbolTable::addUndefinedFunction(StringRef Name, uint32_t Flags, + InputFile *File, + const WasmSignature *Sig) { + LLVM_DEBUG(dbgs() << "addUndefinedFunction: " << Name << "\n"); + Symbol *S; bool WasInserted; - Symbol::Kind Kind = Symbol::UndefinedFunctionKind; - const WasmSignature *NewSig = nullptr; - if (Sym->Type == WasmSymbol::SymbolType::GLOBAL_IMPORT) - Kind = Symbol::UndefinedGlobalKind; + std::tie(S, WasInserted) = insert(Name); + + if (!File || File->kind() == InputFile::ObjectKind) + S->IsUsedInRegularObj = true; + + if (WasInserted) + replaceSymbol<UndefinedFunction>(S, Name, Flags, File, Sig); + else if (auto *Lazy = dyn_cast<LazySymbol>(S)) + Lazy->fetch(); else - NewSig = getFunctionSig(*cast<ObjFile>(F), *Sym); - std::tie(S, WasInserted) = insert(Sym->Name); - if (WasInserted) { - S->update(Kind, F, Sym, nullptr, NewSig); - } else if (S->isLazy()) { - DEBUG(dbgs() << "resolved by existing lazy\n"); - auto *AF = cast<ArchiveFile>(S->getFile()); - AF->addMember(&S->getArchiveSymbol()); - } else if (S->isDefined()) { - DEBUG(dbgs() << "resolved by existing\n"); - checkSymbolTypes(*S, *F, *Sym, NewSig); - } + checkFunctionType(S, File, Sig); + + return S; +} + +Symbol *SymbolTable::addUndefinedData(StringRef Name, uint32_t Flags, + InputFile *File) { + LLVM_DEBUG(dbgs() << "addUndefinedData: " << Name << "\n"); + + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + + if (!File || File->kind() == InputFile::ObjectKind) + S->IsUsedInRegularObj = true; + + if (WasInserted) + replaceSymbol<UndefinedData>(S, Name, Flags, File); + else if (auto *Lazy = dyn_cast<LazySymbol>(S)) + Lazy->fetch(); + else if (S->isDefined()) + checkDataType(S, File); return S; } -void SymbolTable::addLazy(ArchiveFile *F, const Archive::Symbol *Sym) { - DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); +Symbol *SymbolTable::addUndefinedGlobal(StringRef Name, uint32_t Flags, + InputFile *File, + const WasmGlobalType *Type) { + LLVM_DEBUG(dbgs() << "addUndefinedGlobal: " << Name << "\n"); + + Symbol *S; + bool WasInserted; + std::tie(S, WasInserted) = insert(Name); + + if (!File || File->kind() == InputFile::ObjectKind) + S->IsUsedInRegularObj = true; + + if (WasInserted) + replaceSymbol<UndefinedGlobal>(S, Name, Flags, File, Type); + else if (auto *Lazy = dyn_cast<LazySymbol>(S)) + Lazy->fetch(); + else if (S->isDefined()) + checkGlobalType(S, File, Type); + return S; +} + +void SymbolTable::addLazy(ArchiveFile *File, const Archive::Symbol *Sym) { + LLVM_DEBUG(dbgs() << "addLazy: " << Sym->getName() << "\n"); StringRef Name = Sym->getName(); + Symbol *S; bool WasInserted; std::tie(S, WasInserted) = insert(Name); + if (WasInserted) { - S->update(Symbol::LazyKind, F); - S->setArchiveSymbol(*Sym); - } else if (S->isUndefined()) { - // There is an existing undefined symbol. The can load from the - // archive. - DEBUG(dbgs() << "replacing existing undefined\n"); - F->addMember(Sym); + replaceSymbol<LazySymbol>(S, Name, File, *Sym); + return; + } + + // If there is an existing undefined symbol, load a new one from the archive. + if (S->isUndefined()) { + LLVM_DEBUG(dbgs() << "replacing existing undefined\n"); + File->addMember(Sym); } } + +bool SymbolTable::addComdat(StringRef Name) { + return Comdats.insert(CachedHashStringRef(Name)).second; +} diff --git a/wasm/SymbolTable.h b/wasm/SymbolTable.h index fbb74ed14796..26242e6cddd6 100644 --- a/wasm/SymbolTable.h +++ b/wasm/SymbolTable.h @@ -11,13 +11,13 @@ #define LLD_WASM_SYMBOL_TABLE_H #include "InputFiles.h" +#include "LTO.h" #include "Symbols.h" - #include "llvm/ADT/CachedHashString.h" -#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/Support/raw_ostream.h" -using llvm::object::WasmSymbol; +using llvm::wasm::WasmGlobalType; using llvm::wasm::WasmSignature; namespace lld { @@ -40,27 +40,52 @@ class InputSegment; class SymbolTable { public: void addFile(InputFile *File); + void addCombinedLTOObject(); std::vector<ObjFile *> ObjectFiles; + std::vector<BitcodeFile *> BitcodeFiles; + std::vector<InputFunction *> SyntheticFunctions; + std::vector<InputGlobal *> SyntheticGlobals; - void reportDuplicate(Symbol *Existing, InputFile *NewFile); void reportRemainingUndefines(); ArrayRef<Symbol *> getSymbols() const { return SymVector; } Symbol *find(StringRef Name); - Symbol *addDefined(InputFile *F, const WasmSymbol *Sym, - const InputSegment *Segment = nullptr); - Symbol *addUndefined(InputFile *F, const WasmSymbol *Sym); - Symbol *addUndefinedFunction(StringRef Name, const WasmSignature *Type); - Symbol *addDefinedGlobal(StringRef Name); + Symbol *addDefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, + InputFunction *Function); + Symbol *addDefinedData(StringRef Name, uint32_t Flags, InputFile *File, + InputSegment *Segment, uint32_t Address, + uint32_t Size); + Symbol *addDefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, + InputGlobal *G); + + Symbol *addUndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File, + const WasmSignature *Signature); + Symbol *addUndefinedData(StringRef Name, uint32_t Flags, InputFile *File); + Symbol *addUndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, + const WasmGlobalType *Type); + void addLazy(ArchiveFile *F, const Archive::Symbol *Sym); + bool addComdat(StringRef Name); + + DefinedData *addSyntheticDataSymbol(StringRef Name, uint32_t Flags); + DefinedGlobal *addSyntheticGlobal(StringRef Name, uint32_t Flags, + InputGlobal *Global); + DefinedFunction *addSyntheticFunction(StringRef Name, uint32_t Flags, + InputFunction *Function); + private: std::pair<Symbol *, bool> insert(StringRef Name); llvm::DenseMap<llvm::CachedHashStringRef, Symbol *> SymMap; std::vector<Symbol *> SymVector; + + llvm::DenseSet<llvm::CachedHashStringRef> Comdats; + + // For LTO. + std::unique_ptr<BitcodeCompiler> LTO; }; extern SymbolTable *Symtab; diff --git a/wasm/Symbols.cpp b/wasm/Symbols.cpp index 6bf5459c2663..a11081cbcf77 100644 --- a/wasm/Symbols.cpp +++ b/wasm/Symbols.cpp @@ -8,92 +8,224 @@ //===----------------------------------------------------------------------===// #include "Symbols.h" - #include "Config.h" +#include "InputChunks.h" #include "InputFiles.h" -#include "InputSegment.h" +#include "InputGlobal.h" +#include "OutputSegment.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Strings.h" #define DEBUG_TYPE "lld" using namespace llvm; +using namespace llvm::wasm; using namespace lld; using namespace lld::wasm; -uint32_t Symbol::getGlobalIndex() const { - assert(!Sym->isFunction()); - return Sym->ElementIndex; +DefinedFunction *WasmSym::CallCtors; +DefinedData *WasmSym::DsoHandle; +DefinedData *WasmSym::DataEnd; +DefinedData *WasmSym::HeapBase; +DefinedGlobal *WasmSym::StackPointer; + +WasmSymbolType Symbol::getWasmType() const { + if (isa<FunctionSymbol>(this)) + return WASM_SYMBOL_TYPE_FUNCTION; + if (isa<DataSymbol>(this)) + return WASM_SYMBOL_TYPE_DATA; + if (isa<GlobalSymbol>(this)) + return WASM_SYMBOL_TYPE_GLOBAL; + if (isa<SectionSymbol>(this)) + return WASM_SYMBOL_TYPE_SECTION; + llvm_unreachable("invalid symbol kind"); +} + +InputChunk *Symbol::getChunk() const { + if (auto *F = dyn_cast<DefinedFunction>(this)) + return F->Function; + if (auto *D = dyn_cast<DefinedData>(this)) + return D->Segment; + return nullptr; +} + +bool Symbol::isLive() const { + if (auto *G = dyn_cast<DefinedGlobal>(this)) + return G->Global->Live; + if (InputChunk *C = getChunk()) + return C->Live; + return Referenced; } -uint32_t Symbol::getFunctionIndex() const { - assert(Sym->isFunction()); - return Sym->ElementIndex; +void Symbol::markLive() { + if (auto *G = dyn_cast<DefinedGlobal>(this)) + G->Global->Live = true; + if (InputChunk *C = getChunk()) + C->Live = true; + Referenced = true; } -const WasmSignature &Symbol::getFunctionType() const { - assert(FunctionType != nullptr); - return *FunctionType; +uint32_t Symbol::getOutputSymbolIndex() const { + assert(OutputSymbolIndex != INVALID_INDEX); + return OutputSymbolIndex; } -uint32_t Symbol::getVirtualAddress() const { - assert(isGlobal()); - DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); - if (isUndefined()) - return UINT32_MAX; - if (VirtualAddress.hasValue()) - return VirtualAddress.getValue(); +void Symbol::setOutputSymbolIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "setOutputSymbolIndex " << Name << " -> " << Index + << "\n"); + assert(OutputSymbolIndex == INVALID_INDEX); + OutputSymbolIndex = Index; +} + +bool Symbol::isWeak() const { + return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK; +} - assert(Sym != nullptr); - ObjFile *Obj = cast<ObjFile>(File); - const WasmGlobal &Global = - Obj->getWasmObj()->globals()[getGlobalIndex() - Obj->NumGlobalImports()]; - assert(Global.Type == llvm::wasm::WASM_TYPE_I32); - assert(Segment); - return Segment->translateVA(Global.InitExpr.Value.Int32); +bool Symbol::isLocal() const { + return (Flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_LOCAL; } -uint32_t Symbol::getOutputIndex() const { - if (isUndefined() && isWeak()) - return 0; - return OutputIndex.getValue(); +bool Symbol::isHidden() const { + return (Flags & WASM_SYMBOL_VISIBILITY_MASK) == WASM_SYMBOL_VISIBILITY_HIDDEN; } -void Symbol::setVirtualAddress(uint32_t Value) { - DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); - assert(!VirtualAddress.hasValue()); - VirtualAddress = Value; +void Symbol::setHidden(bool IsHidden) { + LLVM_DEBUG(dbgs() << "setHidden: " << Name << " -> " << IsHidden << "\n"); + Flags &= ~WASM_SYMBOL_VISIBILITY_MASK; + if (IsHidden) + Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; + else + Flags |= WASM_SYMBOL_VISIBILITY_DEFAULT; } -void Symbol::setOutputIndex(uint32_t Index) { - DEBUG(dbgs() << "setOutputIndex " << Name << " -> " << Index << "\n"); - assert(!OutputIndex.hasValue()); - OutputIndex = Index; +bool Symbol::isExported() const { + if (!isDefined() || isLocal()) + return false; + + if (ForceExport || Config->ExportAll) + return true; + + return !isHidden(); } -void Symbol::setTableIndex(uint32_t Index) { - DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n"); - assert(!TableIndex.hasValue()); +uint32_t FunctionSymbol::getFunctionIndex() const { + if (auto *F = dyn_cast<DefinedFunction>(this)) + return F->Function->getFunctionIndex(); + assert(FunctionIndex != INVALID_INDEX); + return FunctionIndex; +} + +void FunctionSymbol::setFunctionIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "setFunctionIndex " << Name << " -> " << Index << "\n"); + assert(FunctionIndex == INVALID_INDEX); + FunctionIndex = Index; +} + +bool FunctionSymbol::hasFunctionIndex() const { + if (auto *F = dyn_cast<DefinedFunction>(this)) + return F->Function->hasFunctionIndex(); + return FunctionIndex != INVALID_INDEX; +} + +uint32_t FunctionSymbol::getTableIndex() const { + if (auto *F = dyn_cast<DefinedFunction>(this)) + return F->Function->getTableIndex(); + assert(TableIndex != INVALID_INDEX); + return TableIndex; +} + +bool FunctionSymbol::hasTableIndex() const { + if (auto *F = dyn_cast<DefinedFunction>(this)) + return F->Function->hasTableIndex(); + return TableIndex != INVALID_INDEX; +} + +void FunctionSymbol::setTableIndex(uint32_t Index) { + // For imports, we set the table index here on the Symbol; for defined + // functions we set the index on the InputFunction so that we don't export + // the same thing twice (keeps the table size down). + if (auto *F = dyn_cast<DefinedFunction>(this)) { + F->Function->setTableIndex(Index); + return; + } + LLVM_DEBUG(dbgs() << "setTableIndex " << Name << " -> " << Index << "\n"); + assert(TableIndex == INVALID_INDEX); TableIndex = Index; } -void Symbol::update(Kind K, InputFile *F, const WasmSymbol *WasmSym, - const InputSegment *Seg, const WasmSignature *Sig) { - SymbolKind = K; - File = F; - Sym = WasmSym; - Segment = Seg; - FunctionType = Sig; +DefinedFunction::DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F, + InputFunction *Function) + : FunctionSymbol(Name, DefinedFunctionKind, Flags, F, + Function ? &Function->Signature : nullptr), + Function(Function) {} + +uint32_t DefinedData::getVirtualAddress() const { + LLVM_DEBUG(dbgs() << "getVirtualAddress: " << getName() << "\n"); + if (Segment) + return Segment->OutputSeg->StartVA + Segment->OutputSegmentOffset + Offset; + return Offset; +} + +void DefinedData::setVirtualAddress(uint32_t Value) { + LLVM_DEBUG(dbgs() << "setVirtualAddress " << Name << " -> " << Value << "\n"); + assert(!Segment); + Offset = Value; +} + +uint32_t DefinedData::getOutputSegmentOffset() const { + LLVM_DEBUG(dbgs() << "getOutputSegmentOffset: " << getName() << "\n"); + return Segment->OutputSegmentOffset + Offset; +} + +uint32_t DefinedData::getOutputSegmentIndex() const { + LLVM_DEBUG(dbgs() << "getOutputSegmentIndex: " << getName() << "\n"); + return Segment->OutputSeg->Index; +} + +uint32_t GlobalSymbol::getGlobalIndex() const { + if (auto *F = dyn_cast<DefinedGlobal>(this)) + return F->Global->getGlobalIndex(); + assert(GlobalIndex != INVALID_INDEX); + return GlobalIndex; +} + +void GlobalSymbol::setGlobalIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "setGlobalIndex " << Name << " -> " << Index << "\n"); + assert(GlobalIndex == INVALID_INDEX); + GlobalIndex = Index; +} + +bool GlobalSymbol::hasGlobalIndex() const { + if (auto *F = dyn_cast<DefinedGlobal>(this)) + return F->Global->hasGlobalIndex(); + return GlobalIndex != INVALID_INDEX; } -bool Symbol::isWeak() const { return Sym && Sym->isWeak(); } +DefinedGlobal::DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, + InputGlobal *Global) + : GlobalSymbol(Name, DefinedGlobalKind, Flags, File, + Global ? &Global->getType() : nullptr), + Global(Global) {} + +uint32_t SectionSymbol::getOutputSectionIndex() const { + LLVM_DEBUG(dbgs() << "getOutputSectionIndex: " << getName() << "\n"); + assert(OutputSectionIndex != INVALID_INDEX); + return OutputSectionIndex; +} + +void SectionSymbol::setOutputSectionIndex(uint32_t Index) { + LLVM_DEBUG(dbgs() << "setOutputSectionIndex: " << getName() << " -> " << Index + << "\n"); + assert(Index != INVALID_INDEX); + OutputSectionIndex = Index; +} -bool Symbol::isHidden() const { return Sym && Sym->isHidden(); } +void LazySymbol::fetch() { cast<ArchiveFile>(File)->addMember(&ArchiveSymbol); } std::string lld::toString(const wasm::Symbol &Sym) { if (Config->Demangle) if (Optional<std::string> S = demangleItanium(Sym.getName())) - return "`" + *S + "'"; + return *S; return Sym.getName(); } @@ -101,14 +233,20 @@ std::string lld::toString(wasm::Symbol::Kind Kind) { switch (Kind) { case wasm::Symbol::DefinedFunctionKind: return "DefinedFunction"; + case wasm::Symbol::DefinedDataKind: + return "DefinedData"; case wasm::Symbol::DefinedGlobalKind: return "DefinedGlobal"; case wasm::Symbol::UndefinedFunctionKind: return "UndefinedFunction"; + case wasm::Symbol::UndefinedDataKind: + return "UndefinedData"; case wasm::Symbol::UndefinedGlobalKind: return "UndefinedGlobal"; case wasm::Symbol::LazyKind: return "LazyKind"; + case wasm::Symbol::SectionKind: + return "SectionKind"; } - llvm_unreachable("Invalid symbol kind!"); + llvm_unreachable("invalid symbol kind"); } diff --git a/wasm/Symbols.h b/wasm/Symbols.h index 8194bcaca383..815cc97d22d1 100644 --- a/wasm/Symbols.h +++ b/wasm/Symbols.h @@ -10,53 +10,59 @@ #ifndef LLD_WASM_SYMBOLS_H #define LLD_WASM_SYMBOLS_H +#include "Config.h" #include "lld/Common/LLVM.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Wasm.h" using llvm::object::Archive; using llvm::object::WasmSymbol; -using llvm::wasm::WasmExport; -using llvm::wasm::WasmImport; +using llvm::wasm::WasmGlobal; +using llvm::wasm::WasmGlobalType; using llvm::wasm::WasmSignature; +using llvm::wasm::WasmSymbolType; namespace lld { namespace wasm { class InputFile; +class InputChunk; class InputSegment; +class InputFunction; +class InputGlobal; +class InputSection; +#define INVALID_INDEX UINT32_MAX + +// The base class for real symbol classes. class Symbol { public: enum Kind { DefinedFunctionKind, + DefinedDataKind, DefinedGlobalKind, - - LazyKind, + SectionKind, UndefinedFunctionKind, + UndefinedDataKind, UndefinedGlobalKind, - - LastDefinedKind = DefinedGlobalKind, - InvalidKind, + LazyKind, }; - Symbol(StringRef Name, bool IsLocal) - : WrittenToSymtab(0), WrittenToNameSec(0), IsLocal(IsLocal), Name(Name) {} + Kind kind() const { return SymbolKind; } - Kind getKind() const { return SymbolKind; } + bool isDefined() const { + return SymbolKind == DefinedFunctionKind || SymbolKind == DefinedDataKind || + SymbolKind == DefinedGlobalKind || SymbolKind == SectionKind; + } - bool isLazy() const { return SymbolKind == LazyKind; } - bool isDefined() const { return SymbolKind <= LastDefinedKind; } bool isUndefined() const { - return SymbolKind == UndefinedGlobalKind || - SymbolKind == UndefinedFunctionKind; + return SymbolKind == UndefinedFunctionKind || + SymbolKind == UndefinedDataKind || SymbolKind == UndefinedGlobalKind; } - bool isFunction() const { - return SymbolKind == DefinedFunctionKind || - SymbolKind == UndefinedFunctionKind; - } - bool isGlobal() const { return !isFunction(); } - bool isLocal() const { return IsLocal; } + + bool isLazy() const { return SymbolKind == LazyKind; } + + bool isLocal() const; bool isWeak() const; bool isHidden() const; @@ -66,57 +72,278 @@ public: // Returns the file from which this symbol was created. InputFile *getFile() const { return File; } - uint32_t getGlobalIndex() const; - uint32_t getFunctionIndex() const; + InputChunk *getChunk() const; - bool hasFunctionType() const { return FunctionType != nullptr; } - const WasmSignature &getFunctionType() const; - uint32_t getOutputIndex() const; - uint32_t getTableIndex() const { return TableIndex.getValue(); } + // Indicates that the section or import for this symbol will be included in + // the final image. + bool isLive() const; - // Returns the virtual address of a defined global. - // Only works for globals, not functions. - uint32_t getVirtualAddress() const; + // Marks the symbol's InputChunk as Live, so that it will be included in the + // final image. + void markLive(); + + void setHidden(bool IsHidden); - // Set the output index of the symbol (in the function or global index - // space of the output object. - void setOutputIndex(uint32_t Index); + // Get/set the index in the output symbol table. This is only used for + // relocatable output. + uint32_t getOutputSymbolIndex() const; + void setOutputSymbolIndex(uint32_t Index); - // Returns true if a table index has been set for this symbol - bool hasTableIndex() const { return TableIndex.hasValue(); } + WasmSymbolType getWasmType() const; + bool isExported() const; - // Set the table index of the symbol + // True if this symbol was referenced by a regular (non-bitcode) object. + unsigned IsUsedInRegularObj : 1; + unsigned ForceExport : 1; + +protected: + Symbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) + : IsUsedInRegularObj(false), ForceExport(false), Name(Name), + SymbolKind(K), Flags(Flags), File(F), Referenced(!Config->GcSections) {} + + StringRef Name; + Kind SymbolKind; + uint32_t Flags; + InputFile *File; + uint32_t OutputSymbolIndex = INVALID_INDEX; + bool Referenced; +}; + +class FunctionSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { + return S->kind() == DefinedFunctionKind || + S->kind() == UndefinedFunctionKind; + } + + // Get/set the table index void setTableIndex(uint32_t Index); + uint32_t getTableIndex() const; + bool hasTableIndex() const; + + // Get/set the function index + uint32_t getFunctionIndex() const; + void setFunctionIndex(uint32_t Index); + bool hasFunctionIndex() const; + const WasmSignature *FunctionType; + +protected: + FunctionSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, + const WasmSignature *Type) + : Symbol(Name, K, Flags, F), FunctionType(Type) {} + + uint32_t TableIndex = INVALID_INDEX; + uint32_t FunctionIndex = INVALID_INDEX; +}; + +class DefinedFunction : public FunctionSymbol { +public: + DefinedFunction(StringRef Name, uint32_t Flags, InputFile *F, + InputFunction *Function); + + static bool classof(const Symbol *S) { + return S->kind() == DefinedFunctionKind; + } + + InputFunction *Function; +}; + +class UndefinedFunction : public FunctionSymbol { +public: + UndefinedFunction(StringRef Name, uint32_t Flags, InputFile *File = nullptr, + const WasmSignature *Type = nullptr) + : FunctionSymbol(Name, UndefinedFunctionKind, Flags, File, Type) {} + + static bool classof(const Symbol *S) { + return S->kind() == UndefinedFunctionKind; + } +}; + +class SectionSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { return S->kind() == SectionKind; } + + SectionSymbol(StringRef Name, uint32_t Flags, const InputSection *S, + InputFile *F = nullptr) + : Symbol(Name, SectionKind, Flags, F), Section(S) {} + + const InputSection *Section; + + uint32_t getOutputSectionIndex() const; + void setOutputSectionIndex(uint32_t Index); + +protected: + uint32_t OutputSectionIndex = INVALID_INDEX; +}; + +class DataSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { + return S->kind() == DefinedDataKind || S->kind() == UndefinedDataKind; + } + +protected: + DataSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F) + : Symbol(Name, K, Flags, F) {} +}; + +class DefinedData : public DataSymbol { +public: + // Constructor for regular data symbols originating from input files. + DefinedData(StringRef Name, uint32_t Flags, InputFile *F, + InputSegment *Segment, uint32_t Offset, uint32_t Size) + : DataSymbol(Name, DefinedDataKind, Flags, F), Segment(Segment), + Offset(Offset), Size(Size) {} + + // Constructor for linker synthetic data symbols. + DefinedData(StringRef Name, uint32_t Flags) + : DataSymbol(Name, DefinedDataKind, Flags, nullptr) {} + + static bool classof(const Symbol *S) { return S->kind() == DefinedDataKind; } + + // Returns the output virtual address of a defined data symbol. + uint32_t getVirtualAddress() const; void setVirtualAddress(uint32_t VA); - void update(Kind K, InputFile *F = nullptr, const WasmSymbol *Sym = nullptr, - const InputSegment *Segment = nullptr, - const WasmSignature *Sig = nullptr); + // Returns the offset of a defined data symbol within its OutputSegment. + uint32_t getOutputSegmentOffset() const; + uint32_t getOutputSegmentIndex() const; + uint32_t getSize() const { return Size; } + + InputSegment *Segment = nullptr; + +protected: + uint32_t Offset = 0; + uint32_t Size = 0; +}; + +class UndefinedData : public DataSymbol { +public: + UndefinedData(StringRef Name, uint32_t Flags, InputFile *File = nullptr) + : DataSymbol(Name, UndefinedDataKind, Flags, File) {} + static bool classof(const Symbol *S) { + return S->kind() == UndefinedDataKind; + } +}; - void setArchiveSymbol(const Archive::Symbol &Sym) { ArchiveSymbol = Sym; } - const Archive::Symbol &getArchiveSymbol() { return ArchiveSymbol; } +class GlobalSymbol : public Symbol { +public: + static bool classof(const Symbol *S) { + return S->kind() == DefinedGlobalKind || S->kind() == UndefinedGlobalKind; + } - // This bit is used by Writer::writeNameSection() to prevent - // symbols from being written to the symbol table more than once. - unsigned WrittenToSymtab : 1; - unsigned WrittenToNameSec : 1; + const WasmGlobalType *getGlobalType() const { return GlobalType; } + + // Get/set the global index + uint32_t getGlobalIndex() const; + void setGlobalIndex(uint32_t Index); + bool hasGlobalIndex() const; protected: - unsigned IsLocal : 1; + GlobalSymbol(StringRef Name, Kind K, uint32_t Flags, InputFile *F, + const WasmGlobalType *GlobalType) + : Symbol(Name, K, Flags, F), GlobalType(GlobalType) {} - StringRef Name; - Archive::Symbol ArchiveSymbol = {nullptr, 0, 0}; - Kind SymbolKind = InvalidKind; - InputFile *File = nullptr; - const WasmSymbol *Sym = nullptr; - const InputSegment *Segment = nullptr; - llvm::Optional<uint32_t> OutputIndex; - llvm::Optional<uint32_t> TableIndex; - llvm::Optional<uint32_t> VirtualAddress; - const WasmSignature *FunctionType; + // Explicit function type, needed for undefined or synthetic functions only. + // For regular defined globals this information comes from the InputChunk. + const WasmGlobalType *GlobalType; + uint32_t GlobalIndex = INVALID_INDEX; }; +class DefinedGlobal : public GlobalSymbol { +public: + DefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File, + InputGlobal *Global); + + static bool classof(const Symbol *S) { + return S->kind() == DefinedGlobalKind; + } + + InputGlobal *Global; +}; + +class UndefinedGlobal : public GlobalSymbol { +public: + UndefinedGlobal(StringRef Name, uint32_t Flags, InputFile *File = nullptr, + const WasmGlobalType *Type = nullptr) + : GlobalSymbol(Name, UndefinedGlobalKind, Flags, File, Type) {} + + static bool classof(const Symbol *S) { + return S->kind() == UndefinedGlobalKind; + } +}; + +class LazySymbol : public Symbol { +public: + LazySymbol(StringRef Name, InputFile *File, const Archive::Symbol &Sym) + : Symbol(Name, LazyKind, 0, File), ArchiveSymbol(Sym) {} + + static bool classof(const Symbol *S) { return S->kind() == LazyKind; } + void fetch(); + +private: + Archive::Symbol ArchiveSymbol; +}; + +// linker-generated symbols +struct WasmSym { + // __stack_pointer + // Global that holds the address of the top of the explicit value stack in + // linear memory. + static DefinedGlobal *StackPointer; + + // __data_end + // Symbol marking the end of the data and bss. + static DefinedData *DataEnd; + + // __heap_base + // Symbol marking the end of the data, bss and explicit stack. Any linear + // memory following this address is not used by the linked code and can + // therefore be used as a backing store for brk()/malloc() implementations. + static DefinedData *HeapBase; + + // __wasm_call_ctors + // Function that directly calls all ctors in priority order. + static DefinedFunction *CallCtors; + + // __dso_handle + // Symbol used in calls to __cxa_atexit to determine current DLL + static DefinedData *DsoHandle; +}; + +// A buffer class that is large enough to hold any Symbol-derived +// object. We allocate memory using this class and instantiate a symbol +// using the placement new. +union SymbolUnion { + alignas(DefinedFunction) char A[sizeof(DefinedFunction)]; + alignas(DefinedData) char B[sizeof(DefinedData)]; + alignas(DefinedGlobal) char C[sizeof(DefinedGlobal)]; + alignas(LazySymbol) char D[sizeof(LazySymbol)]; + alignas(UndefinedFunction) char E[sizeof(UndefinedFunction)]; + alignas(UndefinedData) char F[sizeof(UndefinedData)]; + alignas(UndefinedGlobal) char G[sizeof(UndefinedGlobal)]; + alignas(SectionSymbol) char I[sizeof(SectionSymbol)]; +}; + +template <typename T, typename... ArgT> +T *replaceSymbol(Symbol *S, ArgT &&... Arg) { + static_assert(std::is_trivially_destructible<T>(), + "Symbol types must be trivially destructible"); + static_assert(sizeof(T) <= sizeof(SymbolUnion), "Symbol too small"); + static_assert(alignof(T) <= alignof(SymbolUnion), + "SymbolUnion not aligned enough"); + assert(static_cast<Symbol *>(static_cast<T *>(nullptr)) == nullptr && + "Not a Symbol"); + + Symbol SymCopy = *S; + + T *S2 = new (S) T(std::forward<ArgT>(Arg)...); + S2->IsUsedInRegularObj = SymCopy.IsUsedInRegularObj; + S2->ForceExport = SymCopy.ForceExport; + return S2; +} + } // namespace wasm // Returns a symbol name for an error message. diff --git a/wasm/Writer.cpp b/wasm/Writer.cpp index e7dd49d52213..37ad32452a91 100644 --- a/wasm/Writer.cpp +++ b/wasm/Writer.cpp @@ -8,21 +8,28 @@ //===----------------------------------------------------------------------===// #include "Writer.h" - #include "Config.h" +#include "InputChunks.h" +#include "InputGlobal.h" #include "OutputSections.h" #include "OutputSegment.h" #include "SymbolTable.h" #include "WriterUtils.h" #include "lld/Common/ErrorHandler.h" #include "lld/Common/Memory.h" +#include "lld/Common/Strings.h" #include "lld/Common/Threads.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/Object/WasmTraits.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/LEB128.h" #include <cstdarg> +#include <map> #define DEBUG_TYPE "lld" @@ -32,31 +39,16 @@ using namespace lld; using namespace lld::wasm; static constexpr int kStackAlignment = 16; +static constexpr int kInitialTableOffset = 1; +static constexpr const char *kFunctionTableName = "__indirect_function_table"; namespace { -// Traits for using WasmSignature in a DenseMap. -struct WasmSignatureDenseMapInfo { - static WasmSignature getEmptyKey() { - WasmSignature Sig; - Sig.ReturnType = 1; - return Sig; - } - static WasmSignature getTombstoneKey() { - WasmSignature Sig; - Sig.ReturnType = 2; - return Sig; - } - static unsigned getHashValue(const WasmSignature &Sig) { - uintptr_t Value = 0; - Value += DenseMapInfo<int32_t>::getHashValue(Sig.ReturnType); - for (int32_t Param : Sig.ParamTypes) - Value += DenseMapInfo<int32_t>::getHashValue(Param); - return Value; - } - static bool isEqual(const WasmSignature &LHS, const WasmSignature &RHS) { - return LHS == RHS; - } +// An init entry to be written to either the synthetic init func or the +// linking metadata. +struct WasmInitEntry { + const FunctionSymbol *Sym; + uint32_t Priority; }; // The writer writes a SymbolTable result to a file. @@ -67,17 +59,22 @@ public: private: void openFile(); - uint32_t getTypeIndex(const WasmSignature &Sig); - void assignSymbolIndexes(); + uint32_t lookupType(const WasmSignature &Sig); + uint32_t registerType(const WasmSignature &Sig); + + void createCtorFunction(); + void calculateInitFunctions(); + void assignIndexes(); void calculateImports(); - void calculateOffsets(); + void calculateExports(); + void calculateCustomSections(); + void assignSymtab(); void calculateTypes(); void createOutputSegments(); void layoutMemory(); void createHeader(); void createSections(); - SyntheticSection *createSyntheticSection(uint32_t Type, - std::string Name = ""); + SyntheticSection *createSyntheticSection(uint32_t Type, StringRef Name = ""); // Builtin sections void createTypeSection(); @@ -88,9 +85,9 @@ private: void createImportSection(); void createMemorySection(); void createElemSection(); - void createStartSection(); void createCodeSection(); void createDataSection(); + void createCustomSections(); // Custom sections void createRelocSections(); @@ -101,17 +98,24 @@ private: void writeSections(); uint64_t FileSize = 0; - uint32_t DataSize = 0; - uint32_t NumFunctions = 0; uint32_t NumMemoryPages = 0; - uint32_t InitialTableOffset = 0; + uint32_t MaxMemoryPages = 0; std::vector<const WasmSignature *> Types; - DenseMap<WasmSignature, int32_t, WasmSignatureDenseMapInfo> TypeIndices; - std::vector<const Symbol *> FunctionImports; - std::vector<const Symbol *> GlobalImports; - std::vector<const Symbol *> DefinedGlobals; - std::vector<const Symbol *> IndirectFunctions; + DenseMap<WasmSignature, int32_t> TypeIndices; + std::vector<const Symbol *> ImportedSymbols; + unsigned NumImportedFunctions = 0; + unsigned NumImportedGlobals = 0; + std::vector<WasmExport> Exports; + std::vector<const DefinedData *> DefinedFakeGlobals; + std::vector<InputGlobal *> InputGlobals; + std::vector<InputFunction *> InputFunctions; + std::vector<const FunctionSymbol *> IndirectFunctions; + std::vector<const Symbol *> SymtabEntries; + std::vector<WasmInitEntry> InitFunctions; + + llvm::StringMap<std::vector<InputSection *>> CustomSectionMapping; + llvm::StringMap<SectionSymbol *> CustomSectionSymbols; // Elements that are used to construct the final output std::string Header; @@ -125,20 +129,12 @@ private: } // anonymous namespace -static void debugPrint(const char *fmt, ...) { - if (!errorHandler().Verbose) - return; - fprintf(stderr, "lld: "); - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} - void Writer::createImportSection() { - uint32_t NumImports = FunctionImports.size() + GlobalImports.size(); + uint32_t NumImports = ImportedSymbols.size(); if (Config->ImportMemory) ++NumImports; + if (Config->ImportTable) + ++NumImports; if (NumImports == 0) return; @@ -148,16 +144,6 @@ void Writer::createImportSection() { writeUleb128(OS, NumImports, "import count"); - for (const Symbol *Sym : FunctionImports) { - WasmImport Import; - Import.Module = "env"; - Import.Field = Sym->getName(); - Import.Kind = WASM_EXTERNAL_FUNCTION; - assert(TypeIndices.count(Sym->getFunctionType()) > 0); - Import.SigIndex = TypeIndices.lookup(Sym->getFunctionType()); - writeImport(OS, Import); - } - if (Config->ImportMemory) { WasmImport Import; Import.Module = "env"; @@ -165,16 +151,36 @@ void Writer::createImportSection() { Import.Kind = WASM_EXTERNAL_MEMORY; Import.Memory.Flags = 0; Import.Memory.Initial = NumMemoryPages; + if (MaxMemoryPages != 0) { + Import.Memory.Flags |= WASM_LIMITS_FLAG_HAS_MAX; + Import.Memory.Maximum = MaxMemoryPages; + } writeImport(OS, Import); } - for (const Symbol *Sym : GlobalImports) { + if (Config->ImportTable) { + uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size(); + WasmImport Import; + Import.Module = "env"; + Import.Field = kFunctionTableName; + Import.Kind = WASM_EXTERNAL_TABLE; + Import.Table.ElemType = WASM_TYPE_ANYFUNC; + Import.Table.Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize}; + writeImport(OS, Import); + } + + for (const Symbol *Sym : ImportedSymbols) { WasmImport Import; Import.Module = "env"; Import.Field = Sym->getName(); - Import.Kind = WASM_EXTERNAL_GLOBAL; - Import.Global.Mutable = false; - Import.Global.Type = WASM_TYPE_I32; + if (auto *FunctionSym = dyn_cast<FunctionSymbol>(Sym)) { + Import.Kind = WASM_EXTERNAL_FUNCTION; + Import.SigIndex = lookupType(*FunctionSym->FunctionType); + } else { + auto *GlobalSym = cast<GlobalSymbol>(Sym); + Import.Kind = WASM_EXTERNAL_GLOBAL; + Import.Global = *GlobalSym->getGlobalType(); + } writeImport(OS, Import); } } @@ -188,16 +194,15 @@ void Writer::createTypeSection() { } void Writer::createFunctionSection() { - if (!NumFunctions) + if (InputFunctions.empty()) return; SyntheticSection *Section = createSyntheticSection(WASM_SEC_FUNCTION); raw_ostream &OS = Section->getStream(); - writeUleb128(OS, NumFunctions, "function count"); - for (ObjFile *File : Symtab->ObjectFiles) - for (uint32_t Sig : File->getWasmObj()->functionTypes()) - writeUleb128(OS, File->relocateTypeIndex(Sig), "sig index"); + writeUleb128(OS, InputFunctions.size(), "function count"); + for (const InputFunction *Func : InputFunctions) + writeUleb128(OS, lookupType(Func->Signature), "sig index"); } void Writer::createMemorySection() { @@ -207,23 +212,29 @@ void Writer::createMemorySection() { SyntheticSection *Section = createSyntheticSection(WASM_SEC_MEMORY); raw_ostream &OS = Section->getStream(); + bool HasMax = MaxMemoryPages != 0; writeUleb128(OS, 1, "memory count"); - writeUleb128(OS, 0, "memory limits flags"); + writeUleb128(OS, HasMax ? static_cast<unsigned>(WASM_LIMITS_FLAG_HAS_MAX) : 0, + "memory limits flags"); writeUleb128(OS, NumMemoryPages, "initial pages"); + if (HasMax) + writeUleb128(OS, MaxMemoryPages, "max pages"); } void Writer::createGlobalSection() { - if (DefinedGlobals.empty()) + unsigned NumGlobals = InputGlobals.size() + DefinedFakeGlobals.size(); + if (NumGlobals == 0) return; SyntheticSection *Section = createSyntheticSection(WASM_SEC_GLOBAL); raw_ostream &OS = Section->getStream(); - writeUleb128(OS, DefinedGlobals.size(), "global count"); - for (const Symbol *Sym : DefinedGlobals) { + writeUleb128(OS, NumGlobals, "global count"); + for (const InputGlobal *G : InputGlobals) + writeGlobal(OS, G->Global); + for (const DefinedData *Sym : DefinedFakeGlobals) { WasmGlobal Global; - Global.Type = WASM_TYPE_I32; - Global.Mutable = Sym == Config->StackPointerSymbol; + Global.Type = {WASM_TYPE_I32, false}; Global.InitExpr.Opcode = WASM_OPCODE_I32_CONST; Global.InitExpr.Value.Int32 = Sym->getVirtualAddress(); writeGlobal(OS, Global); @@ -231,88 +242,73 @@ void Writer::createGlobalSection() { } void Writer::createTableSection() { - // Always output a table section, even if there are no indirect calls. - // There are two reasons for this: + if (Config->ImportTable) + return; + + // Always output a table section (or table import), even if there are no + // indirect calls. There are two reasons for this: // 1. For executables it is useful to have an empty table slot at 0 // which can be filled with a null function call handler. // 2. If we don't do this, any program that contains a call_indirect but // no address-taken function will fail at validation time since it is // a validation error to include a call_indirect instruction if there // is not table. - uint32_t TableSize = InitialTableOffset + IndirectFunctions.size(); + uint32_t TableSize = kInitialTableOffset + IndirectFunctions.size(); SyntheticSection *Section = createSyntheticSection(WASM_SEC_TABLE); raw_ostream &OS = Section->getStream(); writeUleb128(OS, 1, "table count"); - writeSleb128(OS, WASM_TYPE_ANYFUNC, "table type"); - writeUleb128(OS, WASM_LIMITS_FLAG_HAS_MAX, "table flags"); - writeUleb128(OS, TableSize, "table initial size"); - writeUleb128(OS, TableSize, "table max size"); + WasmLimits Limits = {WASM_LIMITS_FLAG_HAS_MAX, TableSize, TableSize}; + writeTableType(OS, WasmTable{WASM_TYPE_ANYFUNC, Limits}); } void Writer::createExportSection() { - bool ExportMemory = !Config->Relocatable && !Config->ImportMemory; - Symbol *EntrySym = Symtab->find(Config->Entry); - bool ExportEntry = !Config->Relocatable && EntrySym && EntrySym->isDefined(); - bool ExportHidden = Config->EmitRelocs; - - uint32_t NumExports = ExportMemory ? 1 : 0; - - std::vector<const Symbol *> SymbolExports; - if (ExportEntry) - SymbolExports.emplace_back(EntrySym); - - for (const Symbol *Sym : Symtab->getSymbols()) { - if (Sym->isUndefined() || Sym->isGlobal()) - continue; - if (Sym->isHidden() && !ExportHidden) - continue; - if (ExportEntry && Sym == EntrySym) - continue; - SymbolExports.emplace_back(Sym); - } - - for (const Symbol *Sym : DefinedGlobals) { - // Can't export the SP right now because it mutable and mutable globals - // connot be exported. - if (Sym == Config->StackPointerSymbol) - continue; - SymbolExports.emplace_back(Sym); - } - - NumExports += SymbolExports.size(); - if (!NumExports) + if (!Exports.size()) return; SyntheticSection *Section = createSyntheticSection(WASM_SEC_EXPORT); raw_ostream &OS = Section->getStream(); - writeUleb128(OS, NumExports, "export count"); + writeUleb128(OS, Exports.size(), "export count"); + for (const WasmExport &Export : Exports) + writeExport(OS, Export); +} - if (ExportMemory) { - WasmExport MemoryExport; - MemoryExport.Name = "memory"; - MemoryExport.Kind = WASM_EXTERNAL_MEMORY; - MemoryExport.Index = 0; - writeExport(OS, MemoryExport); +void Writer::calculateCustomSections() { + log("calculateCustomSections"); + bool StripDebug = Config->StripDebug || Config->StripAll; + for (ObjFile *File : Symtab->ObjectFiles) { + for (InputSection *Section : File->CustomSections) { + StringRef Name = Section->getName(); + // These custom sections are known the linker and synthesized rather than + // blindly copied + if (Name == "linking" || Name == "name" || Name.startswith("reloc.")) + continue; + // .. or it is a debug section + if (StripDebug && Name.startswith(".debug_")) + continue; + CustomSectionMapping[Name].push_back(Section); + } } +} - for (const Symbol *Sym : SymbolExports) { - log("Export: " + Sym->getName()); - WasmExport Export; - Export.Name = Sym->getName(); - Export.Index = Sym->getOutputIndex(); - if (Sym->isFunction()) - Export.Kind = WASM_EXTERNAL_FUNCTION; - else - Export.Kind = WASM_EXTERNAL_GLOBAL; - writeExport(OS, Export); +void Writer::createCustomSections() { + log("createCustomSections"); + for (auto &Pair : CustomSectionMapping) { + StringRef Name = Pair.first(); + + auto P = CustomSectionSymbols.find(Name); + if (P != CustomSectionSymbols.end()) { + uint32_t SectionIndex = OutputSections.size(); + P->second->setOutputSectionIndex(SectionIndex); + } + + LLVM_DEBUG(dbgs() << "createCustomSection: " << Name << "\n"); + OutputSections.push_back(make<CustomSection>(Name, Pair.second)); } } -void Writer::createStartSection() {} - void Writer::createElemSection() { if (IndirectFunctions.empty()) return; @@ -324,25 +320,25 @@ void Writer::createElemSection() { writeUleb128(OS, 0, "table index"); WasmInitExpr InitExpr; InitExpr.Opcode = WASM_OPCODE_I32_CONST; - InitExpr.Value.Int32 = InitialTableOffset; + InitExpr.Value.Int32 = kInitialTableOffset; writeInitExpr(OS, InitExpr); writeUleb128(OS, IndirectFunctions.size(), "elem count"); - uint32_t TableIndex = InitialTableOffset; - for (const Symbol *Sym : IndirectFunctions) { + uint32_t TableIndex = kInitialTableOffset; + for (const FunctionSymbol *Sym : IndirectFunctions) { assert(Sym->getTableIndex() == TableIndex); - writeUleb128(OS, Sym->getOutputIndex(), "function index"); + writeUleb128(OS, Sym->getFunctionIndex(), "function index"); ++TableIndex; } } void Writer::createCodeSection() { - if (!NumFunctions) + if (InputFunctions.empty()) return; log("createCodeSection"); - auto Section = make<CodeSection>(NumFunctions, Symtab->ObjectFiles); + auto Section = make<CodeSection>(InputFunctions); OutputSections.push_back(Section); } @@ -361,28 +357,68 @@ void Writer::createRelocSections() { log("createRelocSections"); // Don't use iterator here since we are adding to OutputSection size_t OrigSize = OutputSections.size(); - for (size_t i = 0; i < OrigSize; i++) { - OutputSection *S = OutputSections[i]; - const char *name; - uint32_t Count = S->numRelocations(); + for (size_t I = 0; I < OrigSize; I++) { + OutputSection *OSec = OutputSections[I]; + uint32_t Count = OSec->numRelocations(); if (!Count) continue; - if (S->Type == WASM_SEC_DATA) - name = "reloc.DATA"; - else if (S->Type == WASM_SEC_CODE) - name = "reloc.CODE"; + StringRef Name; + if (OSec->Type == WASM_SEC_DATA) + Name = "reloc.DATA"; + else if (OSec->Type == WASM_SEC_CODE) + Name = "reloc.CODE"; + else if (OSec->Type == WASM_SEC_CUSTOM) + Name = Saver.save("reloc." + OSec->Name); else - llvm_unreachable("relocations only supported for code and data"); + llvm_unreachable( + "relocations only supported for code, data, or custom sections"); - SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, name); + SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, Name); raw_ostream &OS = Section->getStream(); - writeUleb128(OS, S->Type, "reloc section"); + writeUleb128(OS, I, "reloc section"); writeUleb128(OS, Count, "reloc count"); - S->writeRelocations(OS); + OSec->writeRelocations(OS); } } +static uint32_t getWasmFlags(const Symbol *Sym) { + uint32_t Flags = 0; + if (Sym->isLocal()) + Flags |= WASM_SYMBOL_BINDING_LOCAL; + if (Sym->isWeak()) + Flags |= WASM_SYMBOL_BINDING_WEAK; + if (Sym->isHidden()) + Flags |= WASM_SYMBOL_VISIBILITY_HIDDEN; + if (Sym->isUndefined()) + Flags |= WASM_SYMBOL_UNDEFINED; + return Flags; +} + +// Some synthetic sections (e.g. "name" and "linking") have subsections. +// Just like the synthetic sections themselves these need to be created before +// they can be written out (since they are preceded by their length). This +// class is used to create subsections and then write them into the stream +// of the parent section. +class SubSection { +public: + explicit SubSection(uint32_t Type) : Type(Type) {} + + void writeTo(raw_ostream &To) { + OS.flush(); + writeUleb128(To, Type, "subsection type"); + writeUleb128(To, Body.size(), "subsection size"); + To.write(Body.data(), Body.size()); + } + +private: + uint32_t Type; + std::string Body; + +public: + raw_string_ostream OS{Body}; +}; + // Create the custom "linking" section containing linker metadata. // This is only created when relocatable output is requested. void Writer::createLinkingSection() { @@ -390,82 +426,145 @@ void Writer::createLinkingSection() { createSyntheticSection(WASM_SEC_CUSTOM, "linking"); raw_ostream &OS = Section->getStream(); - SubSection DataSizeSubSection(WASM_DATA_SIZE); - writeUleb128(DataSizeSubSection.getStream(), DataSize, "data size"); - DataSizeSubSection.finalizeContents(); - DataSizeSubSection.writeToStream(OS); + writeUleb128(OS, WasmMetadataVersion, "Version"); + + if (!SymtabEntries.empty()) { + SubSection Sub(WASM_SYMBOL_TABLE); + writeUleb128(Sub.OS, SymtabEntries.size(), "num symbols"); + + for (const Symbol *Sym : SymtabEntries) { + assert(Sym->isDefined() || Sym->isUndefined()); + WasmSymbolType Kind = Sym->getWasmType(); + uint32_t Flags = getWasmFlags(Sym); + + writeU8(Sub.OS, Kind, "sym kind"); + writeUleb128(Sub.OS, Flags, "sym flags"); + + if (auto *F = dyn_cast<FunctionSymbol>(Sym)) { + writeUleb128(Sub.OS, F->getFunctionIndex(), "index"); + if (Sym->isDefined()) + writeStr(Sub.OS, Sym->getName(), "sym name"); + } else if (auto *G = dyn_cast<GlobalSymbol>(Sym)) { + writeUleb128(Sub.OS, G->getGlobalIndex(), "index"); + if (Sym->isDefined()) + writeStr(Sub.OS, Sym->getName(), "sym name"); + } else if (isa<DataSymbol>(Sym)) { + writeStr(Sub.OS, Sym->getName(), "sym name"); + if (auto *DataSym = dyn_cast<DefinedData>(Sym)) { + writeUleb128(Sub.OS, DataSym->getOutputSegmentIndex(), "index"); + writeUleb128(Sub.OS, DataSym->getOutputSegmentOffset(), + "data offset"); + writeUleb128(Sub.OS, DataSym->getSize(), "data size"); + } + } else { + auto *S = cast<SectionSymbol>(Sym); + writeUleb128(Sub.OS, S->getOutputSectionIndex(), "sym section index"); + } + } - if (!Config->Relocatable) - return; + Sub.writeTo(OS); + } if (Segments.size()) { - SubSection SubSection(WASM_SEGMENT_INFO); - writeUleb128(SubSection.getStream(), Segments.size(), "num data segments"); + SubSection Sub(WASM_SEGMENT_INFO); + writeUleb128(Sub.OS, Segments.size(), "num data segments"); for (const OutputSegment *S : Segments) { - writeStr(SubSection.getStream(), S->Name, "segment name"); - writeUleb128(SubSection.getStream(), S->Alignment, "alignment"); - writeUleb128(SubSection.getStream(), 0, "flags"); + writeStr(Sub.OS, S->Name, "segment name"); + writeUleb128(Sub.OS, S->Alignment, "alignment"); + writeUleb128(Sub.OS, 0, "flags"); } - SubSection.finalizeContents(); - SubSection.writeToStream(OS); + Sub.writeTo(OS); } - std::vector<WasmInitFunc> InitFunctions; - for (ObjFile *File : Symtab->ObjectFiles) { - const WasmLinkingData &L = File->getWasmObj()->linkingData(); - InitFunctions.reserve(InitFunctions.size() + L.InitFunctions.size()); - for (const WasmInitFunc &F : L.InitFunctions) - InitFunctions.emplace_back(WasmInitFunc{ - F.Priority, File->relocateFunctionIndex(F.FunctionIndex)}); + if (!InitFunctions.empty()) { + SubSection Sub(WASM_INIT_FUNCS); + writeUleb128(Sub.OS, InitFunctions.size(), "num init functions"); + for (const WasmInitEntry &F : InitFunctions) { + writeUleb128(Sub.OS, F.Priority, "priority"); + writeUleb128(Sub.OS, F.Sym->getOutputSymbolIndex(), "function index"); + } + Sub.writeTo(OS); } - if (!InitFunctions.empty()) { - SubSection SubSection(WASM_INIT_FUNCS); - writeUleb128(SubSection.getStream(), InitFunctions.size(), - "num init functionsw"); - for (const WasmInitFunc &F : InitFunctions) { - writeUleb128(SubSection.getStream(), F.Priority, "priority"); - writeUleb128(SubSection.getStream(), F.FunctionIndex, "function index"); + struct ComdatEntry { + unsigned Kind; + uint32_t Index; + }; + std::map<StringRef, std::vector<ComdatEntry>> Comdats; + + for (const InputFunction *F : InputFunctions) { + StringRef Comdat = F->getComdatName(); + if (!Comdat.empty()) + Comdats[Comdat].emplace_back( + ComdatEntry{WASM_COMDAT_FUNCTION, F->getFunctionIndex()}); + } + for (uint32_t I = 0; I < Segments.size(); ++I) { + const auto &InputSegments = Segments[I]->InputSegments; + if (InputSegments.empty()) + continue; + StringRef Comdat = InputSegments[0]->getComdatName(); +#ifndef NDEBUG + for (const InputSegment *IS : InputSegments) + assert(IS->getComdatName() == Comdat); +#endif + if (!Comdat.empty()) + Comdats[Comdat].emplace_back(ComdatEntry{WASM_COMDAT_DATA, I}); + } + + if (!Comdats.empty()) { + SubSection Sub(WASM_COMDAT_INFO); + writeUleb128(Sub.OS, Comdats.size(), "num comdats"); + for (const auto &C : Comdats) { + writeStr(Sub.OS, C.first, "comdat name"); + writeUleb128(Sub.OS, 0, "comdat flags"); // flags for future use + writeUleb128(Sub.OS, C.second.size(), "num entries"); + for (const ComdatEntry &Entry : C.second) { + writeU8(Sub.OS, Entry.Kind, "entry kind"); + writeUleb128(Sub.OS, Entry.Index, "entry index"); + } } - SubSection.finalizeContents(); - SubSection.writeToStream(OS); + Sub.writeTo(OS); } } // Create the custom "name" section containing debug symbol names. void Writer::createNameSection() { - // Create an array of all function sorted by function index space - std::vector<const Symbol *> Names; + unsigned NumNames = NumImportedFunctions; + for (const InputFunction *F : InputFunctions) + if (!F->getName().empty() || !F->getDebugName().empty()) + ++NumNames; - for (ObjFile *File : Symtab->ObjectFiles) { - Names.reserve(Names.size() + File->getSymbols().size()); - for (Symbol *S : File->getSymbols()) { - if (!S->isFunction() || S->isWeak() || S->WrittenToNameSec) - continue; - S->WrittenToNameSec = true; - Names.emplace_back(S); - } - } + if (NumNames == 0) + return; SyntheticSection *Section = createSyntheticSection(WASM_SEC_CUSTOM, "name"); - std::sort(Names.begin(), Names.end(), [](const Symbol *A, const Symbol *B) { - return A->getOutputIndex() < B->getOutputIndex(); - }); - - SubSection FunctionSubsection(WASM_NAMES_FUNCTION); - raw_ostream &OS = FunctionSubsection.getStream(); - writeUleb128(OS, Names.size(), "name count"); - - // We have to iterate through the inputs twice so that all the imports - // appear first before any of the local function names. - for (const Symbol *S : Names) { - writeUleb128(OS, S->getOutputIndex(), "func index"); - writeStr(OS, S->getName(), "symbol name"); + SubSection Sub(WASM_NAMES_FUNCTION); + writeUleb128(Sub.OS, NumNames, "name count"); + + // Names must appear in function index order. As it happens ImportedSymbols + // and InputFunctions are numbered in order with imported functions coming + // first. + for (const Symbol *S : ImportedSymbols) { + if (auto *F = dyn_cast<FunctionSymbol>(S)) { + writeUleb128(Sub.OS, F->getFunctionIndex(), "func index"); + Optional<std::string> Name = demangleItanium(F->getName()); + writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name"); + } + } + for (const InputFunction *F : InputFunctions) { + if (!F->getName().empty()) { + writeUleb128(Sub.OS, F->getFunctionIndex(), "func index"); + if (!F->getDebugName().empty()) { + writeStr(Sub.OS, F->getDebugName(), "symbol name"); + } else { + Optional<std::string> Name = demangleItanium(F->getName()); + writeStr(Sub.OS, Name ? StringRef(*Name) : F->getName(), "symbol name"); + } + } } - FunctionSubsection.finalizeContents(); - FunctionSubsection.writeToStream(Section->getStream()); + Sub.writeTo(Section->getStream()); } void Writer::writeHeader() { @@ -479,48 +578,98 @@ void Writer::writeSections() { // Fix the memory layout of the output binary. This assigns memory offsets // to each of the input data sections as well as the explicit stack region. +// The default memory layout is as follows, from low to high. +// +// - initialized data (starting at Config->GlobalBase) +// - BSS data (not currently implemented in llvm) +// - explicit stack (Config->ZStackSize) +// - heap start / unallocated +// +// The --stack-first option means that stack is placed before any static data. +// This can be useful since it means that stack overflow traps immediately rather +// than overwriting global data, but also increases code size since all static +// data loads and stores requires larger offsets. void Writer::layoutMemory() { + createOutputSegments(); + uint32_t MemoryPtr = 0; - if (!Config->Relocatable) { + + auto PlaceStack = [&]() { + if (Config->Relocatable) + return; + MemoryPtr = alignTo(MemoryPtr, kStackAlignment); + if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment)) + error("stack size must be " + Twine(kStackAlignment) + "-byte aligned"); + log("mem: stack size = " + Twine(Config->ZStackSize)); + log("mem: stack base = " + Twine(MemoryPtr)); + MemoryPtr += Config->ZStackSize; + WasmSym::StackPointer->Global->Global.InitExpr.Value.Int32 = MemoryPtr; + log("mem: stack top = " + Twine(MemoryPtr)); + }; + + if (Config->StackFirst) { + PlaceStack(); + } else { MemoryPtr = Config->GlobalBase; - debugPrint("mem: global base = %d\n", Config->GlobalBase); + log("mem: global base = " + Twine(Config->GlobalBase)); } - createOutputSegments(); + uint32_t DataStart = MemoryPtr; + + // Arbitrarily set __dso_handle handle to point to the start of the data + // segments. + if (WasmSym::DsoHandle) + WasmSym::DsoHandle->setVirtualAddress(DataStart); - // Static data comes first for (OutputSegment *Seg : Segments) { MemoryPtr = alignTo(MemoryPtr, Seg->Alignment); Seg->StartVA = MemoryPtr; - debugPrint("mem: %-10s offset=%-8d size=%-4d align=%d\n", - Seg->Name.str().c_str(), MemoryPtr, Seg->Size, Seg->Alignment); + log(formatv("mem: {0,-15} offset={1,-8} size={2,-8} align={3}", Seg->Name, + MemoryPtr, Seg->Size, Seg->Alignment)); MemoryPtr += Seg->Size; } - DataSize = MemoryPtr; - if (!Config->Relocatable) - DataSize -= Config->GlobalBase; - debugPrint("mem: static data = %d\n", DataSize); + // TODO: Add .bss space here. + if (WasmSym::DataEnd) + WasmSym::DataEnd->setVirtualAddress(MemoryPtr); + + log("mem: static data = " + Twine(MemoryPtr - DataStart)); - // Stack comes after static data + if (!Config->StackFirst) + PlaceStack(); + + // Set `__heap_base` to directly follow the end of the stack or global data. + // The fact that this comes last means that a malloc/brk implementation + // can grow the heap at runtime. if (!Config->Relocatable) { - MemoryPtr = alignTo(MemoryPtr, kStackAlignment); - if (Config->ZStackSize != alignTo(Config->ZStackSize, kStackAlignment)) - error("stack size must be " + Twine(kStackAlignment) + "-byte aligned"); - debugPrint("mem: stack size = %d\n", Config->ZStackSize); - debugPrint("mem: stack base = %d\n", MemoryPtr); - MemoryPtr += Config->ZStackSize; - Config->StackPointerSymbol->setVirtualAddress(MemoryPtr); - debugPrint("mem: stack top = %d\n", MemoryPtr); + WasmSym::HeapBase->setVirtualAddress(MemoryPtr); + log("mem: heap base = " + Twine(MemoryPtr)); } + if (Config->InitialMemory != 0) { + if (Config->InitialMemory != alignTo(Config->InitialMemory, WasmPageSize)) + error("initial memory must be " + Twine(WasmPageSize) + "-byte aligned"); + if (MemoryPtr > Config->InitialMemory) + error("initial memory too small, " + Twine(MemoryPtr) + " bytes needed"); + else + MemoryPtr = Config->InitialMemory; + } uint32_t MemSize = alignTo(MemoryPtr, WasmPageSize); NumMemoryPages = MemSize / WasmPageSize; - debugPrint("mem: total pages = %d\n", NumMemoryPages); + log("mem: total pages = " + Twine(NumMemoryPages)); + + if (Config->MaxMemory != 0) { + if (Config->MaxMemory != alignTo(Config->MaxMemory, WasmPageSize)) + error("maximum memory must be " + Twine(WasmPageSize) + "-byte aligned"); + if (MemoryPtr > Config->MaxMemory) + error("maximum memory too small, " + Twine(MemoryPtr) + " bytes needed"); + MaxMemoryPages = Config->MaxMemory / WasmPageSize; + log("mem: max pages = " + Twine(MaxMemoryPages)); + } } SyntheticSection *Writer::createSyntheticSection(uint32_t Type, - std::string Name) { + StringRef Name) { auto Sec = make<SyntheticSection>(Type, Name); log("createSection: " + toString(*Sec)); OutputSections.push_back(Sec); @@ -536,15 +685,16 @@ void Writer::createSections() { createMemorySection(); createGlobalSection(); createExportSection(); - createStartSection(); createElemSection(); createCodeSection(); createDataSection(); + createCustomSections(); // Custom sections - if (Config->EmitRelocs) + if (Config->Relocatable) { + createLinkingSection(); createRelocSections(); - createLinkingSection(); + } if (!Config->StripDebug && !Config->StripAll) createNameSection(); @@ -555,149 +705,336 @@ void Writer::createSections() { } } -void Writer::calculateOffsets() { - for (ObjFile *File : Symtab->ObjectFiles) { - const WasmObjectFile *WasmFile = File->getWasmObj(); - - // Function Index - File->FunctionIndexOffset = - FunctionImports.size() - File->NumFunctionImports() + NumFunctions; - NumFunctions += WasmFile->functions().size(); +void Writer::calculateImports() { + for (Symbol *Sym : Symtab->getSymbols()) { + if (!Sym->isUndefined()) + continue; + if (isa<DataSymbol>(Sym)) + continue; + if (Sym->isWeak() && !Config->Relocatable) + continue; + if (!Sym->isLive()) + continue; + if (!Sym->IsUsedInRegularObj) + continue; - // Memory - if (WasmFile->memories().size() > 1) - fatal(File->getName() + ": contains more than one memory"); + LLVM_DEBUG(dbgs() << "import: " << Sym->getName() << "\n"); + ImportedSymbols.emplace_back(Sym); + if (auto *F = dyn_cast<FunctionSymbol>(Sym)) + F->setFunctionIndex(NumImportedFunctions++); + else + cast<GlobalSymbol>(Sym)->setGlobalIndex(NumImportedGlobals++); } } -void Writer::calculateImports() { +void Writer::calculateExports() { + if (Config->Relocatable) + return; + + if (!Config->Relocatable && !Config->ImportMemory) + Exports.push_back(WasmExport{"memory", WASM_EXTERNAL_MEMORY, 0}); + + if (!Config->Relocatable && Config->ExportTable) + Exports.push_back(WasmExport{kFunctionTableName, WASM_EXTERNAL_TABLE, 0}); + + unsigned FakeGlobalIndex = NumImportedGlobals + InputGlobals.size(); + for (Symbol *Sym : Symtab->getSymbols()) { - if (!Sym->isUndefined() || Sym->isWeak()) + if (!Sym->isExported()) + continue; + if (!Sym->isLive()) continue; - if (Sym->isFunction()) { - Sym->setOutputIndex(FunctionImports.size()); - FunctionImports.push_back(Sym); + StringRef Name = Sym->getName(); + WasmExport Export; + if (auto *F = dyn_cast<DefinedFunction>(Sym)) { + Export = {Name, WASM_EXTERNAL_FUNCTION, F->getFunctionIndex()}; + } else if (auto *G = dyn_cast<DefinedGlobal>(Sym)) { + // TODO(sbc): Remove this check once to mutable global proposal is + // implement in all major browsers. + // See: https://github.com/WebAssembly/mutable-global + if (G->getGlobalType()->Mutable) { + // Only the __stack_pointer should ever be create as mutable. + assert(G == WasmSym::StackPointer); + continue; + } + Export = {Name, WASM_EXTERNAL_GLOBAL, G->getGlobalIndex()}; } else { - Sym->setOutputIndex(GlobalImports.size()); - GlobalImports.push_back(Sym); + auto *D = cast<DefinedData>(Sym); + DefinedFakeGlobals.emplace_back(D); + Export = {Name, WASM_EXTERNAL_GLOBAL, FakeGlobalIndex++}; } + + LLVM_DEBUG(dbgs() << "Export: " << Name << "\n"); + Exports.push_back(Export); + } +} + +void Writer::assignSymtab() { + if (!Config->Relocatable) + return; + + StringMap<uint32_t> SectionSymbolIndices; + + unsigned SymbolIndex = SymtabEntries.size(); + for (ObjFile *File : Symtab->ObjectFiles) { + LLVM_DEBUG(dbgs() << "Symtab entries: " << File->getName() << "\n"); + for (Symbol *Sym : File->getSymbols()) { + if (Sym->getFile() != File) + continue; + + if (auto *S = dyn_cast<SectionSymbol>(Sym)) { + StringRef Name = S->getName(); + if (CustomSectionMapping.count(Name) == 0) + continue; + + auto SSI = SectionSymbolIndices.find(Name); + if (SSI != SectionSymbolIndices.end()) { + Sym->setOutputSymbolIndex(SSI->second); + continue; + } + + SectionSymbolIndices[Name] = SymbolIndex; + CustomSectionSymbols[Name] = cast<SectionSymbol>(Sym); + + Sym->markLive(); + } + + // (Since this is relocatable output, GC is not performed so symbols must + // be live.) + assert(Sym->isLive()); + Sym->setOutputSymbolIndex(SymbolIndex++); + SymtabEntries.emplace_back(Sym); + } + } + + // For the moment, relocatable output doesn't contain any synthetic functions, + // so no need to look through the Symtab for symbols not referenced by + // Symtab->ObjectFiles. +} + +uint32_t Writer::lookupType(const WasmSignature &Sig) { + auto It = TypeIndices.find(Sig); + if (It == TypeIndices.end()) { + error("type not found: " + toString(Sig)); + return 0; } + return It->second; } -uint32_t Writer::getTypeIndex(const WasmSignature &Sig) { +uint32_t Writer::registerType(const WasmSignature &Sig) { auto Pair = TypeIndices.insert(std::make_pair(Sig, Types.size())); - if (Pair.second) + if (Pair.second) { + LLVM_DEBUG(dbgs() << "type " << toString(Sig) << "\n"); Types.push_back(&Sig); + } return Pair.first->second; } void Writer::calculateTypes() { + // The output type section is the union of the following sets: + // 1. Any signature used in the TYPE relocation + // 2. The signatures of all imported functions + // 3. The signatures of all defined functions + for (ObjFile *File : Symtab->ObjectFiles) { - File->TypeMap.reserve(File->getWasmObj()->types().size()); - for (const WasmSignature &Sig : File->getWasmObj()->types()) - File->TypeMap.push_back(getTypeIndex(Sig)); + ArrayRef<WasmSignature> Types = File->getWasmObj()->types(); + for (uint32_t I = 0; I < Types.size(); I++) + if (File->TypeIsUsed[I]) + File->TypeMap[I] = registerType(Types[I]); } -} -void Writer::assignSymbolIndexes() { - uint32_t GlobalIndex = GlobalImports.size(); + for (const Symbol *Sym : ImportedSymbols) + if (auto *F = dyn_cast<FunctionSymbol>(Sym)) + registerType(*F->FunctionType); - if (Config->StackPointerSymbol) { - DefinedGlobals.emplace_back(Config->StackPointerSymbol); - Config->StackPointerSymbol->setOutputIndex(GlobalIndex++); - } + for (const InputFunction *F : InputFunctions) + registerType(F->Signature); +} - if (Config->EmitRelocs) - DefinedGlobals.reserve(Symtab->getSymbols().size()); +void Writer::assignIndexes() { + uint32_t FunctionIndex = NumImportedFunctions + InputFunctions.size(); + auto AddDefinedFunction = [&](InputFunction *Func) { + if (!Func->Live) + return; + InputFunctions.emplace_back(Func); + Func->setFunctionIndex(FunctionIndex++); + }; - uint32_t TableIndex = InitialTableOffset; + for (InputFunction *Func : Symtab->SyntheticFunctions) + AddDefinedFunction(Func); for (ObjFile *File : Symtab->ObjectFiles) { - DEBUG(dbgs() << "assignSymbolIndexes: " << File->getName() << "\n"); - - for (Symbol *Sym : File->getSymbols()) { - // Assign indexes for symbols defined with this file. - if (!Sym->isDefined() || File != Sym->getFile()) - continue; - if (Sym->isFunction()) { - auto *Obj = cast<ObjFile>(Sym->getFile()); - Sym->setOutputIndex(Obj->FunctionIndexOffset + - Sym->getFunctionIndex()); - } else if (Config->EmitRelocs) { - DefinedGlobals.emplace_back(Sym); - Sym->setOutputIndex(GlobalIndex++); - } - } + LLVM_DEBUG(dbgs() << "Functions: " << File->getName() << "\n"); + for (InputFunction *Func : File->Functions) + AddDefinedFunction(Func); + } - for (Symbol *Sym : File->getTableSymbols()) { - if (!Sym->hasTableIndex()) { + uint32_t TableIndex = kInitialTableOffset; + auto HandleRelocs = [&](InputChunk *Chunk) { + if (!Chunk->Live) + return; + ObjFile *File = Chunk->File; + ArrayRef<WasmSignature> Types = File->getWasmObj()->types(); + for (const WasmRelocation &Reloc : Chunk->getRelocations()) { + if (Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_I32 || + Reloc.Type == R_WEBASSEMBLY_TABLE_INDEX_SLEB) { + FunctionSymbol *Sym = File->getFunctionSymbol(Reloc.Index); + if (Sym->hasTableIndex() || !Sym->hasFunctionIndex()) + continue; Sym->setTableIndex(TableIndex++); IndirectFunctions.emplace_back(Sym); + } else if (Reloc.Type == R_WEBASSEMBLY_TYPE_INDEX_LEB) { + // Mark target type as live + File->TypeMap[Reloc.Index] = registerType(Types[Reloc.Index]); + File->TypeIsUsed[Reloc.Index] = true; } } + }; + + for (ObjFile *File : Symtab->ObjectFiles) { + LLVM_DEBUG(dbgs() << "Handle relocs: " << File->getName() << "\n"); + for (InputChunk *Chunk : File->Functions) + HandleRelocs(Chunk); + for (InputChunk *Chunk : File->Segments) + HandleRelocs(Chunk); + for (auto &P : File->CustomSections) + HandleRelocs(P); + } + + uint32_t GlobalIndex = NumImportedGlobals + InputGlobals.size(); + auto AddDefinedGlobal = [&](InputGlobal *Global) { + if (Global->Live) { + LLVM_DEBUG(dbgs() << "AddDefinedGlobal: " << GlobalIndex << "\n"); + Global->setGlobalIndex(GlobalIndex++); + InputGlobals.push_back(Global); + } + }; + + for (InputGlobal *Global : Symtab->SyntheticGlobals) + AddDefinedGlobal(Global); + + for (ObjFile *File : Symtab->ObjectFiles) { + LLVM_DEBUG(dbgs() << "Globals: " << File->getName() << "\n"); + for (InputGlobal *Global : File->Globals) + AddDefinedGlobal(Global); } } static StringRef getOutputDataSegmentName(StringRef Name) { - if (Config->Relocatable) + if (!Config->MergeDataSegments) return Name; - - for (StringRef V : - {".text.", ".rodata.", ".data.rel.ro.", ".data.", ".bss.rel.ro.", - ".bss.", ".init_array.", ".fini_array.", ".ctors.", ".dtors.", ".tbss.", - ".gcc_except_table.", ".tdata.", ".ARM.exidx.", ".ARM.extab."}) { - StringRef Prefix = V.drop_back(); - if (Name.startswith(V) || Name == Prefix) - return Prefix; - } - + if (Name.startswith(".text.")) + return ".text"; + if (Name.startswith(".data.")) + return ".data"; + if (Name.startswith(".bss.")) + return ".bss"; return Name; } void Writer::createOutputSegments() { for (ObjFile *File : Symtab->ObjectFiles) { for (InputSegment *Segment : File->Segments) { + if (!Segment->Live) + continue; StringRef Name = getOutputDataSegmentName(Segment->getName()); OutputSegment *&S = SegmentMap[Name]; if (S == nullptr) { - DEBUG(dbgs() << "new segment: " << Name << "\n"); - S = make<OutputSegment>(Name); + LLVM_DEBUG(dbgs() << "new segment: " << Name << "\n"); + S = make<OutputSegment>(Name, Segments.size()); Segments.push_back(S); } S->addInputSegment(Segment); - DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n"); + LLVM_DEBUG(dbgs() << "added data: " << Name << ": " << S->Size << "\n"); } } } +static const int OPCODE_CALL = 0x10; +static const int OPCODE_END = 0xb; + +// Create synthetic "__wasm_call_ctors" function based on ctor functions +// in input object. +void Writer::createCtorFunction() { + // First write the body's contents to a string. + std::string BodyContent; + { + raw_string_ostream OS(BodyContent); + writeUleb128(OS, 0, "num locals"); + for (const WasmInitEntry &F : InitFunctions) { + writeU8(OS, OPCODE_CALL, "CALL"); + writeUleb128(OS, F.Sym->getFunctionIndex(), "function index"); + } + writeU8(OS, OPCODE_END, "END"); + } + + // Once we know the size of the body we can create the final function body + std::string FunctionBody; + { + raw_string_ostream OS(FunctionBody); + writeUleb128(OS, BodyContent.size(), "function size"); + OS << BodyContent; + } + + ArrayRef<uint8_t> Body = toArrayRef(Saver.save(FunctionBody)); + cast<SyntheticFunction>(WasmSym::CallCtors->Function)->setBody(Body); +} + +// Populate InitFunctions vector with init functions from all input objects. +// This is then used either when creating the output linking section or to +// synthesize the "__wasm_call_ctors" function. +void Writer::calculateInitFunctions() { + for (ObjFile *File : Symtab->ObjectFiles) { + const WasmLinkingData &L = File->getWasmObj()->linkingData(); + for (const WasmInitFunc &F : L.InitFunctions) { + FunctionSymbol *Sym = File->getFunctionSymbol(F.Symbol); + if (*Sym->FunctionType != WasmSignature{{}, WASM_TYPE_NORESULT}) + error("invalid signature for init func: " + toString(*Sym)); + InitFunctions.emplace_back(WasmInitEntry{Sym, F.Priority}); + } + } + + // Sort in order of priority (lowest first) so that they are called + // in the correct order. + std::stable_sort(InitFunctions.begin(), InitFunctions.end(), + [](const WasmInitEntry &L, const WasmInitEntry &R) { + return L.Priority < R.Priority; + }); +} + void Writer::run() { - if (!Config->Relocatable) - InitialTableOffset = 1; + if (Config->Relocatable) + Config->GlobalBase = 0; - log("-- calculateTypes"); - calculateTypes(); log("-- calculateImports"); calculateImports(); - log("-- calculateOffsets"); - calculateOffsets(); + log("-- assignIndexes"); + assignIndexes(); + log("-- calculateInitFunctions"); + calculateInitFunctions(); + if (!Config->Relocatable) + createCtorFunction(); + log("-- calculateTypes"); + calculateTypes(); + log("-- layoutMemory"); + layoutMemory(); + log("-- calculateExports"); + calculateExports(); + log("-- calculateCustomSections"); + calculateCustomSections(); + log("-- assignSymtab"); + assignSymtab(); if (errorHandler().Verbose) { - log("Defined Functions: " + Twine(NumFunctions)); - log("Defined Globals : " + Twine(DefinedGlobals.size())); - log("Function Imports : " + Twine(FunctionImports.size())); - log("Global Imports : " + Twine(GlobalImports.size())); - log("Total Imports : " + - Twine(FunctionImports.size() + GlobalImports.size())); + log("Defined Functions: " + Twine(InputFunctions.size())); + log("Defined Globals : " + Twine(InputGlobals.size())); + log("Function Imports : " + Twine(NumImportedFunctions)); + log("Global Imports : " + Twine(NumImportedGlobals)); for (ObjFile *File : Symtab->ObjectFiles) File->dumpInfo(); } - log("-- assignSymbolIndexes"); - assignSymbolIndexes(); - log("-- layoutMemory"); - layoutMemory(); - createHeader(); log("-- createSections"); createSections(); @@ -721,7 +1058,6 @@ void Writer::run() { // Open a result file. void Writer::openFile() { log("writing: " + Config->OutputFile); - ::remove(Config->OutputFile.str().c_str()); Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr = FileOutputBuffer::create(Config->OutputFile, FileSize, diff --git a/wasm/WriterUtils.cpp b/wasm/WriterUtils.cpp index 5bdf0d2e3f65..201529edeaa6 100644 --- a/wasm/WriterUtils.cpp +++ b/wasm/WriterUtils.cpp @@ -8,12 +8,9 @@ //===----------------------------------------------------------------------===// #include "WriterUtils.h" - #include "lld/Common/ErrorHandler.h" - #include "llvm/Support/Debug.h" #include "llvm/Support/EndianStream.h" -#include "llvm/Support/FormatVariadic.h" #include "llvm/Support/LEB128.h" #define DEBUG_TYPE "lld" @@ -22,7 +19,7 @@ using namespace llvm; using namespace llvm::wasm; using namespace lld::wasm; -static const char *valueTypeToString(int32_t Type) { +static const char *valueTypeToString(uint8_t Type) { switch (Type) { case WASM_TYPE_I32: return "i32"; @@ -39,61 +36,57 @@ static const char *valueTypeToString(int32_t Type) { namespace lld { -void wasm::debugWrite(uint64_t offset, Twine msg) { - DEBUG(dbgs() << format(" | %08" PRIx64 ": ", offset) << msg << "\n"); +void wasm::debugWrite(uint64_t Offset, const Twine &Msg) { + LLVM_DEBUG(dbgs() << format(" | %08lld: ", Offset) << Msg << "\n"); } -void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg) { - if (msg) - debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number)); +void wasm::writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg) { + debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); encodeULEB128(Number, OS); } -void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const char *msg) { - if (msg) - debugWrite(OS.tell(), msg + formatv(" [{0:x}]", Number)); +void wasm::writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg) { + debugWrite(OS.tell(), Msg + "[" + utohexstr(Number) + "]"); encodeSLEB128(Number, OS); } -void wasm::writeBytes(raw_ostream &OS, const char *bytes, size_t count, - const char *msg) { - if (msg) - debugWrite(OS.tell(), msg + formatv(" [data[{0}]]", count)); - OS.write(bytes, count); +void wasm::writeBytes(raw_ostream &OS, const char *Bytes, size_t Count, + const Twine &Msg) { + debugWrite(OS.tell(), Msg + " [data[" + Twine(Count) + "]]"); + OS.write(Bytes, Count); } -void wasm::writeStr(raw_ostream &OS, const StringRef String, const char *msg) { - if (msg) - debugWrite(OS.tell(), - msg + formatv(" [str[{0}]: {1}]", String.size(), String)); - writeUleb128(OS, String.size(), nullptr); - writeBytes(OS, String.data(), String.size()); +void wasm::writeStr(raw_ostream &OS, StringRef String, const Twine &Msg) { + debugWrite(OS.tell(), + Msg + " [str[" + Twine(String.size()) + "]: " + String + "]"); + encodeULEB128(String.size(), OS); + OS.write(String.data(), String.size()); } -void wasm::writeU8(raw_ostream &OS, uint8_t byte, const char *msg) { - OS << byte; +void wasm::writeU8(raw_ostream &OS, uint8_t Byte, const Twine &Msg) { + debugWrite(OS.tell(), Msg + " [0x" + utohexstr(Byte) + "]"); + OS << Byte; } -void wasm::writeU32(raw_ostream &OS, uint32_t Number, const char *msg) { - debugWrite(OS.tell(), msg + formatv("[{0:x}]", Number)); - support::endian::Writer<support::little>(OS).write(Number); +void wasm::writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg) { + debugWrite(OS.tell(), Msg + "[0x" + utohexstr(Number) + "]"); + support::endian::write(OS, Number, support::little); } -void wasm::writeValueType(raw_ostream &OS, int32_t Type, const char *msg) { - debugWrite(OS.tell(), msg + formatv("[type: {0}]", valueTypeToString(Type))); - writeSleb128(OS, Type, nullptr); +void wasm::writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg) { + writeU8(OS, Type, Msg + "[type: " + valueTypeToString(Type) + "]"); } void wasm::writeSig(raw_ostream &OS, const WasmSignature &Sig) { - writeSleb128(OS, WASM_TYPE_FUNC, "signature type"); - writeUleb128(OS, Sig.ParamTypes.size(), "param count"); - for (int32_t ParamType : Sig.ParamTypes) { + writeU8(OS, WASM_TYPE_FUNC, "signature type"); + writeUleb128(OS, Sig.ParamTypes.size(), "param Count"); + for (uint8_t ParamType : Sig.ParamTypes) { writeValueType(OS, ParamType, "param type"); } if (Sig.ReturnType == WASM_TYPE_NORESULT) { - writeUleb128(OS, 0, "result count"); + writeUleb128(OS, 0, "result Count"); } else { - writeUleb128(OS, 1, "result count"); + writeUleb128(OS, 1, "result Count"); writeValueType(OS, Sig.ReturnType, "result type"); } } @@ -117,18 +110,27 @@ void wasm::writeInitExpr(raw_ostream &OS, const WasmInitExpr &InitExpr) { } void wasm::writeLimits(raw_ostream &OS, const WasmLimits &Limits) { - writeUleb128(OS, Limits.Flags, "limits flags"); + writeU8(OS, Limits.Flags, "limits flags"); writeUleb128(OS, Limits.Initial, "limits initial"); if (Limits.Flags & WASM_LIMITS_FLAG_HAS_MAX) writeUleb128(OS, Limits.Maximum, "limits max"); } +void wasm::writeGlobalType(raw_ostream &OS, const WasmGlobalType &Type) { + writeValueType(OS, Type.Type, "global type"); + writeU8(OS, Type.Mutable, "global mutable"); +} + void wasm::writeGlobal(raw_ostream &OS, const WasmGlobal &Global) { - writeValueType(OS, Global.Type, "global type"); - writeUleb128(OS, Global.Mutable, "global mutable"); + writeGlobalType(OS, Global.Type); writeInitExpr(OS, Global.InitExpr); } +void wasm::writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type) { + writeU8(OS, WASM_TYPE_ANYFUNC, "table type"); + writeLimits(OS, Type.Limits); +} + void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { writeStr(OS, Import.Module, "import module name"); writeStr(OS, Import.Field, "import field name"); @@ -138,12 +140,14 @@ void wasm::writeImport(raw_ostream &OS, const WasmImport &Import) { writeUleb128(OS, Import.SigIndex, "import sig index"); break; case WASM_EXTERNAL_GLOBAL: - writeValueType(OS, Import.Global.Type, "import global type"); - writeUleb128(OS, Import.Global.Mutable, "import global mutable"); + writeGlobalType(OS, Import.Global); break; case WASM_EXTERNAL_MEMORY: writeLimits(OS, Import.Memory); break; + case WASM_EXTERNAL_TABLE: + writeTableType(OS, Import.Table); + break; default: fatal("unsupported import type: " + Twine(Import.Kind)); } @@ -162,27 +166,13 @@ void wasm::writeExport(raw_ostream &OS, const WasmExport &Export) { case WASM_EXTERNAL_MEMORY: writeUleb128(OS, Export.Index, "memory index"); break; - default: - fatal("unsupported export type: " + Twine(Export.Kind)); - } -} - -void wasm::writeReloc(raw_ostream &OS, const OutputRelocation &Reloc) { - writeUleb128(OS, Reloc.Reloc.Type, "reloc type"); - writeUleb128(OS, Reloc.Reloc.Offset, "reloc offset"); - writeUleb128(OS, Reloc.NewIndex, "reloc index"); - - switch (Reloc.Reloc.Type) { - case R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case R_WEBASSEMBLY_MEMORY_ADDR_I32: - writeUleb128(OS, Reloc.Reloc.Addend, "reloc addend"); + case WASM_EXTERNAL_TABLE: + writeUleb128(OS, Export.Index, "table index"); break; default: - break; + fatal("unsupported export type: " + Twine(Export.Kind)); } } - } // namespace lld std::string lld::toString(ValType Type) { @@ -195,6 +185,8 @@ std::string lld::toString(ValType Type) { return "F32"; case ValType::F64: return "F64"; + case ValType::EXCEPT_REF: + return "except_ref"; } llvm_unreachable("Invalid wasm::ValType"); } @@ -213,3 +205,8 @@ std::string lld::toString(const WasmSignature &Sig) { S += toString(static_cast<ValType>(Sig.ReturnType)); return S.str(); } + +std::string lld::toString(const WasmGlobalType &Sig) { + return (Sig.Mutable ? "var " : "const ") + + toString(static_cast<ValType>(Sig.Type)); +} diff --git a/wasm/WriterUtils.h b/wasm/WriterUtils.h index c1ed90793f78..74d727b24b40 100644 --- a/wasm/WriterUtils.h +++ b/wasm/WriterUtils.h @@ -10,49 +10,32 @@ #ifndef LLD_WASM_WRITERUTILS_H #define LLD_WASM_WRITERUTILS_H +#include "lld/Common/LLVM.h" #include "llvm/ADT/Twine.h" #include "llvm/Object/Wasm.h" #include "llvm/Support/raw_ostream.h" using llvm::raw_ostream; -// Needed for WasmSignatureDenseMapInfo -inline bool operator==(const llvm::wasm::WasmSignature &LHS, - const llvm::wasm::WasmSignature &RHS) { - return LHS.ReturnType == RHS.ReturnType && LHS.ParamTypes == RHS.ParamTypes; -} - -inline bool operator!=(const llvm::wasm::WasmSignature &LHS, - const llvm::wasm::WasmSignature &RHS) { - return !(LHS == RHS); -} - namespace lld { namespace wasm { -struct OutputRelocation { - llvm::wasm::WasmRelocation Reloc; - uint32_t NewIndex; - uint32_t Value; -}; - -void debugWrite(uint64_t offset, llvm::Twine msg); +void debugWrite(uint64_t Offset, const Twine &Msg); -void writeUleb128(raw_ostream &OS, uint32_t Number, const char *msg); +void writeUleb128(raw_ostream &OS, uint32_t Number, const Twine &Msg); -void writeSleb128(raw_ostream &OS, int32_t Number, const char *msg); +void writeSleb128(raw_ostream &OS, int32_t Number, const Twine &Msg); -void writeBytes(raw_ostream &OS, const char *bytes, size_t count, - const char *msg = nullptr); +void writeBytes(raw_ostream &OS, const char *Bytes, size_t count, + const Twine &Msg); -void writeStr(raw_ostream &OS, const llvm::StringRef String, - const char *msg = nullptr); +void writeStr(raw_ostream &OS, StringRef String, const Twine &Msg); -void writeU8(raw_ostream &OS, uint8_t byte, const char *msg); +void writeU8(raw_ostream &OS, uint8_t byte, const Twine &Msg); -void writeU32(raw_ostream &OS, uint32_t Number, const char *msg); +void writeU32(raw_ostream &OS, uint32_t Number, const Twine &Msg); -void writeValueType(raw_ostream &OS, int32_t Type, const char *msg); +void writeValueType(raw_ostream &OS, uint8_t Type, const Twine &Msg); void writeSig(raw_ostream &OS, const llvm::wasm::WasmSignature &Sig); @@ -60,18 +43,21 @@ void writeInitExpr(raw_ostream &OS, const llvm::wasm::WasmInitExpr &InitExpr); void writeLimits(raw_ostream &OS, const llvm::wasm::WasmLimits &Limits); +void writeGlobalType(raw_ostream &OS, const llvm::wasm::WasmGlobalType &Type); + void writeGlobal(raw_ostream &OS, const llvm::wasm::WasmGlobal &Global); +void writeTableType(raw_ostream &OS, const llvm::wasm::WasmTable &Type); + void writeImport(raw_ostream &OS, const llvm::wasm::WasmImport &Import); void writeExport(raw_ostream &OS, const llvm::wasm::WasmExport &Export); -void writeReloc(raw_ostream &OS, const OutputRelocation &Reloc); - } // namespace wasm -std::string toString(const llvm::wasm::ValType Type); +std::string toString(llvm::wasm::ValType Type); std::string toString(const llvm::wasm::WasmSignature &Sig); +std::string toString(const llvm::wasm::WasmGlobalType &Sig); } // namespace lld |