diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:26:06 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:26:06 +0000 |
commit | 267829774358b5aebd3e726ae318813bd48129bb (patch) | |
tree | 5a8904da0d9716ea10b69258f5d50e0b1ee2ec2c | |
parent | 0317860f00ca8e821989c92c8a6cc461fd5f2009 (diff) |
Vendor import of lld trunk r307894:vendor/lld/lld-trunk-r307894
Notes
Notes:
svn path=/vendor/lld/dist/; revision=320965
svn path=/vendor/lld/lld-trunk-r307894/; revision=320966; tag=vendor/lld/lld-trunk-r307894
85 files changed, 2668 insertions, 494 deletions
diff --git a/COFF/Chunks.cpp b/COFF/Chunks.cpp index 9b642dcaf137..c0996f55f9d1 100644 --- a/COFF/Chunks.cpp +++ b/COFF/Chunks.cpp @@ -52,6 +52,7 @@ static void add16(uint8_t *P, int16_t V) { write16le(P, read16le(P) + V); } static void add32(uint8_t *P, int32_t V) { write32le(P, read32le(P) + V); } 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); } static void applySecRel(const SectionChunk *Sec, uint8_t *Off, OutputSection *OS, uint64_t S) { @@ -166,6 +167,41 @@ void SectionChunk::applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, } } +static void applyArm64Addr(uint8_t *Off, uint64_t Imm) { + uint32_t ImmLo = (Imm & 0x3) << 29; + uint32_t ImmHi = (Imm & 0x1FFFFC) << 3; + uint64_t Mask = (0x3 << 29) | (0x1FFFFC << 3); + write32le(Off, (read32le(Off) & ~Mask) | ImmLo | ImmHi); +} + +// Update the immediate field in a AARCH64 ldr, str, and add instruction. +static void applyArm64Imm(uint8_t *Off, uint64_t Imm) { + uint32_t Orig = read32le(Off); + Imm += (Orig >> 10) & 0xFFF; + Orig &= ~(0xFFF << 10); + write32le(Off, Orig | ((Imm & 0xFFF) << 10)); +} + +static void applyArm64Ldr(uint8_t *Off, uint64_t Imm) { + int Size = read32le(Off) >> 30; + Imm >>= Size; + applyArm64Imm(Off, Imm); +} + +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 >> 12) - (P >> 12)); break; + case IMAGE_REL_ARM64_PAGEOFFSET_12A: applyArm64Imm(Off, S & 0xfff); 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_ADDR32: add32(Off, S + Config->ImageBase); break; + case IMAGE_REL_ARM64_ADDR64: add64(Off, S + Config->ImageBase); break; + default: + fatal("unsupported relocation type 0x" + Twine::utohexstr(Type)); + } +} + void SectionChunk::writeTo(uint8_t *Buf) const { if (!hasData()) return; @@ -210,6 +246,9 @@ void SectionChunk::writeTo(uint8_t *Buf) const { case ARMNT: applyRelARM(Off, Rel.Type, OS, S, P); break; + case ARM64: + applyRelARM64(Off, Rel.Type, OS, S, P); + break; default: llvm_unreachable("unknown machine type"); } @@ -236,6 +275,10 @@ static uint8_t getBaserelType(const coff_relocation &Rel) { if (Rel.Type == IMAGE_REL_ARM_MOV32T) return IMAGE_REL_BASED_ARM_MOV32T; return IMAGE_REL_BASED_ABSOLUTE; + case ARM64: + if (Rel.Type == IMAGE_REL_ARM64_ADDR64) + return IMAGE_REL_BASED_DIR64; + return IMAGE_REL_BASED_ABSOLUTE; default: llvm_unreachable("unknown machine type"); } @@ -345,6 +388,14 @@ void ImportThunkChunkARM::writeTo(uint8_t *Buf) const { applyMOV32T(Buf + OutputSectionOff, ImpSymbol->getRVA() + Config->ImageBase); } +void ImportThunkChunkARM64::writeTo(uint8_t *Buf) const { + int64_t PageOff = (ImpSymbol->getRVA() >> 12) - (RVA >> 12); + int64_t Off = ImpSymbol->getRVA() & 0xfff; + memcpy(Buf + OutputSectionOff, ImportThunkARM64, sizeof(ImportThunkARM64)); + applyArm64Addr(Buf + OutputSectionOff, PageOff); + applyArm64Ldr(Buf + OutputSectionOff + 4, Off); +} + void LocalImportChunk::getBaserels(std::vector<Baserel> *Res) { Res->emplace_back(getRVA()); } diff --git a/COFF/Chunks.h b/COFF/Chunks.h index 6e1bf94da1a5..fc3f5d0df4b6 100644 --- a/COFF/Chunks.h +++ b/COFF/Chunks.h @@ -151,6 +151,8 @@ public: uint64_t P) const; void applyRelARM(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, uint64_t P) const; + void applyRelARM64(uint8_t *Off, uint16_t Type, OutputSection *OS, uint64_t S, + uint64_t P) const; // Called if the garbage collector decides to not include this chunk // in a final output. It's supposed to print out a log message to stdout. @@ -264,6 +266,12 @@ static const uint8_t ImportThunkARM[] = { 0xdc, 0xf8, 0x00, 0xf0, // ldr.w pc, [ip] }; +static const uint8_t ImportThunkARM64[] = { + 0x10, 0x00, 0x00, 0x90, // adrp x16, #0 + 0x10, 0x02, 0x40, 0xf9, // ldr x16, [x16] + 0x00, 0x02, 0x1f, 0xd6, // br x16 +}; + // Windows-specific. // A chunk for DLL import jump table entry. In a final output, it's // contents will be a JMP instruction to some __imp_ symbol. @@ -299,6 +307,16 @@ private: Defined *ImpSymbol; }; +class ImportThunkChunkARM64 : public Chunk { +public: + explicit ImportThunkChunkARM64(Defined *S) : ImpSymbol(S) {} + size_t getSize() const override { return sizeof(ImportThunkARM64); } + void writeTo(uint8_t *Buf) const override; + +private: + Defined *ImpSymbol; +}; + // Windows-specific. // See comments for DefinedLocalImport class. class LocalImportChunk : public Chunk { diff --git a/COFF/Config.h b/COFF/Config.h index 9fcea96d65d3..25fdc7abd67b 100644 --- a/COFF/Config.h +++ b/COFF/Config.h @@ -31,6 +31,7 @@ class SymbolBody; // Short aliases. static const auto AMD64 = llvm::COFF::IMAGE_FILE_MACHINE_AMD64; +static const auto ARM64 = llvm::COFF::IMAGE_FILE_MACHINE_ARM64; static const auto ARMNT = llvm::COFF::IMAGE_FILE_MACHINE_ARMNT; static const auto I386 = llvm::COFF::IMAGE_FILE_MACHINE_I386; @@ -73,7 +74,7 @@ enum class DebugType { // Global configuration. struct Configuration { enum ManifestKind { SideBySide, Embed, No }; - bool is64() { return Machine == AMD64; } + bool is64() { return Machine == AMD64 || Machine == ARM64; } llvm::COFF::MachineTypes Machine = IMAGE_FILE_MACHINE_UNKNOWN; bool Verbose = false; @@ -91,6 +92,7 @@ struct Configuration { bool WriteSymtab = true; unsigned DebugTypes = static_cast<unsigned>(DebugType::None); llvm::SmallString<128> PDBPath; + std::vector<llvm::StringRef> Argv; // Symbols in this set are considered as live by the garbage collector. std::set<SymbolBody *> GCRoot; diff --git a/COFF/Driver.cpp b/COFF/Driver.cpp index 22efb312ae49..3620297b8b94 100644 --- a/COFF/Driver.cpp +++ b/COFF/Driver.cpp @@ -55,8 +55,8 @@ std::vector<SpecificAllocBase *> SpecificAllocBase::Instances; bool link(ArrayRef<const char *> Args, raw_ostream &Diag) { ErrorCount = 0; ErrorOS = &Diag; - Argv0 = Args[0]; Config = make<Configuration>(); + Config->Argv = {Args.begin(), Args.end()}; Config->ColorDiagnostics = (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); Driver = make<LinkerDriver>(); diff --git a/COFF/DriverUtils.cpp b/COFF/DriverUtils.cpp index d0152b0917b6..39d582469640 100644 --- a/COFF/DriverUtils.cpp +++ b/COFF/DriverUtils.cpp @@ -85,6 +85,7 @@ MachineTypes getMachineType(StringRef S) { .Cases("x64", "amd64", AMD64) .Cases("x86", "i386", I386) .Case("arm", ARMNT) + .Case("arm64", ARM64) .Default(IMAGE_FILE_MACHINE_UNKNOWN); if (MT != IMAGE_FILE_MACHINE_UNKNOWN) return MT; @@ -95,6 +96,8 @@ StringRef machineToStr(MachineTypes MT) { switch (MT) { case ARMNT: return "arm"; + case ARM64: + return "arm64"; case AMD64: return "x64"; case I386: @@ -378,13 +381,11 @@ static std::string createManifestXml() { static std::unique_ptr<MemoryBuffer> 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); + 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); } diff --git a/COFF/Error.cpp b/COFF/Error.cpp index 166b1971e77f..34abc280f6bf 100644 --- a/COFF/Error.cpp +++ b/COFF/Error.cpp @@ -29,7 +29,6 @@ namespace lld { static std::mutex Mu; namespace coff { -StringRef Argv0; uint64_t ErrorCount; raw_ostream *ErrorOS; @@ -45,7 +44,7 @@ static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { } static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Argv0 + ": "; + *ErrorOS << Config->Argv[0] << ": "; if (Config->ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; @@ -58,7 +57,7 @@ static void print(StringRef S, raw_ostream::Colors C) { void log(const Twine &Msg) { if (Config->Verbose) { std::lock_guard<std::mutex> Lock(Mu); - outs() << Argv0 << ": " << Msg << "\n"; + outs() << Config->Argv[0] << ": " << Msg << "\n"; outs().flush(); } } diff --git a/COFF/Error.h b/COFF/Error.h index a4f44fb1e36c..e1e4c1e5216f 100644 --- a/COFF/Error.h +++ b/COFF/Error.h @@ -18,7 +18,6 @@ namespace coff { extern uint64_t ErrorCount; extern llvm::raw_ostream *ErrorOS; -extern llvm::StringRef Argv0; void log(const Twine &Msg); void message(const Twine &Msg); diff --git a/COFF/InputFiles.cpp b/COFF/InputFiles.cpp index c26483e3e368..7d41caebb4b9 100644 --- a/COFF/InputFiles.cpp +++ b/COFF/InputFiles.cpp @@ -380,6 +380,8 @@ MachineTypes BitcodeFile::getMachineType() { return I386; case Triple::arm: return ARMNT; + case Triple::aarch64: + return ARM64; default: return IMAGE_FILE_MACHINE_UNKNOWN; } diff --git a/COFF/PDB.cpp b/COFF/PDB.cpp index c9842cfd1b9a..508f59e3af1f 100644 --- a/COFF/PDB.cpp +++ b/COFF/PDB.cpp @@ -18,19 +18,20 @@ #include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h" #include "llvm/DebugInfo/CodeView/DebugSubsectionVisitor.h" #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h" +#include "llvm/DebugInfo/CodeView/SymbolSerializer.h" #include "llvm/DebugInfo/CodeView/TypeDumpVisitor.h" #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/DebugInfo/CodeView/TypeTableBuilder.h" #include "llvm/DebugInfo/MSF/MSFBuilder.h" #include "llvm/DebugInfo/MSF/MSFCommon.h" +#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/DbiStream.h" #include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/InfoStream.h" #include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBFile.h" #include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h" -#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h" #include "llvm/DebugInfo/PDB/Native/PDBTypeServerHandler.h" #include "llvm/DebugInfo/PDB/Native/TpiStream.h" @@ -124,26 +125,25 @@ static bool remapTypeIndex(TypeIndex &TI, ArrayRef<TypeIndex> TypeIndexMap) { return true; } -static bool remapTypesInSymbolRecord(ObjectFile *File, +static void remapTypesInSymbolRecord(ObjectFile *File, MutableArrayRef<uint8_t> Contents, ArrayRef<TypeIndex> TypeIndexMap, ArrayRef<TiReference> TypeRefs) { for (const TiReference &Ref : TypeRefs) { unsigned ByteSize = Ref.Count * sizeof(TypeIndex); - if (Contents.size() < Ref.Offset + ByteSize) { - log("ignoring short symbol record"); - return false; - } + if (Contents.size() < Ref.Offset + ByteSize) + fatal("symbol record too short"); MutableArrayRef<TypeIndex> TIs( reinterpret_cast<TypeIndex *>(Contents.data() + Ref.Offset), Ref.Count); - for (TypeIndex &TI : TIs) + for (TypeIndex &TI : TIs) { if (!remapTypeIndex(TI, TypeIndexMap)) { + TI = TypeIndex(SimpleTypeKind::NotTranslated); log("ignoring symbol record in " + File->getName() + " with bad type index 0x" + utohexstr(TI.getIndex())); - return false; + continue; } + } } - return true; } /// MSVC translates S_PROC_ID_END to S_END. @@ -176,6 +176,70 @@ static MutableArrayRef<uint8_t> copySymbolForPdb(const CVSymbol &Sym, return NewData; } +/// Return true if this symbol opens a scope. This implies that the symbol has +/// "parent" and "end" fields, which contain the offset of the S_END or +/// S_INLINESITE_END record. +static bool symbolOpensScope(SymbolKind Kind) { + switch (Kind) { + case SymbolKind::S_GPROC32: + case SymbolKind::S_LPROC32: + case SymbolKind::S_LPROC32_ID: + case SymbolKind::S_GPROC32_ID: + case SymbolKind::S_BLOCK32: + case SymbolKind::S_SEPCODE: + case SymbolKind::S_THUNK32: + case SymbolKind::S_INLINESITE: + case SymbolKind::S_INLINESITE2: + return true; + default: + break; + } + return false; +} + +static bool symbolEndsScope(SymbolKind Kind) { + switch (Kind) { + case SymbolKind::S_END: + case SymbolKind::S_PROC_ID_END: + case SymbolKind::S_INLINESITE_END: + return true; + default: + break; + } + return false; +} + +struct ScopeRecord { + ulittle32_t PtrParent; + ulittle32_t PtrEnd; +}; + +struct SymbolScope { + ScopeRecord *OpeningRecord; + uint32_t ScopeOffset; +}; + +static void scopeStackOpen(SmallVectorImpl<SymbolScope> &Stack, + uint32_t CurOffset, CVSymbol &Sym) { + assert(symbolOpensScope(Sym.kind())); + SymbolScope S; + S.ScopeOffset = CurOffset; + S.OpeningRecord = const_cast<ScopeRecord *>( + reinterpret_cast<const ScopeRecord *>(Sym.content().data())); + S.OpeningRecord->PtrParent = Stack.empty() ? 0 : Stack.back().ScopeOffset; + Stack.push_back(S); +} + +static void scopeStackClose(SmallVectorImpl<SymbolScope> &Stack, + uint32_t CurOffset, ObjectFile *File) { + if (Stack.empty()) { + warn("symbol scopes are not balanced in " + File->getName()); + return; + } + SymbolScope S = Stack.pop_back_val(); + S.OpeningRecord->PtrEnd = CurOffset; +} + static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, ArrayRef<TypeIndex> TypeIndexMap, BinaryStreamRef SymData) { @@ -184,6 +248,7 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, CVSymbolArray Syms; BinaryStreamReader Reader(SymData); ExitOnErr(Reader.readArray(Syms, Reader.getLength())); + SmallVector<SymbolScope, 4> Scopes; for (const CVSymbol &Sym : Syms) { // Discover type index references in the record. Skip it if we don't know // where they are. @@ -199,14 +264,17 @@ static void mergeSymbolRecords(BumpPtrAllocator &Alloc, ObjectFile *File, // Re-map all the type index references. MutableArrayRef<uint8_t> Contents = NewData.drop_front(sizeof(RecordPrefix)); - if (!remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs)) - continue; + remapTypesInSymbolRecord(File, Contents, TypeIndexMap, TypeRefs); - // FIXME: Fill in "Parent" and "End" fields by maintaining a stack of - // scopes. + // Fill in "Parent" and "End" fields by maintaining a stack of scopes. + CVSymbol NewSym(Sym.kind(), NewData); + if (symbolOpensScope(Sym.kind())) + scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym); + else if (symbolEndsScope(Sym.kind())) + scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File); // Add the symbol to the module. - File->ModuleDBI->addSymbol(CVSymbol(Sym.kind(), NewData)); + File->ModuleDBI->addSymbol(NewSym); } } @@ -246,7 +314,9 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, bool InArchive = !File->ParentName.empty(); SmallString<128> Path = InArchive ? File->ParentName : File->getName(); sys::fs::make_absolute(Path); + sys::path::native(Path, llvm::sys::path::Style::windows); StringRef Name = InArchive ? File->getName() : StringRef(Path); + File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); @@ -325,9 +395,52 @@ static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, addTypeInfo(Builder.getIpiBuilder(), IDTable); } +static void addLinkerModuleSymbols(StringRef Path, + pdb::DbiModuleDescriptorBuilder &Mod, + BumpPtrAllocator &Allocator) { + codeview::SymbolSerializer Serializer(Allocator, CodeViewContainer::Pdb); + codeview::ObjNameSym ONS(SymbolRecordKind::ObjNameSym); + codeview::Compile3Sym CS(SymbolRecordKind::Compile3Sym); + codeview::EnvBlockSym EBS(SymbolRecordKind::EnvBlockSym); + + ONS.Name = "* Linker *"; + ONS.Signature = 0; + + CS.Machine = Config->is64() ? CPUType::X64 : CPUType::Intel80386; + CS.Flags = CompileSym3Flags::None; + CS.VersionBackendBuild = 0; + CS.VersionBackendMajor = 0; + CS.VersionBackendMinor = 0; + CS.VersionBackendQFE = 0; + CS.VersionFrontendBuild = 0; + CS.VersionFrontendMajor = 0; + CS.VersionFrontendMinor = 0; + CS.VersionFrontendQFE = 0; + CS.Version = "LLVM Linker"; + CS.setLanguage(SourceLanguage::Link); + + ArrayRef<StringRef> Args = makeArrayRef(Config->Argv).drop_front(); + std::string ArgStr = llvm::join(Args, " "); + EBS.Fields.push_back("cwd"); + SmallString<64> cwd; + llvm::sys::fs::current_path(cwd); + EBS.Fields.push_back(cwd); + EBS.Fields.push_back("exe"); + EBS.Fields.push_back(Config->Argv[0]); + EBS.Fields.push_back("pdb"); + EBS.Fields.push_back(Path); + EBS.Fields.push_back("cmd"); + EBS.Fields.push_back(ArgStr); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + ONS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + CS, Allocator, CodeViewContainer::Pdb)); + Mod.addSymbol(codeview::SymbolSerializer::writeOneSymbol( + EBS, Allocator, CodeViewContainer::Pdb)); +} + // Creates a PDB file. -void coff::createPDB(StringRef Path, SymbolTable *Symtab, - ArrayRef<uint8_t> SectionTable, +void coff::createPDB(SymbolTable *Symtab, ArrayRef<uint8_t> SectionTable, const llvm::codeview::DebugInfo *DI) { BumpPtrAllocator Alloc; pdb::PDBFileBuilder Builder(Alloc); @@ -342,22 +455,37 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab, auto &InfoBuilder = Builder.getInfoBuilder(); InfoBuilder.setAge(DI ? DI->PDB70.Age : 0); + llvm::SmallString<128> NativePath(Config->PDBPath.begin(), + Config->PDBPath.end()); + llvm::sys::fs::make_absolute(NativePath); + llvm::sys::path::native(NativePath, llvm::sys::path::Style::windows); + pdb::PDB_UniqueId uuid{}; if (DI) memcpy(&uuid, &DI->PDB70.Signature, sizeof(uuid)); InfoBuilder.setGuid(uuid); - // Should be the current time, but set 0 for reproducibilty. - InfoBuilder.setSignature(0); + InfoBuilder.setSignature(time(nullptr)); InfoBuilder.setVersion(pdb::PdbRaw_ImplVer::PdbImplVC70); - // Add an empty DPI stream. + // Add an empty DBI stream. pdb::DbiStreamBuilder &DbiBuilder = Builder.getDbiBuilder(); - DbiBuilder.setVersionHeader(pdb::PdbDbiV110); + DbiBuilder.setVersionHeader(pdb::PdbDbiV70); + ExitOnErr(DbiBuilder.addDbgStream(pdb::DbgHeaderType::NewFPO, {})); + + // It's not entirely clear what this is, but the * Linker * module uses it. + uint32_t PdbFilePathNI = DbiBuilder.addECName(NativePath); TypeTableBuilder TypeTable(BAlloc); TypeTableBuilder IDTable(BAlloc); addObjectsToPDB(Alloc, Symtab, Builder, TypeTable, IDTable); + // Add public and symbol records stream. + + // For now we don't actually write any thing useful to the publics stream, but + // the act of "getting" it also creates it lazily so that we write an empty + // stream. + (void)Builder.getPublicsBuilder(); + // Add Section Contributions. addSectionContribs(Symtab, DbiBuilder); @@ -369,12 +497,14 @@ void coff::createPDB(StringRef Path, SymbolTable *Symtab, pdb::DbiStreamBuilder::createSectionMap(Sections); DbiBuilder.setSectionMap(SectionMap); - ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); + auto &LinkerModule = ExitOnErr(DbiBuilder.addModuleInfo("* Linker *")); + LinkerModule.setPdbFilePathNI(PdbFilePathNI); + addLinkerModuleSymbols(NativePath, LinkerModule, Alloc); // Add COFF section header stream. ExitOnErr( DbiBuilder.addDbgStream(pdb::DbgHeaderType::SectionHdr, SectionTable)); // Write to a file. - ExitOnErr(Builder.commit(Path)); + ExitOnErr(Builder.commit(Config->PDBPath)); } diff --git a/COFF/PDB.h b/COFF/PDB.h index c9c37914299a..9aaa3178df21 100644 --- a/COFF/PDB.h +++ b/COFF/PDB.h @@ -23,8 +23,7 @@ namespace lld { namespace coff { class SymbolTable; -void createPDB(llvm::StringRef Path, SymbolTable *Symtab, - llvm::ArrayRef<uint8_t> SectionTable, +void createPDB(SymbolTable *Symtab, llvm::ArrayRef<uint8_t> SectionTable, const llvm::codeview::DebugInfo *DI); } } diff --git a/COFF/Symbols.cpp b/COFF/Symbols.cpp index 1cf2934a355b..9b59079072a8 100644 --- a/COFF/Symbols.cpp +++ b/COFF/Symbols.cpp @@ -68,6 +68,8 @@ static Chunk *makeImportThunk(DefinedImportData *S, uint16_t Machine) { return make<ImportThunkChunkX64>(S); if (Machine == I386) return make<ImportThunkChunkX86>(S); + if (Machine == ARM64) + return make<ImportThunkChunkARM64>(S); assert(Machine == ARMNT); return make<ImportThunkChunkARM>(S); } diff --git a/COFF/Writer.cpp b/COFF/Writer.cpp index 4cf718a48d8b..a6a5e278498a 100644 --- a/COFF/Writer.cpp +++ b/COFF/Writer.cpp @@ -239,7 +239,7 @@ void Writer::run() { const llvm::codeview::DebugInfo *DI = nullptr; if (Config->DebugTypes & static_cast<unsigned>(coff::DebugType::CV)) DI = BuildId->DI; - createPDB(Config->PDBPath, Symtab, SectionTable, DI); + createPDB(Symtab, SectionTable, DI); } writeMapFile(OutputSections); diff --git a/ELF/Config.h b/ELF/Config.h index 32e86b0ec7b6..5e3b77637316 100644 --- a/ELF/Config.h +++ b/ELF/Config.h @@ -97,6 +97,7 @@ struct Configuration { llvm::StringRef ThinLTOCacheDir; std::string Rpath; std::vector<VersionDefinition> VersionDefinitions; + std::vector<llvm::StringRef> Argv; std::vector<llvm::StringRef> AuxiliaryList; std::vector<llvm::StringRef> SearchPaths; std::vector<llvm::StringRef> SymbolOrderingFile; diff --git a/ELF/Driver.cpp b/ELF/Driver.cpp index 5fb33caea46f..10ad13f214d5 100644 --- a/ELF/Driver.cpp +++ b/ELF/Driver.cpp @@ -74,13 +74,13 @@ bool elf::link(ArrayRef<const char *> Args, bool CanExitEarly, raw_ostream &Error) { ErrorCount = 0; ErrorOS = &Error; - Argv0 = Args[0]; InputSections.clear(); Tar = nullptr; Config = make<Configuration>(); Driver = make<LinkerDriver>(); Script = make<LinkerScript>(); + Config->Argv = {Args.begin(), Args.end()}; Driver->main(Args, CanExitEarly); freeArena(); diff --git a/ELF/Error.cpp b/ELF/Error.cpp index 7a58668bdcc0..224570ea7424 100644 --- a/ELF/Error.cpp +++ b/ELF/Error.cpp @@ -27,7 +27,6 @@ using namespace lld::elf; uint64_t elf::ErrorCount; raw_ostream *elf::ErrorOS; -StringRef elf::Argv0; // The functions defined in this file can be called from multiple threads, // but outs() or errs() are not thread-safe. We protect them using a mutex. @@ -46,7 +45,7 @@ static void newline(const Twine &Msg) { } static void print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << Argv0 + ": "; + *ErrorOS << Config->Argv[0] << ": "; if (Config->ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; @@ -59,7 +58,7 @@ static void print(StringRef S, raw_ostream::Colors C) { void elf::log(const Twine &Msg) { if (Config->Verbose) { std::lock_guard<std::mutex> Lock(Mu); - outs() << Argv0 << ": " << Msg << "\n"; + outs() << Config->Argv[0] << ": " << Msg << "\n"; outs().flush(); } } diff --git a/ELF/Error.h b/ELF/Error.h index dd6e37c99b15..89bc2111b44e 100644 --- a/ELF/Error.h +++ b/ELF/Error.h @@ -37,7 +37,6 @@ namespace elf { extern uint64_t ErrorCount; extern llvm::raw_ostream *ErrorOS; -extern llvm::StringRef Argv0; void log(const Twine &Msg); void message(const Twine &Msg); diff --git a/ELF/Filesystem.cpp b/ELF/Filesystem.cpp index b63d521a83b0..d468ae0c618a 100644 --- a/ELF/Filesystem.cpp +++ b/ELF/Filesystem.cpp @@ -38,7 +38,8 @@ using namespace lld::elf; // This function spawns a background thread to call unlink. // The calling thread returns almost immediately. void elf::unlinkAsync(StringRef Path) { - if (!Config->Threads || !sys::fs::exists(Config->OutputFile)) + if (!Config->Threads || !sys::fs::exists(Config->OutputFile) || + !sys::fs::is_regular_file(Config->OutputFile)) return; // First, rename Path to avoid race condition. We cannot remove diff --git a/ELF/GdbIndex.h b/ELF/GdbIndex.h index 527667f7280e..c49f8946e199 100644 --- a/ELF/GdbIndex.h +++ b/ELF/GdbIndex.h @@ -45,6 +45,7 @@ struct NameTypeEntry { // debug information performed. That information futher used // for filling gdb index section areas. struct GdbIndexChunk { + InputSection *DebugInfoSec; std::vector<AddressEntry> AddressArea; std::vector<CompilationUnitEntry> CompilationUnits; std::vector<NameTypeEntry> NamesAndTypes; diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp index e07f24d665df..d3c307d5cb6b 100644 --- a/ELF/InputFiles.cpp +++ b/ELF/InputFiles.cpp @@ -45,14 +45,11 @@ namespace { // LLVM DWARF parser will not be able to parse .debug_line correctly, unless // we assign each section some unique address. This callback method assigns // each section an address equal to its offset in ELF object file. -class ObjectInfo : public LoadedObjectInfo { +class ObjectInfo : public LoadedObjectInfoHelper<ObjectInfo> { public: uint64_t getSectionLoadAddress(const object::SectionRef &Sec) const override { return static_cast<const ELFSectionRef &>(Sec).getOffset(); } - std::unique_ptr<LoadedObjectInfo> clone() const override { - return std::unique_ptr<LoadedObjectInfo>(); - } }; } diff --git a/ELF/InputSection.cpp b/ELF/InputSection.cpp index b1d5e1349460..c6a539b8dfa5 100644 --- a/ELF/InputSection.cpp +++ b/ELF/InputSection.cpp @@ -276,7 +276,9 @@ template <class ELFT> std::string InputSectionBase::getSrcMsg(uint64_t Offset) { template <class ELFT> std::string InputSectionBase::getObjMsg(uint64_t Off) { // Synthetic sections don't have input files. elf::ObjectFile<ELFT> *File = getFile<ELFT>(); - std::string Filename = File ? File->getName() : "(internal)"; + if (!File) + return ("(internal):(" + Name + "+0x" + utohexstr(Off) + ")").str(); + std::string Filename = File->getName(); std::string Archive; if (!File->ArchiveName.empty()) @@ -466,7 +468,7 @@ static uint64_t getAArch64UndefinedRelativeWeakVA(uint64_t Type, uint64_t A, static uint64_t getARMStaticBase(const SymbolBody &Body) { OutputSection *OS = Body.getOutputSection(); if (!OS || !OS->FirstInPtLoad) - fatal("SBREL relocation to " + Body.getName() + " without static base\n"); + fatal("SBREL relocation to " + Body.getName() + " without static base"); return OS->FirstInPtLoad->Addr; } diff --git a/ELF/LinkerScript.cpp b/ELF/LinkerScript.cpp index d369a6f978a2..a182d5a3a096 100644 --- a/ELF/LinkerScript.cpp +++ b/ELF/LinkerScript.cpp @@ -111,17 +111,13 @@ LinkerScript::getOrCreateOutputSectionCommand(StringRef Name) { void LinkerScript::setDot(Expr E, const Twine &Loc, bool InSec) { uint64_t Val = E().getValue(); - if (Val < Dot) { - if (InSec) - error(Loc + ": unable to move location counter backward for: " + - CurOutSec->Name); - else - error(Loc + ": unable to move location counter backward"); - } + if (Val < Dot && InSec) + error(Loc + ": unable to move location counter backward for: " + + CurAddressState->OutSec->Name); Dot = Val; // Update to location counter means update to section size. if (InSec) - CurOutSec->Size = Dot - CurOutSec->Addr; + CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; } // Sets value of a symbol. Two kinds of symbols are processed: synthetic @@ -373,7 +369,13 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { // which will map to whatever the first actual section is. Aether = make<OutputSection>("", 0, SHF_ALLOC); Aether->SectionIndex = 1; - CurOutSec = Aether; + auto State = make_unique<AddressState>(Opt); + // CurAddressState captures the local AddressState and makes it accessible + // deliberately. This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + CurAddressState = State.get(); + CurAddressState->OutSec = Aether; Dot = 0; for (size_t I = 0; I < Opt.Commands.size(); ++I) { @@ -435,7 +437,7 @@ void LinkerScript::processCommands(OutputSectionFactory &Factory) { } } } - CurOutSec = nullptr; + CurAddressState = nullptr; } void LinkerScript::fabricateDefaultCommands() { @@ -481,20 +483,31 @@ void LinkerScript::fabricateDefaultCommands() { // Add sections that didn't match any sections command. void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { + unsigned NumCommands = Opt.Commands.size(); for (InputSectionBase *S : InputSections) { if (!S->Live || S->Parent) continue; StringRef Name = getOutputSectionName(S->Name); - auto I = std::find_if( - Opt.Commands.begin(), Opt.Commands.end(), [&](BaseCommand *Base) { - if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) - return Cmd->Name == Name; - return false; - }); - if (I == Opt.Commands.end()) { + auto End = Opt.Commands.begin() + NumCommands; + auto I = std::find_if(Opt.Commands.begin(), End, [&](BaseCommand *Base) { + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + return Cmd->Name == Name; + return false; + }); + OutputSectionCommand *Cmd; + if (I == End) { Factory.addInputSec(S, Name); + OutputSection *Sec = S->getOutputSection(); + assert(Sec->SectionIndex == INT_MAX); + OutputSectionCommand *&CmdRef = SecToCommand[Sec]; + if (!CmdRef) { + CmdRef = createOutputSectionCommand(Sec->Name, "<internal>"); + CmdRef->Sec = Sec; + Opt.Commands.push_back(CmdRef); + } + Cmd = CmdRef; } else { - auto *Cmd = cast<OutputSectionCommand>(*I); + Cmd = cast<OutputSectionCommand>(*I); Factory.addInputSec(S, Name, Cmd->Sec); if (OutputSection *Sec = Cmd->Sec) { SecToCommand[Sec] = Cmd; @@ -502,21 +515,22 @@ void LinkerScript::addOrphanSections(OutputSectionFactory &Factory) { assert(Sec->SectionIndex == INT_MAX || Sec->SectionIndex == Index); Sec->SectionIndex = Index; } - auto *ISD = make<InputSectionDescription>(""); - ISD->Sections.push_back(cast<InputSection>(S)); - Cmd->Commands.push_back(ISD); } + auto *ISD = make<InputSectionDescription>(""); + ISD->Sections.push_back(cast<InputSection>(S)); + Cmd->Commands.push_back(ISD); } } uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { - bool IsTbss = (CurOutSec->Flags & SHF_TLS) && CurOutSec->Type == SHT_NOBITS; - uint64_t Start = IsTbss ? Dot + ThreadBssOffset : Dot; + bool IsTbss = (CurAddressState->OutSec->Flags & SHF_TLS) && + CurAddressState->OutSec->Type == SHT_NOBITS; + uint64_t Start = IsTbss ? Dot + CurAddressState->ThreadBssOffset : Dot; Start = alignTo(Start, Align); uint64_t End = Start + Size; if (IsTbss) - ThreadBssOffset = End - Dot; + CurAddressState->ThreadBssOffset = End - Dot; else Dot = End; return End; @@ -524,40 +538,43 @@ uint64_t LinkerScript::advance(uint64_t Size, unsigned Align) { void LinkerScript::output(InputSection *S) { uint64_t Pos = advance(S->getSize(), S->Alignment); - S->OutSecOff = Pos - S->getSize() - CurOutSec->Addr; + S->OutSecOff = Pos - S->getSize() - CurAddressState->OutSec->Addr; // 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) } - CurOutSec->Size = Pos - CurOutSec->Addr; + CurAddressState->OutSec->Size = Pos - CurAddressState->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 (CurMemRegion) { - CurMemRegion->Offset += CurOutSec->Size; - uint64_t CurSize = CurMemRegion->Offset - CurMemRegion->Origin; - if (CurSize > CurMemRegion->Length) { - uint64_t OverflowAmt = CurSize - CurMemRegion->Length; - error("section '" + CurOutSec->Name + "' will not fit in region '" + - CurMemRegion->Name + "': overflowed by " + Twine(OverflowAmt) + - " bytes"); + if (CurAddressState->MemRegion) { + uint64_t &CurOffset = + CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; + CurOffset += CurAddressState->OutSec->Size; + uint64_t CurSize = CurOffset - CurAddressState->MemRegion->Origin; + if (CurSize > CurAddressState->MemRegion->Length) { + uint64_t OverflowAmt = CurSize - CurAddressState->MemRegion->Length; + error("section '" + CurAddressState->OutSec->Name + + "' will not fit in region '" + CurAddressState->MemRegion->Name + + "': overflowed by " + Twine(OverflowAmt) + " bytes"); } } } void LinkerScript::switchTo(OutputSection *Sec) { - if (CurOutSec == Sec) + if (CurAddressState->OutSec == Sec) return; - CurOutSec = Sec; - CurOutSec->Addr = advance(0, CurOutSec->Alignment); + CurAddressState->OutSec = Sec; + CurAddressState->OutSec->Addr = + advance(0, CurAddressState->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 (LMAOffset) - CurOutSec->LMAOffset = LMAOffset(); + if (CurAddressState->LMAOffset) + CurAddressState->OutSec->LMAOffset = CurAddressState->LMAOffset(); } void LinkerScript::process(BaseCommand &Base) { @@ -569,9 +586,9 @@ void LinkerScript::process(BaseCommand &Base) { // Handle BYTE(), SHORT(), LONG(), or QUAD(). if (auto *Cmd = dyn_cast<BytesDataCommand>(&Base)) { - Cmd->Offset = Dot - CurOutSec->Addr; + Cmd->Offset = Dot - CurAddressState->OutSec->Addr; Dot += Cmd->Size; - CurOutSec->Size = Dot - CurOutSec->Addr; + CurAddressState->OutSec->Size = Dot - CurAddressState->OutSec->Addr; return; } @@ -596,7 +613,7 @@ void LinkerScript::process(BaseCommand &Base) { if (!Sec->Live) continue; - assert(CurOutSec == Sec->getParent()); + assert(CurAddressState->OutSec == Sec->getParent()); output(Sec); } } @@ -649,17 +666,17 @@ void LinkerScript::assignOffsets(OutputSectionCommand *Cmd) { if (Cmd->LMAExpr) { uint64_t D = Dot; - LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; + CurAddressState->LMAOffset = [=] { return Cmd->LMAExpr().getValue() - D; }; } - CurMemRegion = Cmd->MemRegion; - if (CurMemRegion) - Dot = CurMemRegion->Offset; + CurAddressState->MemRegion = Cmd->MemRegion; + if (CurAddressState->MemRegion) + Dot = CurAddressState->MemRegionOffset[CurAddressState->MemRegion]; 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 (CurOutSec->Flags & SHF_COMPRESSED) + if (CurAddressState->OutSec->Flags & SHF_COMPRESSED) return; for (BaseCommand *C : Cmd->Commands) @@ -746,30 +763,20 @@ void LinkerScript::adjustSectionsAfterSorting() { if (!Cmd) continue; - if (Cmd->Phdrs.empty()) - Cmd->Phdrs = DefPhdrs; - else + if (Cmd->Phdrs.empty()) { + OutputSection *Sec = Cmd->Sec; + // To match the bfd linker script behaviour, only propagate program + // headers to sections that are allocated. + if (Sec && (Sec->Flags & SHF_ALLOC)) + Cmd->Phdrs = DefPhdrs; + } else { DefPhdrs = Cmd->Phdrs; + } } removeEmptyCommands(); } -void LinkerScript::createOrphanCommands() { - for (OutputSection *Sec : OutputSections) { - if (Sec->SectionIndex != INT_MAX) - continue; - OutputSectionCommand *Cmd = - createOutputSectionCommand(Sec->Name, "<internal>"); - Cmd->Sec = Sec; - SecToCommand[Sec] = Cmd; - auto *ISD = make<InputSectionDescription>(""); - ISD->Sections = Sec->Sections; - Cmd->Commands.push_back(ISD); - Opt.Commands.push_back(Cmd); - } -} - void LinkerScript::processNonSectionCommands() { for (BaseCommand *Base : Opt.Commands) { if (auto *Cmd = dyn_cast<SymbolAssignment>(Base)) @@ -779,22 +786,25 @@ void LinkerScript::processNonSectionCommands() { } } -static bool -allocateHeaders(std::vector<PhdrEntry> &Phdrs, - ArrayRef<OutputSectionCommand *> OutputSectionCommands, - uint64_t Min) { - auto FirstPTLoad = - std::find_if(Phdrs.begin(), Phdrs.end(), - [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); +void LinkerScript::allocateHeaders(std::vector<PhdrEntry> &Phdrs) { + uint64_t Min = std::numeric_limits<uint64_t>::max(); + for (OutputSectionCommand *Cmd : OutputSectionCommands) { + OutputSection *Sec = Cmd->Sec; + if (Sec->Flags & SHF_ALLOC) + Min = std::min<uint64_t>(Min, Sec->Addr); + } + + auto FirstPTLoad = llvm::find_if( + Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_LOAD; }); if (FirstPTLoad == Phdrs.end()) - return false; + return; uint64_t HeaderSize = getHeaderSize(); if (HeaderSize <= Min || Script->hasPhdrsCommands()) { Min = alignDown(Min - HeaderSize, Config->MaxPageSize); Out::ElfHeader->Addr = Min; Out::ProgramHeaders->Addr = Min + Out::ElfHeader->Size; - return true; + return; } assert(FirstPTLoad->First == Out::ElfHeader); @@ -817,17 +827,28 @@ allocateHeaders(std::vector<PhdrEntry> &Phdrs, Phdrs.erase(FirstPTLoad); } - auto PhdrI = std::find_if(Phdrs.begin(), Phdrs.end(), [](const PhdrEntry &E) { - return E.p_type == PT_PHDR; - }); + auto PhdrI = llvm::find_if( + Phdrs, [](const PhdrEntry &E) { return E.p_type == PT_PHDR; }); if (PhdrI != Phdrs.end()) Phdrs.erase(PhdrI); - return false; } -void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) { +LinkerScript::AddressState::AddressState(const ScriptConfiguration &Opt) { + for (auto &MRI : Opt.MemoryRegions) { + const MemoryRegion *MR = &MRI.second; + MemRegionOffset[MR] = MR->Origin; + } +} + +void LinkerScript::assignAddresses() { // Assign addresses as instructed by linker script SECTIONS sub-commands. Dot = 0; + auto State = make_unique<AddressState>(Opt); + // CurAddressState captures the local AddressState and makes it accessible + // deliberately. This is needed as there are some cases where we cannot just + // thread the current state through to a lambda function created by the + // script parser. + CurAddressState = State.get(); ErrorOnMissingSection = true; switchTo(Aether); @@ -845,15 +866,7 @@ void LinkerScript::assignAddresses(std::vector<PhdrEntry> &Phdrs) { auto *Cmd = cast<OutputSectionCommand>(Base); assignOffsets(Cmd); } - - uint64_t MinVA = std::numeric_limits<uint64_t>::max(); - for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (Sec->Flags & SHF_ALLOC) - MinVA = std::min<uint64_t>(MinVA, Sec->Addr); - } - - allocateHeaders(Phdrs, OutputSectionCommands, MinVA); + CurAddressState = nullptr; } // Creates program headers as instructed by PHDRS linker script command. @@ -879,12 +892,9 @@ std::vector<PhdrEntry> LinkerScript::createPhdrs() { // Add output sections to program headers. for (OutputSectionCommand *Cmd : OutputSectionCommands) { - OutputSection *Sec = Cmd->Sec; - if (!(Sec->Flags & SHF_ALLOC)) - break; - // Assign headers specified by linker script - for (size_t Id : getPhdrIndices(Sec)) { + for (size_t Id : getPhdrIndices(Cmd)) { + OutputSection *Sec = Cmd->Sec; Ret[Id].add(Sec); if (Opt.PhdrsCommands[Id].Flags == UINT_MAX) Ret[Id].p_flags |= Sec->getPhdrFlags(); @@ -911,6 +921,92 @@ OutputSectionCommand *LinkerScript::getCmd(OutputSection *Sec) const { return I->second; } +void OutputSectionCommand::sort(std::function<int(InputSectionBase *S)> Order) { + typedef std::pair<unsigned, InputSection *> Pair; + auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; + + std::vector<Pair> V; + assert(Commands.size() == 1); + auto *ISD = cast<InputSectionDescription>(Commands[0]); + for (InputSection *S : ISD->Sections) + V.push_back({Order(S), S}); + std::stable_sort(V.begin(), V.end(), Comp); + ISD->Sections.clear(); + for (Pair &P : V) + ISD->Sections.push_back(P.second); +} + +// Returns true if S matches /Filename.?\.o$/. +static bool isCrtBeginEnd(StringRef S, StringRef Filename) { + if (!S.endswith(".o")) + return false; + S = S.drop_back(2); + if (S.endswith(Filename)) + return true; + return !S.empty() && S.drop_back().endswith(Filename); +} + +static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } +static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } + +// .ctors and .dtors are sorted by this priority from highest to lowest. +// +// 1. The section was contained in crtbegin (crtbegin contains +// some sentinel value in its .ctors and .dtors so that the runtime +// can find the beginning of the sections.) +// +// 2. The section has an optional priority value in the form of ".ctors.N" +// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, +// they are compared as string rather than number. +// +// 3. The section is just ".ctors" or ".dtors". +// +// 4. The section was contained in crtend, which contains an end marker. +// +// In an ideal world, we don't need this function because .init_array and +// .ctors are duplicate features (and .init_array is newer.) However, there +// are too many real-world use cases of .ctors, so we had no choice to +// support that with this rather ad-hoc semantics. +static bool compCtors(const InputSection *A, const InputSection *B) { + bool BeginA = isCrtbegin(A->File->getName()); + bool BeginB = isCrtbegin(B->File->getName()); + if (BeginA != BeginB) + return BeginA; + bool EndA = isCrtend(A->File->getName()); + bool EndB = isCrtend(B->File->getName()); + if (EndA != EndB) + return EndB; + StringRef X = A->Name; + StringRef Y = B->Name; + assert(X.startswith(".ctors") || X.startswith(".dtors")); + 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; +} + +// Sorts input sections by the special rules for .ctors and .dtors. +// Unfortunately, the rules are different from the one for .{init,fini}_array. +// Read the comment above. +void OutputSectionCommand::sortCtorsDtors() { + assert(Commands.size() == 1); + auto *ISD = cast<InputSectionDescription>(Commands[0]); + std::stable_sort(ISD->Sections.begin(), ISD->Sections.end(), compCtors); +} + +// 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 +// because the compiler keeps the original initialization order in a +// translation unit and we need to respect that. +// For more detail, read the section of the GCC's manual about init_priority. +void OutputSectionCommand::sortInitFini() { + // Sort sections by priority. + sort([](InputSectionBase *S) { return getPriority(S->Name); }); +} + uint32_t OutputSectionCommand::getFiller() { if (Filler) return *Filler; @@ -1085,16 +1181,9 @@ template <class ELFT> void OutputSectionCommand::writeTo(uint8_t *Buf) { writeInt(Buf + Data->Offset, Data->Expression().getValue(), Data->Size); } -bool LinkerScript::hasLMA(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) - if (Cmd->LMAExpr) - return true; - return false; -} - ExprValue LinkerScript::getSymbolValue(const Twine &Loc, StringRef S) { if (S == ".") - return {CurOutSec, Dot - CurOutSec->Addr, Loc}; + return {CurAddressState->OutSec, Dot - CurAddressState->OutSec->Addr, Loc}; if (SymbolBody *B = findSymbol(S)) { if (auto *D = dyn_cast<DefinedRegular>(B)) return {D->Section, D->Value, Loc}; @@ -1111,17 +1200,14 @@ static const size_t NoPhdr = -1; // Returns indices of ELF headers containing specific section. Each index is a // zero based number of ELF header listed within PHDRS {} script block. -std::vector<size_t> LinkerScript::getPhdrIndices(OutputSection *Sec) { - if (OutputSectionCommand *Cmd = getCmd(Sec)) { - std::vector<size_t> Ret; - for (StringRef PhdrName : Cmd->Phdrs) { - size_t Index = getPhdrIndex(Cmd->Location, PhdrName); - if (Index != NoPhdr) - Ret.push_back(Index); - } - return Ret; +std::vector<size_t> LinkerScript::getPhdrIndices(OutputSectionCommand *Cmd) { + std::vector<size_t> Ret; + for (StringRef PhdrName : Cmd->Phdrs) { + size_t Index = getPhdrIndex(Cmd->Location, PhdrName); + if (Index != NoPhdr) + Ret.push_back(Index); } - return {}; + return Ret; } // Returns the index of the segment named PhdrName if found otherwise diff --git a/ELF/LinkerScript.h b/ELF/LinkerScript.h index f8a34a1e97dd..dd5a7d797f60 100644 --- a/ELF/LinkerScript.h +++ b/ELF/LinkerScript.h @@ -110,7 +110,6 @@ struct MemoryRegion { std::string Name; uint64_t Origin; uint64_t Length; - uint64_t Offset; uint32_t Flags; uint32_t NegFlags; }; @@ -140,6 +139,10 @@ struct OutputSectionCommand : BaseCommand { template <class ELFT> void writeTo(uint8_t *Buf); template <class ELFT> void maybeCompress(); uint32_t getFiller(); + + void sort(std::function<int(InputSectionBase *S)> Order); + void sortInitFini(); + void sortCtorsDtors(); }; // This struct represents one section match pattern in SECTIONS() command. @@ -222,6 +225,17 @@ struct ScriptConfiguration { }; class LinkerScript final { + // Temporary state used in processCommands() and assignAddresses() + // that must be reinitialized for each call to the above functions, and must + // not be used outside of the scope of a call to the above functions. + struct AddressState { + uint64_t ThreadBssOffset = 0; + OutputSection *OutSec = nullptr; + MemoryRegion *MemRegion = nullptr; + llvm::DenseMap<const MemoryRegion *, uint64_t> MemRegionOffset; + std::function<uint64_t()> LMAOffset; + AddressState(const ScriptConfiguration &Opt); + }; llvm::DenseMap<OutputSection *, OutputSectionCommand *> SecToCommand; llvm::DenseMap<StringRef, OutputSectionCommand *> NameToOutputSectionCommand; @@ -234,7 +248,7 @@ class LinkerScript final { std::vector<InputSectionBase *> createInputSectionList(OutputSectionCommand &Cmd); - std::vector<size_t> getPhdrIndices(OutputSection *Sec); + std::vector<size_t> getPhdrIndices(OutputSectionCommand *Cmd); size_t getPhdrIndex(const Twine &Loc, StringRef PhdrName); MemoryRegion *findMemoryRegion(OutputSectionCommand *Cmd); @@ -244,14 +258,10 @@ class LinkerScript final { void output(InputSection *Sec); void process(BaseCommand &Base); + AddressState *CurAddressState = nullptr; OutputSection *Aether; uint64_t Dot; - uint64_t ThreadBssOffset = 0; - - std::function<uint64_t()> LMAOffset; - OutputSection *CurOutSec = nullptr; - MemoryRegion *CurMemRegion = nullptr; public: bool ErrorOnMissingSection = false; @@ -276,13 +286,11 @@ public: std::vector<PhdrEntry> createPhdrs(); bool ignoreInterpSection(); - bool hasLMA(OutputSection *Sec); bool shouldKeep(InputSectionBase *S); void assignOffsets(OutputSectionCommand *Cmd); - void createOrphanCommands(); void processNonSectionCommands(); - void assignAddresses(std::vector<PhdrEntry> &Phdrs); - + void assignAddresses(); + void allocateHeaders(std::vector<PhdrEntry> &Phdrs); void addSymbol(SymbolAssignment *Cmd); void processCommands(OutputSectionFactory &Factory); diff --git a/ELF/OutputSections.cpp b/ELF/OutputSections.cpp index c0bf6b32e6e2..d6ae5dcae167 100644 --- a/ELF/OutputSections.cpp +++ b/ELF/OutputSections.cpp @@ -101,100 +101,6 @@ void OutputSection::addSection(InputSection *S) { this->Entsize = std::max(this->Entsize, S->Entsize); } -// This function is called after we sort input sections -// and scan relocations to setup sections' offsets. -void OutputSection::assignOffsets() { - OutputSectionCommand *Cmd = Script->getCmd(this); - uint64_t Off = 0; - for (BaseCommand *Base : Cmd->Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) - for (InputSection *S : ISD->Sections) - Off = updateOffset(Off, S); - this->Size = Off; -} - -void OutputSection::sort(std::function<int(InputSectionBase *S)> Order) { - typedef std::pair<unsigned, InputSection *> Pair; - auto Comp = [](const Pair &A, const Pair &B) { return A.first < B.first; }; - - std::vector<Pair> V; - for (InputSection *S : Sections) - V.push_back({Order(S), S}); - std::stable_sort(V.begin(), V.end(), Comp); - Sections.clear(); - for (Pair &P : V) - Sections.push_back(P.second); -} - -// 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 -// because the compiler keeps the original initialization order in a -// translation unit and we need to respect that. -// For more detail, read the section of the GCC's manual about init_priority. -void OutputSection::sortInitFini() { - // Sort sections by priority. - sort([](InputSectionBase *S) { return getPriority(S->Name); }); -} - -// Returns true if S matches /Filename.?\.o$/. -static bool isCrtBeginEnd(StringRef S, StringRef Filename) { - if (!S.endswith(".o")) - return false; - S = S.drop_back(2); - if (S.endswith(Filename)) - return true; - return !S.empty() && S.drop_back().endswith(Filename); -} - -static bool isCrtbegin(StringRef S) { return isCrtBeginEnd(S, "crtbegin"); } -static bool isCrtend(StringRef S) { return isCrtBeginEnd(S, "crtend"); } - -// .ctors and .dtors are sorted by this priority from highest to lowest. -// -// 1. The section was contained in crtbegin (crtbegin contains -// some sentinel value in its .ctors and .dtors so that the runtime -// can find the beginning of the sections.) -// -// 2. The section has an optional priority value in the form of ".ctors.N" -// or ".dtors.N" where N is a number. Unlike .{init,fini}_array, -// they are compared as string rather than number. -// -// 3. The section is just ".ctors" or ".dtors". -// -// 4. The section was contained in crtend, which contains an end marker. -// -// In an ideal world, we don't need this function because .init_array and -// .ctors are duplicate features (and .init_array is newer.) However, there -// are too many real-world use cases of .ctors, so we had no choice to -// support that with this rather ad-hoc semantics. -static bool compCtors(const InputSection *A, const InputSection *B) { - bool BeginA = isCrtbegin(A->File->getName()); - bool BeginB = isCrtbegin(B->File->getName()); - if (BeginA != BeginB) - return BeginA; - bool EndA = isCrtend(A->File->getName()); - bool EndB = isCrtend(B->File->getName()); - if (EndA != EndB) - return EndB; - StringRef X = A->Name; - StringRef Y = B->Name; - assert(X.startswith(".ctors") || X.startswith(".dtors")); - 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; -} - -// Sorts input sections by the special rules for .ctors and .dtors. -// Unfortunately, the rules are different from the one for .{init,fini}_array. -// Read the comment above. -void OutputSection::sortCtorsDtors() { - std::stable_sort(Sections.begin(), Sections.end(), compCtors); -} - static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { // The ELF spec just says // ---------------------------------------------------------------- @@ -249,9 +155,7 @@ static SectionKey createKey(InputSectionBase *C, StringRef OutsecName) { return SectionKey{OutsecName, Flags, Alignment}; } -OutputSectionFactory::OutputSectionFactory( - std::vector<OutputSection *> &OutputSections) - : OutputSections(OutputSections) {} +OutputSectionFactory::OutputSectionFactory() {} static uint64_t getIncompatibleFlags(uint64_t Flags) { return Flags & (SHF_ALLOC | SHF_TLS); diff --git a/ELF/OutputSections.h b/ELF/OutputSections.h index d5f77838d530..68ee066a13da 100644 --- a/ELF/OutputSections.h +++ b/ELF/OutputSections.h @@ -80,10 +80,6 @@ public: uint32_t ShName = 0; void addSection(InputSection *S); - void sort(std::function<int(InputSectionBase *S)> Order); - void sortInitFini(); - void sortCtorsDtors(); - void assignOffsets(); std::vector<InputSection *> Sections; // Used for implementation of --compress-debug-sections option. @@ -135,7 +131,7 @@ namespace elf { // linker scripts. class OutputSectionFactory { public: - OutputSectionFactory(std::vector<OutputSection *> &OutputSections); + OutputSectionFactory(); ~OutputSectionFactory(); void addInputSec(InputSectionBase *IS, StringRef OutsecName); @@ -144,7 +140,6 @@ public: private: llvm::SmallDenseMap<SectionKey, OutputSection *> Map; - std::vector<OutputSection *> &OutputSections; }; uint64_t getHeaderSize(); diff --git a/ELF/Relocations.cpp b/ELF/Relocations.cpp index fd823fe0ed42..52dbe4b583d0 100644 --- a/ELF/Relocations.cpp +++ b/ELF/Relocations.cpp @@ -557,9 +557,9 @@ static RelExpr adjustExpr(SymbolBody &Body, RelExpr Expr, uint32_t Type, // the refered symbol can be preemepted to refer to the executable. if (Config->Shared || (Config->Pic && !isRelExpr(Expr))) { error("can't create dynamic relocation " + toString(Type) + " against " + - (Body.getName().empty() ? "local symbol in readonly segment" + (Body.getName().empty() ? "local symbol" : "symbol: " + toString(Body)) + - getLocation<ELFT>(S, Body, RelOff)); + " in readonly segment" + getLocation<ELFT>(S, Body, RelOff)); return Expr; } @@ -1049,10 +1049,17 @@ ThunkSection *ThunkCreator::addThunkSection(OutputSection *OS, std::pair<Thunk *, bool> ThunkCreator::getThunk(SymbolBody &Body, uint32_t Type) { - auto res = ThunkedSymbols.insert({&Body, nullptr}); - if (res.second) - res.first->second = addThunk(Type, Body); - return std::make_pair(res.first->second, res.second); + auto Res = ThunkedSymbols.insert({&Body, std::vector<Thunk *>()}); + if (!Res.second) { + // Check existing Thunks for Body to see if they can be reused + for (Thunk *ET : Res.first->second) + if (ET->isCompatibleWith(Type)) + return std::make_pair(ET, false); + } + // No existing compatible Thunk in range, create a new one + Thunk *T = addThunk(Type, Body); + Res.first->second.push_back(T); + return std::make_pair(T, true); } // Call Fn on every executable InputSection accessed via the linker script @@ -1066,13 +1073,12 @@ void ThunkCreator::forEachExecInputSection( OutputSection *OS = Cmd->Sec; if (!(OS->Flags & SHF_ALLOC) || !(OS->Flags & SHF_EXECINSTR)) continue; - if (OutputSectionCommand *C = Script->getCmd(OS)) - for (BaseCommand *BC : C->Commands) - if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { - CurTS = nullptr; - for (InputSection* IS : ISD->Sections) - Fn(OS, &ISD->Sections, IS); - } + for (BaseCommand *BC : Cmd->Commands) + if (auto *ISD = dyn_cast<InputSectionDescription>(BC)) { + CurTS = nullptr; + for (InputSection *IS : ISD->Sections) + Fn(OS, &ISD->Sections, IS); + } } } diff --git a/ELF/Relocations.h b/ELF/Relocations.h index 445308b27cec..fc3e3444ac24 100644 --- a/ELF/Relocations.h +++ b/ELF/Relocations.h @@ -144,14 +144,17 @@ private: std::pair<Thunk *, bool> getThunk(SymbolBody &Body, uint32_t Type); ThunkSection *addThunkSection(OutputSection *OS, std::vector<InputSection *> *, uint64_t Off); - // Track Symbols that already have a Thunk - llvm::DenseMap<SymbolBody *, Thunk *> ThunkedSymbols; + // Record all the available Thunks for a Symbol + llvm::DenseMap<SymbolBody *, std::vector<Thunk *>> ThunkedSymbols; // Find a Thunk from the Thunks symbol definition, we can use this to find // the Thunk from a relocation to the Thunks symbol definition. llvm::DenseMap<SymbolBody *, Thunk *> Thunks; - // Track InputSections that have a ThunkSection placed in front + // Track InputSections that have an inline ThunkSection placed in front + // an inline ThunkSection may have control fall through to the section below + // so we need to make sure that there is only one of them. + // The Mips LA25 Thunk is an example of an inline ThunkSection. llvm::DenseMap<InputSection *, ThunkSection *> ThunkedSections; // All the ThunkSections that we have created, organised by OutputSection diff --git a/ELF/ScriptParser.cpp b/ELF/ScriptParser.cpp index 4a44944fe7ed..72940ca0cfd4 100644 --- a/ELF/ScriptParser.cpp +++ b/ELF/ScriptParser.cpp @@ -1191,8 +1191,7 @@ void ScriptParser::readMemory() { if (It != Script->Opt.MemoryRegions.end()) setError("region '" + Name + "' already defined"); else - Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, - Origin, Flags, NegFlags}; + Script->Opt.MemoryRegions[Name] = {Name, Origin, Length, Flags, NegFlags}; } } diff --git a/ELF/SymbolTable.cpp b/ELF/SymbolTable.cpp index d75b89f17527..c802d74b8ff8 100644 --- a/ELF/SymbolTable.cpp +++ b/ELF/SymbolTable.cpp @@ -211,6 +211,13 @@ static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) { // Find an existing symbol or create and insert a new one. template <class ELFT> std::pair<Symbol *, bool> SymbolTable<ELFT>::insert(StringRef Name) { + // <name>@@<version> means the symbol is the default version. In that + // case symbol <name> must exist and <name>@@<version> will be used to + // resolve references to <name>. + size_t Pos = Name.find("@@"); + if (Pos != StringRef::npos) + Name = Name.take_front(Pos); + auto P = Symtab.insert( {CachedHashStringRef(Name), SymIndex((int)SymVector.size(), false)}); SymIndex &V = P.first->second; @@ -319,7 +326,7 @@ static int compareDefined(Symbol *S, bool WasInserted, uint8_t Binding) { if (WasInserted) return 1; SymbolBody *Body = S->body(); - if (Body->isLazy() || !Body->isInCurrentDSO()) + if (!Body->isInCurrentDSO()) return 1; if (Binding == STB_WEAK) return -1; @@ -689,6 +696,12 @@ void SymbolTable<ELFT>::assignExactVersion(SymbolVersion Ver, uint16_t VersionId // Assign the version. for (SymbolBody *B : Syms) { + // Skip symbols containing version info because symbol versions + // specified by symbol names take precedence over version scripts. + // See parseSymbolVersion(). + if (B->getName().find('@') != StringRef::npos) + continue; + Symbol *Sym = B->symbol(); if (Sym->InVersionScript) warn("duplicate symbol '" + Ver.Name + "' in version script"); @@ -702,47 +715,21 @@ void SymbolTable<ELFT>::assignWildcardVersion(SymbolVersion Ver, uint16_t VersionId) { if (!Ver.HasWildcard) return; - std::vector<SymbolBody *> Syms = findAllByVersion(Ver); // Exact matching takes precendence over fuzzy matching, // so we set a version to a symbol only if no version has been assigned // to the symbol. This behavior is compatible with GNU. - for (SymbolBody *B : Syms) + for (SymbolBody *B : findAllByVersion(Ver)) if (B->symbol()->VersionId == Config->DefaultSymbolVersion) B->symbol()->VersionId = VersionId; } -static bool isDefaultVersion(SymbolBody *B) { - return B->isInCurrentDSO() && B->getName().find("@@") != StringRef::npos; -} - // This function processes version scripts by updating VersionId // member of symbols. template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { - // Symbol themselves might know their versions because symbols - // can contain versions in the form of <name>@<version>. - // Let them parse and update their names to exclude version suffix. - for (Symbol *Sym : SymVector) { - SymbolBody *Body = Sym->body(); - bool IsDefault = isDefaultVersion(Body); - Body->parseSymbolVersion(); - - if (!IsDefault) - continue; - - // <name>@@<version> means the symbol is the default version. If that's the - // case, the symbol is not used only to resolve <name> of version <version> - // but also undefined unversioned symbols with name <name>. - SymbolBody *S = find(Body->getName()); - if (S && S->isUndefined()) - S->copy(Body); - } - // Handle edge cases first. handleAnonymousVersion(); - if (Config->VersionDefinitions.empty()) - return; // Now we have version definitions, so we need to set version ids to symbols. // Each version definition has a glob pattern, and all symbols that match @@ -761,6 +748,12 @@ template <class ELFT> void SymbolTable<ELFT>::scanVersionScript() { for (VersionDefinition &V : llvm::reverse(Config->VersionDefinitions)) for (SymbolVersion &Ver : V.Globals) assignWildcardVersion(Ver, V.Id); + + // Symbol themselves might know their versions because symbols + // can contain versions in the form of <name>@<version>. + // Let them parse and update their names to exclude version suffix. + for (Symbol *Sym : SymVector) + Sym->body()->parseSymbolVersion(); } template class elf::SymbolTable<ELF32LE>; diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp index e8cd662c69ac..1d17f57f0c30 100644 --- a/ELF/Symbols.cpp +++ b/ELF/Symbols.cpp @@ -159,19 +159,12 @@ bool SymbolBody::isPreemptible() const { return true; } -// Overwrites all attributes except symbol name with Other's so that -// this symbol becomes an alias to Other. This is useful for handling -// some options such as --wrap. -// -// The reason why we want to keep the symbol name is because, if we -// copy symbol names, we'll end up having symbol tables in resulting -// executables or DSOs containing two or more identical symbols, which -// is just inconvenient. +// Overwrites all attributes with Other's so that this symbol becomes +// an alias to Other. This is useful for handling some options such as +// --wrap. void SymbolBody::copy(SymbolBody *Other) { - StringRef S = Name; memcpy(symbol()->Body.buffer, Other->symbol()->Body.buffer, sizeof(Symbol::Body)); - Name = S; } uint64_t SymbolBody::getVA(int64_t Addend) const { @@ -272,7 +265,12 @@ void SymbolBody::parseSymbolVersion() { } // It is an error if the specified version is not defined. - error(toString(File) + ": symbol " + S + " has undefined version " + Verstr); + // 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) + error(toString(File) + ": symbol " + S + " has undefined version " + + Verstr); } Defined::Defined(Kind K, StringRefZ Name, bool IsLocal, uint8_t StOther, diff --git a/ELF/Symbols.h b/ELF/Symbols.h index 773e1ad9588a..a1b3a6fba911 100644 --- a/ELF/Symbols.h +++ b/ELF/Symbols.h @@ -65,7 +65,9 @@ public: return SymbolKind == LazyArchiveKind || SymbolKind == LazyObjectKind; } bool isShared() const { return SymbolKind == SharedKind; } - bool isInCurrentDSO() const { return !isUndefined() && !isShared(); } + bool isInCurrentDSO() const { + return !isUndefined() && !isShared() && !isLazy(); + } bool isLocal() const { return IsLocal; } bool isPreemptible() const; StringRef getName() const { return Name; } @@ -218,7 +220,7 @@ public: Verdef(Verdef), ElfSym(ElfSym) { // IFuncs defined in DSOs are treated as functions by the static linker. if (isGnuIFunc()) - Type = llvm::ELF::STT_FUNC; + this->Type = llvm::ELF::STT_FUNC; this->File = File; } diff --git a/ELF/SyntheticSections.cpp b/ELF/SyntheticSections.cpp index 995d05692ee2..fd724fac327c 100644 --- a/ELF/SyntheticSections.cpp +++ b/ELF/SyntheticSections.cpp @@ -1071,10 +1071,11 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { return; // Already finalized. this->Link = InX::DynStrTab->getParent()->SectionIndex; - if (In<ELFT>::RelaDyn->getParent()->Size > 0) { + if (In<ELFT>::RelaDyn->getParent() && !In<ELFT>::RelaDyn->empty()) { bool IsRela = Config->IsRela; add({IsRela ? DT_RELA : DT_REL, In<ELFT>::RelaDyn}); - add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent()->Size}); + add({IsRela ? DT_RELASZ : DT_RELSZ, In<ELFT>::RelaDyn->getParent(), + Entry::SecSize}); add({IsRela ? DT_RELAENT : DT_RELENT, uint64_t(IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel))}); @@ -1087,9 +1088,9 @@ template <class ELFT> void DynamicSection<ELFT>::finalizeContents() { add({IsRela ? DT_RELACOUNT : DT_RELCOUNT, NumRelativeRels}); } } - if (In<ELFT>::RelaPlt->getParent()->Size > 0) { + if (In<ELFT>::RelaPlt->getParent() && !In<ELFT>::RelaPlt->empty()) { add({DT_JMPREL, In<ELFT>::RelaPlt}); - add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent()->Size}); + add({DT_PLTRELSZ, In<ELFT>::RelaPlt->getParent(), Entry::SecSize}); switch (Config->EMachine) { case EM_MIPS: add({DT_MIPS_PLTGOT, In<ELFT>::GotPlt}); @@ -1699,9 +1700,9 @@ unsigned PltSection::getPltRelocOff() const { return (HeaderSize == 0) ? InX::Plt->getSize() : 0; } -GdbIndexSection::GdbIndexSection() +GdbIndexSection::GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks) : SyntheticSection(0, SHT_PROGBITS, 1, ".gdb_index"), - StringPool(llvm::StringTableBuilder::ELF) {} + StringPool(llvm::StringTableBuilder::ELF), Chunks(std::move(Chunks)) {} // Iterative hash function for symbol's name is described in .gdb_index format // specification. Note that we use one for version 5 to 7 here, it is different @@ -1713,11 +1714,10 @@ static uint32_t hash(StringRef Str) { return R; } -static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf, - InputSection *Sec) { +static std::vector<CompilationUnitEntry> readCuList(DWARFContext &Dwarf) { std::vector<CompilationUnitEntry> Ret; for (std::unique_ptr<DWARFCompileUnit> &CU : Dwarf.compile_units()) - Ret.push_back({Sec->OutSecOff + CU->getOffset(), CU->getLength() + 4}); + Ret.push_back({CU->getOffset(), CU->getLength() + 4}); return Ret; } @@ -1764,19 +1764,15 @@ static std::vector<InputSection *> getDebugInfoSections() { std::vector<InputSection *> Ret; for (InputSectionBase *S : InputSections) if (InputSection *IS = dyn_cast<InputSection>(S)) - if (IS->getParent() && IS->Name == ".debug_info") + if (IS->Name == ".debug_info") Ret.push_back(IS); return Ret; } void GdbIndexSection::buildIndex() { - std::vector<InputSection *> V = getDebugInfoSections(); - if (V.empty()) + if (Chunks.empty()) return; - for (InputSection *Sec : V) - Chunks.push_back(readDwarf(Sec)); - uint32_t CuId = 0; for (GdbIndexChunk &D : Chunks) { for (AddressEntry &E : D.AddressArea) @@ -1802,23 +1798,33 @@ void GdbIndexSection::buildIndex() { } } -GdbIndexChunk GdbIndexSection::readDwarf(InputSection *Sec) { - Expected<std::unique_ptr<object::ObjectFile>> Obj = - object::ObjectFile::createObjectFile(Sec->File->MB); - if (!Obj) { - error(toString(Sec->File) + ": error creating DWARF context"); - return {}; - } - - DWARFContextInMemory Dwarf(*Obj.get()); - +static GdbIndexChunk readDwarf(DWARFContextInMemory &Dwarf, InputSection *Sec) { GdbIndexChunk Ret; - Ret.CompilationUnits = readCuList(Dwarf, Sec); + Ret.DebugInfoSec = Sec; + Ret.CompilationUnits = readCuList(Dwarf); Ret.AddressArea = readAddressArea(Dwarf, Sec); Ret.NamesAndTypes = readPubNamesAndTypes(Dwarf, Config->IsLE); return Ret; } +template <class ELFT> GdbIndexSection *elf::createGdbIndex() { + std::vector<GdbIndexChunk> Chunks; + for (InputSection *Sec : getDebugInfoSections()) { + InputFile *F = Sec->File; + std::error_code EC; + ELFObjectFile<ELFT> Obj(F->MB, EC); + if (EC) + fatal(EC.message()); + DWARFContextInMemory Dwarf(Obj, nullptr, [&](Error E) { + error(toString(F) + ": error parsing DWARF data:\n>>> " + + toString(std::move(E))); + return ErrorPolicy::Continue; + }); + Chunks.push_back(readDwarf(Dwarf, Sec)); + } + return make<GdbIndexSection>(std::move(Chunks)); +} + static size_t getCuSize(std::vector<GdbIndexChunk> &C) { size_t Ret = 0; for (GdbIndexChunk &D : C) @@ -1876,7 +1882,7 @@ void GdbIndexSection::writeTo(uint8_t *Buf) { // Write the CU list. for (GdbIndexChunk &D : Chunks) { for (CompilationUnitEntry &Cu : D.CompilationUnits) { - write64le(Buf, Cu.CuOffset); + write64le(Buf, D.DebugInfoSec->OutSecOff + Cu.CuOffset); write64le(Buf + 8, Cu.CuLength); Buf += 16; } @@ -2345,6 +2351,11 @@ 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 void PltSection::addEntry<ELF32LE>(SymbolBody &Sym); template void PltSection::addEntry<ELF32BE>(SymbolBody &Sym); template void PltSection::addEntry<ELF64LE>(SymbolBody &Sym); diff --git a/ELF/SyntheticSections.h b/ELF/SyntheticSections.h index be9a43c8155b..ddd8ca99a61b 100644 --- a/ELF/SyntheticSections.h +++ b/ELF/SyntheticSections.h @@ -503,7 +503,7 @@ class GdbIndexSection final : public SyntheticSection { const unsigned SymTabEntrySize = 2 * OffsetTypeSize; public: - GdbIndexSection(); + GdbIndexSection(std::vector<GdbIndexChunk> &&Chunks); void finalizeContents() override; void writeTo(uint8_t *Buf) override; size_t getSize() const override; @@ -524,7 +524,6 @@ public: std::vector<GdbIndexChunk> Chunks; private: - GdbIndexChunk readDwarf(InputSection *Sec); void buildIndex(); uint32_t CuTypesOffset; @@ -538,6 +537,8 @@ private: bool Finalized = false; }; +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. diff --git a/ELF/Thunks.cpp b/ELF/Thunks.cpp index 752a881d7867..cae31027e557 100644 --- a/ELF/Thunks.cpp +++ b/ELF/Thunks.cpp @@ -57,6 +57,7 @@ public: uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ARMV7PILongThunk final : public Thunk { @@ -66,28 +67,31 @@ public: uint32_t size() const override { return 16; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ThumbV7ABSLongThunk final : public Thunk { public: ThumbV7ABSLongThunk(const SymbolBody &Dest) : Thunk(Dest) { - this->alignment = 2; + alignment = 2; } uint32_t size() const override { return 10; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; class ThumbV7PILongThunk final : public Thunk { public: ThumbV7PILongThunk(const SymbolBody &Dest) : Thunk(Dest) { - this->alignment = 2; + alignment = 2; } uint32_t size() const override { return 12; } void writeTo(uint8_t *Buf, ThunkSection &IS) const override; void addSymbols(ThunkSection &IS) override; + bool isCompatibleWith(uint32_t RelocType) const override; }; // MIPS LA25 thunk @@ -128,6 +132,11 @@ void ARMV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + void ThumbV7ABSLongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x40, 0xf2, 0x00, 0x0c, // movw ip, :lower16:S @@ -147,6 +156,12 @@ void ThumbV7ABSLongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7ABSLongThunk::isCompatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + void ARMV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0xf0, 0xcf, 0x0f, 0xe3, // P: movw ip,:lower16:S - (P + (L1-P) +8) @@ -168,6 +183,11 @@ void ARMV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$a", STT_NOTYPE, Offset, 0, &IS); } +bool ARMV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // Thumb branch relocations can't use BLX + return RelocType != R_ARM_THM_JUMP19 && RelocType != R_ARM_THM_JUMP24; +} + void ThumbV7PILongThunk::writeTo(uint8_t *Buf, ThunkSection &IS) const { const uint8_t Data[] = { 0x4f, 0xf6, 0xf4, 0x7c, // P: movw ip,:lower16:S - (P + (L1-P) + 4) @@ -189,9 +209,15 @@ void ThumbV7PILongThunk::addSymbols(ThunkSection &IS) { addSyntheticLocal("$t", STT_NOTYPE, Offset, 0, &IS); } +bool ThumbV7PILongThunk::isCompatibleWith(uint32_t RelocType) const { + // ARM branch relocations can't use BLX + return RelocType != R_ARM_JUMP24 && RelocType != R_ARM_PC24 && + RelocType != R_ARM_PLT32; +} + // Write MIPS LA25 thunk code to call PIC function from the non-PIC one. void MipsThunk::writeTo(uint8_t *Buf, ThunkSection &) const { - uint64_t S = this->Destination.getVA(); + 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) diff --git a/ELF/Thunks.h b/ELF/Thunks.h index 38ee090e75e1..00b6b2cf2994 100644 --- a/ELF/Thunks.h +++ b/ELF/Thunks.h @@ -41,6 +41,10 @@ public: // a branch and fall through to the first Symbol in the Target. virtual InputSection *getTargetInputSection() const { return nullptr; } + // To reuse a Thunk the caller as identified by the RelocType must be + // compatible with it. + virtual bool isCompatibleWith(uint32_t RelocType) const { return true; } + // The alignment requirement for this Thunk, defaults to the size of the // typical code section alignment. const SymbolBody &Destination; diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp index 080d8e787301..bf43ee5c5f91 100644 --- a/ELF/Writer.cpp +++ b/ELF/Writer.cpp @@ -73,13 +73,12 @@ private: std::unique_ptr<FileOutputBuffer> Buffer; - OutputSectionFactory Factory{OutputSections}; + OutputSectionFactory Factory; void addRelIpltSymbols(); void addStartEndSymbols(); void addStartStopSymbols(OutputSection *Sec); uint64_t getEntryAddr(); - OutputSection *findSection(StringRef Name); OutputSection *findSectionInScript(StringRef Name); OutputSectionCommand *findSectionCommand(StringRef Name); @@ -152,10 +151,6 @@ template <class ELFT> static void combineEhFrameSections() { } template <class ELFT> void Writer<ELFT>::clearOutputSections() { - if (Script->Opt.HasSections) - Script->createOrphanCommands(); - else - Script->fabricateDefaultCommands(); // Clear the OutputSections to make sure it is not used anymore. Any // code from this point on should be using the linker script // commands. @@ -190,9 +185,10 @@ template <class ELFT> void Writer<ELFT>::run() { // output sections by default rules. We still need to give the // linker script a chance to run, because it might contain // non-SECTIONS commands such as ASSERT. - createSections(); Script->processCommands(Factory); + createSections(); } + clearOutputSections(); if (Config->Discard != DiscardPolicy::All) copyLocalSymbols(); @@ -218,7 +214,8 @@ template <class ELFT> void Writer<ELFT>::run() { OutputSectionCommands.begin(), OutputSectionCommands.end(), [](OutputSectionCommand *Cmd) { Cmd->maybeCompress<ELFT>(); }); - Script->assignAddresses(Phdrs); + Script->assignAddresses(); + Script->allocateHeaders(Phdrs); // Remove empty PT_LOAD to avoid causing the dynamic linker to try to mmap a // 0 sized region. This has to be done late since only after assignAddresses @@ -383,7 +380,7 @@ template <class ELFT> void Writer<ELFT>::createSyntheticSections() { Add(InX::IgotPlt); if (Config->GdbIndex) { - InX::GdbIndex = make<GdbIndexSection>(); + InX::GdbIndex = createGdbIndex<ELFT>(); Add(InX::GdbIndex); } @@ -499,11 +496,18 @@ template <class ELFT> void Writer<ELFT>::copyLocalSymbols() { template <class ELFT> void Writer<ELFT>::addSectionSymbols() { // Create one STT_SECTION symbol for each output section we might // have a relocation with. - for (OutputSection *Sec : OutputSections) { - if (Sec->Sections.empty()) + for (BaseCommand *Base : Script->Opt.Commands) { + auto *Cmd = dyn_cast<OutputSectionCommand>(Base); + if (!Cmd) continue; - - InputSection *IS = Sec->Sections[0]; + auto I = llvm::find_if(Cmd->Commands, [](BaseCommand *Base) { + if (auto *ISD = dyn_cast<InputSectionDescription>(Base)) + return !ISD->Sections.empty(); + return false; + }); + if (I == Cmd->Commands.end()) + continue; + InputSection *IS = cast<InputSectionDescription>(*I)->Sections[0]; if (isa<SyntheticSection>(IS) || IS->Type == SHT_REL || IS->Type == SHT_RELA) continue; @@ -864,20 +868,19 @@ template <class ELFT> void Writer<ELFT>::addReservedSymbols() { // Sort input sections by section name suffixes for // __attribute__((init_priority(N))). -static void sortInitFini(OutputSection *S) { - if (S) - reinterpret_cast<OutputSection *>(S)->sortInitFini(); +static void sortInitFini(OutputSectionCommand *Cmd) { + if (Cmd) + Cmd->sortInitFini(); } // Sort input sections by the special rule for .ctors and .dtors. -static void sortCtorsDtors(OutputSection *S) { - if (S) - reinterpret_cast<OutputSection *>(S)->sortCtorsDtors(); +static void sortCtorsDtors(OutputSectionCommand *Cmd) { + if (Cmd) + Cmd->sortCtorsDtors(); } // Sort input sections using the list provided by --symbol-ordering-file. -template <class ELFT> -static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) { +template <class ELFT> static void sortBySymbolsOrder() { if (Config->SymbolOrderingFile.empty()) return; @@ -902,9 +905,9 @@ static void sortBySymbolsOrder(ArrayRef<OutputSection *> OutputSections) { } // Sort sections by priority. - for (OutputSection *Base : OutputSections) - if (auto *Sec = dyn_cast<OutputSection>(Base)) - Sec->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + Cmd->sort([&](InputSectionBase *S) { return SectionOrder.lookup(S); }); } template <class ELFT> @@ -934,11 +937,12 @@ template <class ELFT> void Writer<ELFT>::createSections() { if (IS) Factory.addInputSec(IS, getOutputSectionName(IS->Name)); - sortBySymbolsOrder<ELFT>(OutputSections); - sortInitFini(findSection(".init_array")); - sortInitFini(findSection(".fini_array")); - sortCtorsDtors(findSection(".ctors")); - sortCtorsDtors(findSection(".dtors")); + Script->fabricateDefaultCommands(); + sortBySymbolsOrder<ELFT>(); + sortInitFini(findSectionCommand(".init_array")); + sortInitFini(findSectionCommand(".fini_array")); + sortCtorsDtors(findSectionCommand(".ctors")); + sortCtorsDtors(findSectionCommand(".dtors")); } // We want to find how similar two ranks are. @@ -1132,7 +1136,7 @@ static void applySynthetic(const std::vector<SyntheticSection *> &Sections, // to make them visible from linkescript side. But not all sections are always // required to be in output. For example we don't need dynamic section content // sometimes. This function filters out such unused sections from the output. -static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) { +static void removeUnusedSyntheticSections() { // All input synthetic sections that can be empty are placed after // all regular ones. We iterate over them all and exit at first // non-synthetic. @@ -1145,29 +1149,53 @@ static void removeUnusedSyntheticSections(std::vector<OutputSection *> &V) { continue; if ((SS == InX::Got || SS == InX::MipsGot) && ElfSym::GlobalOffsetTable) continue; - OS->Sections.erase(std::find(OS->Sections.begin(), OS->Sections.end(), SS)); - SS->Live = false; + + OutputSectionCommand *Cmd = Script->getCmd(OS); + std::vector<BaseCommand *>::iterator Empty = Cmd->Commands.end(); + for (auto I = Cmd->Commands.begin(), E = Cmd->Commands.end(); I != E; ++I) { + BaseCommand *B = *I; + if (auto *ISD = dyn_cast<InputSectionDescription>(B)) { + auto P = std::find(ISD->Sections.begin(), ISD->Sections.end(), SS); + if (P != ISD->Sections.end()) + ISD->Sections.erase(P); + if (ISD->Sections.empty()) + Empty = I; + } + } + if (Empty != Cmd->Commands.end()) + Cmd->Commands.erase(Empty); + // If there are no other sections in the output section, remove it from the // output. - if (OS->Sections.empty()) - V.erase(std::find(V.begin(), V.end(), OS)); + if (Cmd->Commands.empty()) { + // Also remove script commands matching the output section. + auto &Cmds = Script->Opt.Commands; + auto I = std::remove_if(Cmds.begin(), Cmds.end(), [&](BaseCommand *Cmd) { + if (auto *OSCmd = dyn_cast<OutputSectionCommand>(Cmd)) + return OSCmd->Sec == OS; + return false; + }); + Cmds.erase(I, Cmds.end()); + } } } // Create output section objects and add them to OutputSections. template <class ELFT> void Writer<ELFT>::finalizeSections() { - Out::DebugInfo = findSection(".debug_info"); - Out::PreinitArray = findSection(".preinit_array"); - Out::InitArray = findSection(".init_array"); - Out::FiniArray = findSection(".fini_array"); + Out::DebugInfo = findSectionInScript(".debug_info"); + Out::PreinitArray = findSectionInScript(".preinit_array"); + Out::InitArray = findSectionInScript(".init_array"); + Out::FiniArray = findSectionInScript(".fini_array"); // The linker needs to define SECNAME_start, SECNAME_end and SECNAME_stop // symbols for sections, so that the runtime can get the start and end // addresses of each section by section name. Add such symbols. if (!Config->Relocatable) { addStartEndSymbols(); - for (OutputSection *Sec : OutputSections) - addStartStopSymbols(Sec); + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + if (Cmd->Sec) + addStartStopSymbols(Cmd->Sec); } // Add _DYNAMIC symbol. Unlike GNU gold, our _DYNAMIC symbol has no type. @@ -1218,9 +1246,8 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { return; addPredefinedSections(); - removeUnusedSyntheticSections(OutputSections); + removeUnusedSyntheticSections(); - clearOutputSections(); sortSections(); // Now that we have the final list, create a list of all the @@ -1257,12 +1284,6 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { Out::ProgramHeaders->Size = sizeof(Elf_Phdr) * Phdrs.size(); } - // Compute the size of .rela.dyn and .rela.plt early since we need - // them to populate .dynamic. - for (SyntheticSection *SS : {In<ELFT>::RelaDyn, In<ELFT>::RelaPlt}) - if (SS->getParent() && !SS->empty()) - SS->getParent()->assignOffsets(); - // 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, @@ -1286,6 +1307,7 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { // are out of range. This will need to turn into a loop that converges // when no more Thunks are added ThunkCreator TC; + Script->assignAddresses(); if (TC.createThunks(OutputSectionCommands)) { applySynthetic({InX::MipsGot}, [](SyntheticSection *SS) { SS->updateAllocSize(); }); @@ -1308,21 +1330,18 @@ template <class ELFT> void Writer<ELFT>::finalizeSections() { template <class ELFT> void Writer<ELFT>::addPredefinedSections() { // ARM ABI requires .ARM.exidx to be terminated by some piece of data. // We have the terminater synthetic section class. Add that at the end. - auto *OS = dyn_cast_or_null<OutputSection>(findSection(".ARM.exidx")); - if (!OS || OS->Sections.empty() || Config->Relocatable) + OutputSectionCommand *Cmd = findSectionCommand(".ARM.exidx"); + if (!Cmd || Cmd->Commands.empty() || Config->Relocatable) return; auto *Sentinel = make<ARMExidxSentinelSection>(); - OS->addSection(Sentinel); - // If there are linker script commands existing at this point then add the - // sentinel to the last of these too. - if (OutputSectionCommand *C = Script->getCmd(OS)) { - auto ISD = std::find_if(C->Commands.rbegin(), C->Commands.rend(), - [](const BaseCommand *Base) { - return isa<InputSectionDescription>(Base); - }); - cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel); - } + Cmd->Sec->addSection(Sentinel); + // Add the sentinel to the last of these too. + auto ISD = std::find_if(Cmd->Commands.rbegin(), Cmd->Commands.rend(), + [](const BaseCommand *Base) { + return isa<InputSectionDescription>(Base); + }); + cast<InputSectionDescription>(*ISD)->Sections.push_back(Sentinel); } // The linker is expected to define SECNAME_start and SECNAME_end @@ -1346,7 +1365,7 @@ template <class ELFT> void Writer<ELFT>::addStartEndSymbols() { Define("__init_array_start", "__init_array_end", Out::InitArray); Define("__fini_array_start", "__fini_array_end", Out::FiniArray); - if (OutputSection *Sec = findSection(".ARM.exidx")) + if (OutputSection *Sec = findSectionInScript(".ARM.exidx")) Define("__exidx_start", "__exidx_end", Sec); } @@ -1366,9 +1385,10 @@ void Writer<ELFT>::addStartStopSymbols(OutputSection *Sec) { template <class ELFT> OutputSectionCommand *Writer<ELFT>::findSectionCommand(StringRef Name) { - for (OutputSectionCommand *Cmd : OutputSectionCommands) - if (Cmd->Name == Name) - return Cmd; + for (BaseCommand *Base : Script->Opt.Commands) + if (auto *Cmd = dyn_cast<OutputSectionCommand>(Base)) + if (Cmd->Name == Name) + return Cmd; return nullptr; } @@ -1378,13 +1398,6 @@ template <class ELFT> OutputSection *Writer<ELFT>::findSectionInScript(StringRef return nullptr; } -template <class ELFT> OutputSection *Writer<ELFT>::findSection(StringRef Name) { - for (OutputSection *Sec : OutputSections) - if (Sec->Name == Name) - return Sec; - return nullptr; -} - static bool needsPtLoad(OutputSection *Sec) { if (!(Sec->Flags & SHF_ALLOC)) return false; @@ -1446,7 +1459,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { // different flags or is loaded at a discontiguous address using AT linker // script command. uint64_t NewFlags = computeFlags(Sec->getPhdrFlags()); - if (Script->hasLMA(Sec) || Flags != NewFlags) { + if (Cmd->LMAExpr || Flags != NewFlags) { Load = AddHdr(PT_LOAD, NewFlags); Flags = NewFlags; } @@ -1514,7 +1527,7 @@ template <class ELFT> std::vector<PhdrEntry> Writer<ELFT>::createPhdrs() { for (OutputSectionCommand *Cmd : OutputSectionCommands) { OutputSection *Sec = Cmd->Sec; if (Sec->Type == SHT_NOTE) { - if (!Note || Script->hasLMA(Sec)) + if (!Note || Cmd->LMAExpr) Note = AddHdr(PT_NOTE, PF_R); Note->add(Sec); } else { @@ -1528,11 +1541,9 @@ template <class ELFT> void Writer<ELFT>::addPtArmExid(std::vector<PhdrEntry> &Phdrs) { if (Config->EMachine != EM_ARM) return; - auto I = - std::find_if(OutputSectionCommands.begin(), OutputSectionCommands.end(), - [](OutputSectionCommand *Cmd) { - return Cmd->Sec->Type == SHT_ARM_EXIDX; - }); + auto I = llvm::find_if(OutputSectionCommands, [](OutputSectionCommand *Cmd) { + return Cmd->Sec->Type == SHT_ARM_EXIDX; + }); if (I == OutputSectionCommands.end()) return; diff --git a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp index edbe576f0086..b54054726dfe 100644 --- a/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp +++ b/lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp @@ -508,9 +508,9 @@ readBinary(std::unique_ptr<MemoryBuffer> &mb, if (dyldInfo) { // If any exports, extract and add to normalized exportInfo vector. if (dyldInfo->export_size) { - const uint8_t *trieStart = reinterpret_cast<const uint8_t*>(start + - dyldInfo->export_off); - ArrayRef<uint8_t> trie(trieStart, dyldInfo->export_size); + const uint8_t *trieStart = reinterpret_cast<const uint8_t *>( + start + read32(&dyldInfo->export_off, isBig)); + ArrayRef<uint8_t> trie(trieStart, read32(&dyldInfo->export_size, isBig)); for (const ExportEntry &trieExport : MachOObjectFile::exports(trie)) { Export normExport; normExport.name = trieExport.name().copy(f->ownedAllocations); diff --git a/test/COFF/Inputs/library-arm64.lib b/test/COFF/Inputs/library-arm64.lib Binary files differnew file mode 100644 index 000000000000..04e193dd16ba --- /dev/null +++ b/test/COFF/Inputs/library-arm64.lib diff --git a/test/COFF/Inputs/pdb-diff-cl.pdb b/test/COFF/Inputs/pdb-diff-cl.pdb Binary files differnew file mode 100644 index 000000000000..ba5d8380e7c3 --- /dev/null +++ b/test/COFF/Inputs/pdb-diff-cl.pdb diff --git a/test/COFF/Inputs/pdb-diff.cpp b/test/COFF/Inputs/pdb-diff.cpp new file mode 100644 index 000000000000..f9acd68d1199 --- /dev/null +++ b/test/COFF/Inputs/pdb-diff.cpp @@ -0,0 +1,10 @@ +// Build with cl: +// cl.exe /Z7 pdb-diff.cpp /link /debug /pdb:pdb-diff-cl.pdb +// /nodefaultlib /entry:main +// Build with lld (after running the above cl command): +// lld-link.exe /debug /pdb:pdb-diff-lld.pdb /nodefaultlib +// /entry:main pdb-diff.obj + +void *__purecall = 0; + +int main() { return 42; } diff --git a/test/COFF/Inputs/pdb-diff.obj b/test/COFF/Inputs/pdb-diff.obj Binary files differnew file mode 100644 index 000000000000..a8948bd0c513 --- /dev/null +++ b/test/COFF/Inputs/pdb-diff.obj diff --git a/test/COFF/Inputs/pdb-scopes-a.yaml b/test/COFF/Inputs/pdb-scopes-a.yaml new file mode 100644 index 000000000000..e9f4484c7060 --- /dev/null +++ b/test/COFF/Inputs/pdb-scopes-a.yaml @@ -0,0 +1,425 @@ +--- !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: 'C:\src\llvm-project\build\a.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 5 + DbgStart: 4 + DbgEnd: 4 + FunctionType: 4099 + Flags: [ ] + DisplayName: g + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 8 + Type: 116 + Register: RSP + VarName: x + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 5 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\a.c' + Lines: + - Offset: 0 + LineStart: 1 + IsStatement: true + EndDelta: 0 + Columns: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 58 + DbgStart: 8 + DbgEnd: 53 + FunctionType: 4101 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 56 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 64 + Type: 116 + Register: RSP + VarName: argc + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 17 + Offset: 15 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 32 + Type: 116 + Register: RSP + VarName: x + - Kind: S_END + ScopeEndSym: + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 17 + Offset: 34 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 36 + Type: 116 + Register: RSP + VarName: y + - Kind: S_END + ScopeEndSym: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 58 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\a.c' + Lines: + - Offset: 0 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 8 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 15 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 23 + LineStart: 6 + IsStatement: true + EndDelta: 0 + - Offset: 32 + LineStart: 7 + IsStatement: true + EndDelta: 0 + - Offset: 34 + LineStart: 8 + IsStatement: true + EndDelta: 0 + - Offset: 42 + LineStart: 9 + IsStatement: true + EndDelta: 0 + - Offset: 51 + LineStart: 11 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\a.c' + Kind: MD5 + Checksum: 7FA72225C3F5630316383BD8BCC3EF72 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\a.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4110 + Relocations: + - VirtualAddress: 152 + SymbolName: g + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 156 + SymbolName: g + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 220 + SymbolName: g + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 224 + SymbolName: g + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 292 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 296 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 369 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 373 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 412 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 416 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 452 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 456 + 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: 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: 4097 + Attrs: 65548 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: g + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 116 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4096 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4100 + Name: main + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: f + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4105 ] + - Kind: LF_STRING_ID + StringId: + Id: 4106 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: a.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ] + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 894C2408C3CCCCCCCCCCCCCCCCCCCCCC894C24084883EC38837C2440007413C74424202A0000008B4C2420E800000000EB11C74424240D0000008B4C2424E80000000033C04883C438C3 + Relocations: + - VirtualAddress: 44 + SymbolName: f + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 63 + SymbolName: f + Type: IMAGE_REL_AMD64_REL32 + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0108010008620000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 000000003A00000000000000 + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$main' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - 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: 628 + NumberOfRelocations: 12 + 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: 624 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 74 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 2120072435 + Number: 0 + - Name: g + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: f + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: main + Value: 16 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN5' + Value: 16 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3137252093 + Number: 0 + - Name: '$unwind$main' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 336416693 + Number: 0 + - Name: '$pdata$main' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/test/COFF/Inputs/pdb-scopes-b.yaml b/test/COFF/Inputs/pdb-scopes-b.yaml new file mode 100644 index 000000000000..2839bf7e3538 --- /dev/null +++ b/test/COFF/Inputs/pdb-scopes-b.yaml @@ -0,0 +1,365 @@ +--- !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: 'C:\src\llvm-project\build\b.obj' + - Kind: S_COMPILE3 + Compile3Sym: + Flags: [ SecurityChecks, HotPatch ] + Machine: X64 + FrontendMajor: 19 + FrontendMinor: 0 + FrontendBuild: 24215 + FrontendQFE: 1 + BackendMajor: 19 + BackendMinor: 0 + BackendBuild: 24215 + BackendQFE: 1 + Version: 'Microsoft (R) Optimizing Compiler' + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 62 + DbgStart: 8 + DbgEnd: 57 + FunctionType: 4101 + Flags: [ ] + DisplayName: f + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 56 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 64 + Type: 116 + Register: RSP + VarName: x + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 20 + Offset: 15 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 32 + Type: 116 + Register: RSP + VarName: y + - Kind: S_END + ScopeEndSym: + - Kind: S_BLOCK32 + BlockSym: + CodeSize: 20 + Offset: 37 + BlockName: '' + - Kind: S_REGREL32 + RegRelativeSym: + Offset: 36 + Type: 116 + Register: RSP + VarName: w + - Kind: S_END + ScopeEndSym: + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 62 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\b.c' + Lines: + - Offset: 0 + LineStart: 2 + IsStatement: true + EndDelta: 0 + - Offset: 8 + LineStart: 3 + IsStatement: true + EndDelta: 0 + - Offset: 15 + LineStart: 4 + IsStatement: true + EndDelta: 0 + - Offset: 26 + LineStart: 5 + IsStatement: true + EndDelta: 0 + - Offset: 35 + LineStart: 6 + IsStatement: true + EndDelta: 0 + - Offset: 37 + LineStart: 7 + IsStatement: true + EndDelta: 0 + - Offset: 48 + LineStart: 8 + IsStatement: true + EndDelta: 0 + - Offset: 57 + LineStart: 10 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\b.c' + Kind: MD5 + Checksum: 8E8C92DB46478902EBEAEBFCFF15A6E0 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\b.c' + - !Symbols + Records: + - Kind: S_BUILDINFO + BuildInfoSym: + BuildId: 4110 + Relocations: + - VirtualAddress: 152 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 156 + SymbolName: f + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 223 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 227 + SymbolName: f + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 266 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 270 + SymbolName: f + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 308 + SymbolName: f + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 312 + SymbolName: f + 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: [ 0 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 0 + ArgumentList: 4096 + - Kind: LF_POINTER + Pointer: + ReferentType: 4097 + Attrs: 65548 + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 116 ] + - Kind: LF_PROCEDURE + Procedure: + ReturnType: 3 + CallConv: NearC + Options: [ None ] + ParameterCount: 1 + ArgumentList: 4099 + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4100 + Name: f + - Kind: LF_FUNC_ID + FuncId: + ParentScope: 0 + FunctionType: 4097 + Name: g + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\PROGRA~2\MICROS~1.0\VC\Bin\amd64\cl.exe' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: '-c -Z7 -MT -IC:\PROGRA~2\MICROS~1.0\VC\include -IC:\PROGRA~2\MICROS~1.0\VC\atlmfc\include -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\ucrt -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\shared -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\um' + - Kind: LF_SUBSTR_LIST + StringList: + StringIndices: [ 4105 ] + - Kind: LF_STRING_ID + StringId: + Id: 4106 + String: ' -IC:\PROGRA~2\WI3CF2~1\10\include\10.0.14393.0\winrt -TC -X' + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: b.c + - Kind: LF_STRING_ID + StringId: + Id: 0 + String: 'C:\src\llvm-project\build\vc140.pdb' + - Kind: LF_BUILDINFO + BuildInfo: + ArgIndices: [ 4103, 4104, 4108, 4109, 4107 ] + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 894C24084883EC38837C24400074168B44244083C003894424208B4C2420E800000000EB148B44244083C004894424248B4C2424E8000000004883C438C3 + Relocations: + - VirtualAddress: 31 + SymbolName: g + Type: IMAGE_REL_AMD64_REL32 + - VirtualAddress: 53 + SymbolName: g + Type: IMAGE_REL_AMD64_REL32 + - Name: .xdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '0108010008620000' + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: '000000003E00000000000000' + Relocations: + - VirtualAddress: 0 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 4 + SymbolName: '$LN5' + Type: IMAGE_REL_AMD64_ADDR32NB + - VirtualAddress: 8 + SymbolName: '$unwind$f' + Type: IMAGE_REL_AMD64_ADDR32NB +symbols: + - 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: 484 + NumberOfRelocations: 8 + 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: 616 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 62 + NumberOfRelocations: 2 + NumberOfLinenumbers: 0 + CheckSum: 3841032836 + Number: 0 + - Name: g + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: f + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: '$LN5' + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_LABEL + - Name: .xdata + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 3137252093 + Number: 0 + - Name: '$unwind$f' + Value: 0 + SectionNumber: 5 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .pdata + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 3 + NumberOfLinenumbers: 0 + CheckSum: 2420588879 + Number: 0 + - Name: '$pdata$f' + Value: 0 + SectionNumber: 6 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC +... diff --git a/test/COFF/arm64-magic.yaml b/test/COFF/arm64-magic.yaml new file mode 100644 index 000000000000..a35eeca483c7 --- /dev/null +++ b/test/COFF/arm64-magic.yaml @@ -0,0 +1,46 @@ +# RUN: yaml2obj < %s > %t.obj +# RUN: lld-link /out:%t.exe /entry:mainCRTStartup /subsystem:console %t.obj +# RUN: llvm-readobj -file-headers %t.exe | FileCheck %s + +# CHECK: Format: COFF-ARM64 +# CHECK: Arch: aarch64 +# CHECK: AddressSize: 64bit +# CHECK: ImageFileHeader { +# CHECK: Machine: IMAGE_FILE_MACHINE_ARM64 (0xAA64) +# CHECK: Characteristics [ (0x22) +# CHECK: IMAGE_FILE_EXECUTABLE_IMAGE (0x2) +# CHECK: IMAGE_FILE_LARGE_ADDRESS_AWARE (0x20) +# CHECK: ] +# CHECK: } +# CHECK: ImageOptionalHeader { +# CHECK: Magic: 0x20B + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARM64 + Characteristics: [] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_PURGEABLE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: 'e0031f2ac0035fd6' +symbols: + - Name: .text + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 8 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 1 + - Name: mainCRTStartup + 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-relocs-imports.test b/test/COFF/arm64-relocs-imports.test new file mode 100644 index 000000000000..3d252aaa2801 --- /dev/null +++ b/test/COFF/arm64-relocs-imports.test @@ -0,0 +1,136 @@ +# REQUIRES: aarch64 + +# RUN: yaml2obj < %s > %t.obj +# RUN: llvm-objdump -d %t.obj | FileCheck %s -check-prefix BEFORE +# RUN: lld-link /entry:main /subsystem:console /out:%t.exe %t.obj %p/Inputs/library-arm64.lib +# RUN: llvm-objdump -d %t.exe | FileCheck %s -check-prefix AFTER + +# BEFORE: Disassembly of section .text: +# BEFORE: 0: fe 0f 1f f8 str x30, [sp, #-16]! +# BEFORE: 4: 00 00 00 90 adrp x0, #0 +# BEFORE: 8: 00 08 00 91 add x0, x0, #2 +# BEFORE: c: 00 00 00 94 bl #0 +# BEFORE: 10: 00 01 40 39 ldrb w0, [x8] +# BEFORE: 14: 00 01 40 79 ldrh w0, [x8] +# BEFORE: 18: 00 01 40 b9 ldr w0, [x8] +# BEFORE: 1c: 00 01 40 f9 ldr x0, [x8] +# BEFORE: 20: e0 03 1f 2a mov w0, wzr +# BEFORE: 24: fe 07 41 f8 ldr x30, [sp], #16 +# BEFORE: 28: c0 03 5f d6 ret +# BEFORE: 2c: 08 00 00 00 <unknown> +# BEFORE: 30: 00 00 00 00 <unknown> + +# 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: 0a 00 00 94 bl #40 +# 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: e0 03 1f 2a mov w0, wzr +# AFTER: 140002024: fe 07 41 f8 ldr x30, [sp], #16 +# AFTER: 140002028: c0 03 5f d6 ret +# AFTER: 14000202c: 10 10 00 40 <unknown> +# AFTER: 140002030: 01 00 00 00 <unknown> +# AFTER: 140002034: 10 00 00 b0 adrp x16, #4096 +# AFTER: 140002038: 10 1e 40 f9 ldr x16, [x16, #56] +# AFTER: 14000203c: 00 02 1f d6 br x16 + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_ARM64 + Characteristics: [ ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 4 + SectionData: FE0F1FF80000009000080091000000940001403900014079000140B9000140F9E0031F2AFE0741F8C0035FD60800000000000000 + Relocations: + - VirtualAddress: 4 + SymbolName: .Lstr + Type: 4 + - VirtualAddress: 8 + SymbolName: .Lstr + Type: 6 + - VirtualAddress: 12 + SymbolName: function + Type: 3 + - VirtualAddress: 16 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 20 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 24 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 28 + SymbolName: .Lglobal + Type: 7 + - VirtualAddress: 44 + SymbolName: .Lglobal + Type: 14 + - 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: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + Alignment: 1 + SectionData: 00000000202068656C6C6F20776F726C6400 +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: 3 + NumberOfLinenumbers: 0 + CheckSum: 1438860354 + Number: 1 + - Name: .rdata + Value: 0 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 12 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 872944732 + Number: 4 + - Name: main + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL + - Name: .Lstr + Value: 4 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: .Lglobal + Value: 8 + SectionNumber: 4 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + - Name: function + Value: 0 + SectionNumber: 0 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/combined-resources.test b/test/COFF/combined-resources.test index dc6c87af0f77..e8d5d65008d5 100644 --- a/test/COFF/combined-resources.test +++ b/test/COFF/combined-resources.test @@ -8,10 +8,206 @@ # RUN: lld-link /out:%t.exe /entry:main %t.obj %p/Inputs/resource.res \ # RUN: %p/Inputs/combined-resources.res %p/Inputs/combined-resources-2.res -# RUN: llvm-readobj -coff-resources -file-headers %t.exe | FileCheck %s - +# RUN: llvm-readobj -coff-resources -file-headers -section-data %t.exe | \ +# RUN: FileCheck %s CHECK: ResourceTableRVA: 0x1000 CHECK-NEXT: ResourceTableSize: 0xC1C CHECK-DAG: Resources [ CHECK-NEXT: Total Number of Resources: 13 +CHECK-DAG: .rsrc Data ( +CHECK-NEXT: 0000: 00000000 00000000 00000000 01000600 |................| +CHECK-NEXT: 0010: 38030080 48000080 02000000 60000080 |8...H.......`...| +CHECK-NEXT: 0020: 04000000 80000080 05000000 A0000080 |................| +CHECK-NEXT: 0030: 06000000 B8000080 09000000 D0000080 |................| +CHECK-NEXT: 0040: 0A000000 F0000080 00000000 00000000 |................| +CHECK-NEXT: 0050: 00000000 01000000 50030080 08010080 |........P.......| +CHECK-NEXT: 0060: 00000000 00000000 00000000 02000000 |................| +CHECK-NEXT: 0070: FE020080 20010080 0C030080 38010080 |.... .......8...| +CHECK-NEXT: 0080: 00000000 00000000 00000000 01000100 |................| +CHECK-NEXT: 0090: 2C030080 50010080 60380000 68010080 |,...P...`8..h...| +CHECK-NEXT: 00A0: 00000000 00000000 00000000 01000000 |................| +CHECK-NEXT: 00B0: 16030080 80010080 00000000 00000000 |................| +CHECK-NEXT: 00C0: 00000000 00000100 01000000 98010080 |................| +CHECK-NEXT: 00D0: 00000000 00000000 00000000 01000100 |................| +CHECK-NEXT: 00E0: E0020080 B0010080 0C000000 D0010080 |................| +CHECK-NEXT: 00F0: 00000000 00000000 00000000 01000000 |................| +CHECK-NEXT: 0100: 66030080 E8010080 00000000 00000000 |f...............| +CHECK-NEXT: 0110: 00000000 00000100 09040000 10020000 |................| +CHECK-NEXT: 0120: 00000000 00000000 00000000 00000100 |................| +CHECK-NEXT: 0130: 09040000 20020000 00000000 00000000 |.... ...........| +CHECK-NEXT: 0140: 00000000 00000100 09040000 30020000 |............0...| +CHECK-NEXT: 0150: 00000000 00000000 00000000 00000100 |................| +CHECK-NEXT: 0160: 090C0000 40020000 00000000 00000000 |....@...........| +CHECK-NEXT: 0170: 00000000 00000100 04080000 50020000 |............P...| +CHECK-NEXT: 0180: 00000000 00000000 00000000 00000100 |................| +CHECK-NEXT: 0190: 09040000 60020000 00000000 00000000 |....`...........| +CHECK-NEXT: 01A0: 00000000 00000100 09040000 70020000 |............p...| +CHECK-NEXT: 01B0: 00000000 00000000 00000000 00000200 |................| +CHECK-NEXT: 01C0: 09040000 80020000 04080000 90020000 |................| +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: 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.| +CHECK-NEXT: 0310: 4B004100 59000A00 54004500 53005400 |K.A.Y...T.E.S.T.| +CHECK-NEXT: 0320: 44004900 41004C00 4F004700 05002200 |D.I.A.L.O.G...".| +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: 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: 03F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0400: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0410: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +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: 05F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0600: FFFFFFFF FFFFFFFF BDBDBDF7 F7F7EFEF |................| +CHECK-NEXT: 0610: EFD0D0D0 AFAFAFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0620: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0630: FFFFFFFF FFFFFFFF C1C1C1F7 F7F7D5D5 |................| +CHECK-NEXT: 0640: D5B6B6B6 FFFFFFFF 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: 0680: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0690: FFFFFFFF FFFFFFFF C8C8C8C5 C5C5FFFF |................| +CHECK-NEXT: 06A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 06B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 06C0: FFFFFFFF FFFFFFFF CBCBCBFF FFFFFFFF |................| +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: 0720: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0730: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0740: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0750: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0760: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0770: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0780: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0790: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +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: 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: 0830: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0840: 01B31800 DE55F6FE F9DBFAE7 FEFFFE86 |.....U..........| +CHECK-NEXT: 0850: EFAE00DE 5501B318 FFFFFFFF 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: 0890: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08A0: 01B31800 ED9800ED 9800ED98 00ED9887 |................| +CHECK-NEXT: 08B0: F7CFFEFF FF01B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08D0: 01B31800 F4BA00F4 BA00F4BA 00F4BA00 |................| +CHECK-NEXT: 08E0: F4BA9CFB E401B318 FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 08F0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0900: 01B31800 FBDB00FB DB00FBDB 00FBDB00 |................| +CHECK-NEXT: 0910: FBDB00FB DB01B318 FFFFFFFF 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: 0950: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0960: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0970: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0980: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 0990: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09A0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09B0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +CHECK-NEXT: 09C0: FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF |................| +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: ) diff --git a/test/COFF/pdb-comdat.test b/test/COFF/pdb-comdat.test index a7b5c401ab92..ea691aec87ad 100644 --- a/test/COFF/pdb-comdat.test +++ b/test/COFF/pdb-comdat.test @@ -47,7 +47,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_ID [size = 44] `main` -CHECK: parent = 0, end = 0, addr = 0002:0000, code size = 24 +CHECK: parent = 0, end = 196, addr = 0002: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 @@ -58,7 +58,7 @@ CHECK: 200 | S_GDATA32 [size = 24] `global` CHECK: type = 0x0074 (int), addr = 0000:0000 CHECK: 224 | S_BUILDINFO [size = 8] BuildId = `4106` CHECK: 232 | S_GPROC32_ID [size = 44] `foo` -CHECK: parent = 0, end = 0, addr = 0002:0032, code size = 15 +CHECK: parent = 0, end = 308, addr = 0002:0032, code size = 15 CHECK: debug start = 0, debug end = 14, flags = none CHECK: 276 | S_FRAMEPROC [size = 32] CHECK: size = 0, padding size = 0, offset to padding = 0 @@ -72,7 +72,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_ID [size = 44] `bar` -CHECK: parent = 0, end = 0, addr = 0002:0048, code size = 14 +CHECK: parent = 0, end = 196, addr = 0002: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 new file mode 100644 index 000000000000..79b23a5c026d --- /dev/null +++ b/test/COFF/pdb-diff.test @@ -0,0 +1,212 @@ +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: lld-link /debug /pdb:%T/pdb-diff-lld.pdb /nodefaultlib /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/ %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 | D | +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: | Public Symbol Records | {{[EI]}} | +CHECK-NEXT: |------------------------------+---| +CHECK-NEXT: | Global Symbol Hash | D | +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 | D | +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 | D | +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-invalid-func-type.yaml b/test/COFF/pdb-invalid-func-type.yaml new file mode 100644 index 000000000000..686079e7d8e4 --- /dev/null +++ b/test/COFF/pdb-invalid-func-type.yaml @@ -0,0 +1,146 @@ +# This test has an S_GPROC32_ID symbol with an invalid type index. Make sure we +# keep the record, or we'll have unbalanced scopes, which is bad. This situation +# can arise when we can't find the type server PDB. + +# RUN: yaml2obj %s -o %t.obj +# RUN: lld-link %t.obj -out:%t.exe -debug -pdb:%t.pdb -nodefaultlib -entry:main +# RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +# CHECK: Mod 0000 | `{{.*}}pdb-invalid-func-type.yaml.tmp.obj`: +# CHECK: 4 | S_GPROC32_ID [size = 44] `main` +# CHECK: parent = 0, end = 80, addr = 0001:0000, code size = 3 +# CHECK: 48 | S_FRAMEPROC [size = 32] +# CHECK: 80 | S_END [size = 4] + +--- !COFF +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ ] +sections: + - Name: '.debug$S' + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_DISCARDABLE, IMAGE_SCN_MEM_READ ] + Alignment: 1 + Subsections: + - !Symbols + Records: + - Kind: S_GPROC32_ID + ProcSym: + CodeSize: 3 + DbgStart: 0 + DbgEnd: 2 + # Corrupt function type! + FunctionType: 4101 + Flags: [ ] + DisplayName: main + - Kind: S_FRAMEPROC + FrameProcSym: + TotalFrameBytes: 0 + PaddingFrameBytes: 0 + OffsetToPadding: 0 + BytesOfCalleeSavedRegisters: 0 + OffsetOfExceptionHandler: 0 + SectionIdOfExceptionHandler: 0 + Flags: [ AsynchronousExceptionHandling, OptimizedForSpeed ] + - Kind: S_PROC_ID_END + ScopeEndSym: + - !Lines + CodeSize: 3 + Flags: [ ] + RelocOffset: 0 + RelocSegment: 0 + Blocks: + - FileName: 'c:\src\llvm-project\build\t.c' + Lines: + - Offset: 0 + LineStart: 1 + IsStatement: true + EndDelta: 0 + Columns: + - !FileChecksums + Checksums: + - FileName: 'c:\src\llvm-project\build\t.c' + Kind: MD5 + Checksum: 270A878DCC1B845655B162F56C4F5020 + - !StringTable + Strings: + - 'c:\src\llvm-project\build\t.c' + Relocations: + - VirtualAddress: 44 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 48 + SymbolName: main + Type: IMAGE_REL_AMD64_SECTION + - VirtualAddress: 100 + SymbolName: main + Type: IMAGE_REL_AMD64_SECREL + - VirtualAddress: 104 + 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: 1 + Types: + - Kind: LF_ARGLIST + ArgList: + ArgIndices: [ 0 ] + - 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 + - Name: '.text$mn' + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + Alignment: 16 + SectionData: 33C0C3 +symbols: + - Name: '.debug$S' + Value: 0 + SectionNumber: 1 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 328 + NumberOfRelocations: 4 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.debug$T' + Value: 0 + SectionNumber: 2 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 564 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 0 + Number: 0 + - Name: '.text$mn' + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_NULL + StorageClass: IMAGE_SYM_CLASS_STATIC + SectionDefinition: + Length: 3 + NumberOfRelocations: 0 + NumberOfLinenumbers: 0 + CheckSum: 4021952397 + Number: 0 + - Name: main + Value: 0 + SectionNumber: 3 + SimpleType: IMAGE_SYM_TYPE_NULL + ComplexType: IMAGE_SYM_DTYPE_FUNCTION + StorageClass: IMAGE_SYM_CLASS_EXTERNAL +... diff --git a/test/COFF/pdb-lib.s b/test/COFF/pdb-lib.s index 47375cc26ff2..ab95f82a2a91 100644 --- a/test/COFF/pdb-lib.s +++ b/test/COFF/pdb-lib.s @@ -13,12 +13,15 @@ # CHECK-NEXT: Mod 0000 | Name: `{{.*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: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0001 | Name: `bar.obj`: # CHECK-NEXT: Obj: `{{.*pdb-lib.s.tmp[/\\]bar.lib}}`: # CHECK-NEXT: debug stream: 10, # files: 0, has ec info: false +# CHECK-NEXT: pdb file ni: 0 ``, src file ni: 0 `` # CHECK-NEXT: Mod 0002 | Name: `* Linker *`: # CHECK-NEXT: Obj: ``: # CHECK-NEXT: debug stream: 11, # files: 0, has ec info: false +# CHECK-NEXT: pdb file ni: 1 `{{.*foo.pdb}}`, src file ni: 0 `` .def _main; .scl 2; diff --git a/test/COFF/pdb-linker-module.test b/test/COFF/pdb-linker-module.test new file mode 100644 index 000000000000..ce366b6d6482 --- /dev/null +++ b/test/COFF/pdb-linker-module.test @@ -0,0 +1,18 @@ +RUN: lld-link /debug /pdb:%t.pdb /nodefaultlib /entry:main %S/Inputs/pdb-diff.obj +RUN: llvm-pdbutil dump -modules -symbols %t.pdb | FileCheck %s + +CHECK: Mod 0001 | `* Linker *`: +CHECK-NEXT: 4 | S_OBJNAME [size = 20] sig=0, `* Linker *` +CHECK-NEXT: 24 | S_COMPILE3 [size = 40] +CHECK-NEXT: machine = intel 80386, Ver = LLVM Linker, language = link +CHECK-NEXT: frontend = 0.0.0.0, backend = 0.0.0.0 +CHECK-NEXT: flags = none +CHECK-NEXT: 64 | S_ENVBLOCK +CHECK-NEXT: - cwd +CHECK-NEXT: - +CHECK-NEXT: - exe +CHECK-NEXT: - {{.*}}lld-link +CHECK-NEXT: - pdb +CHECK-NEXT: - {{.*}}pdb-linker-module{{.*}}pdb +CHECK-NEXT: - cmd +CHECK-NEXT: - /debug /pdb:{{.*}}pdb-linker-module{{.*}}pdb /nodefaultlib /entry:main {{.*}}pdb-diff.obj diff --git a/test/COFF/pdb-none.test b/test/COFF/pdb-none.test index a028cf05547e..c1becbad7a3b 100644 --- a/test/COFF/pdb-none.test +++ b/test/COFF/pdb-none.test @@ -7,8 +7,8 @@ # CHECK: PdbStream: # CHECK-NEXT: Age: 0 -# CHECK-NEXT: Guid: '{00000000-0000-0000-0000-000000000000}' -# CHECK-NEXT: Signature: 0 +# CHECK-NEXT: Guid: +# CHECK-NEXT: Signature: # CHECK-NEXT: Features: [ VC140 ] # CHECK-NEXT: Version: VC70 diff --git a/test/COFF/pdb-scopes.test b/test/COFF/pdb-scopes.test new file mode 100644 index 000000000000..7beb59766cc5 --- /dev/null +++ b/test/COFF/pdb-scopes.test @@ -0,0 +1,75 @@ +Consider this program: + +$ cat a.c +void g(int x) {} +void f(int x); +int main(int argc) { + if (argc) { + int x = 42; + f(x); + } else { + int y = 13; + f(y); + } +} + +$ cat b.c +extern void g(); +void f(int x) { + if (x) { + int y = x + 3; + g(y); + } else { + int w = x + 4; + g(w); + } +} + +This program is interesting because there are two TUs, and each TU has nested +scopes. Make sure we get the right parent and end offsets. + +RUN: yaml2obj %S/Inputs/pdb-scopes-a.yaml -o %t-a.obj +RUN: yaml2obj %S/Inputs/pdb-scopes-b.yaml -o %t-b.obj +RUN: lld-link %t-a.obj %t-b.obj -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb +RUN: llvm-pdbutil dump -symbols %t.pdb | FileCheck %s + +CHECK-LABEL: Mod 0000 | `{{.*}}pdb-scopes.test.tmp-a.obj`: +CHECK: 104 | S_GPROC32_ID [size = 44] `g` +CHECK: parent = 0, end = 196, addr = 0002: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_ID [size = 44] `main` +CHECK: parent = 0, end = 384, addr = 0002: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: 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: 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_ID [size = 44] `f` +CHECK: parent = 0, end = 284, addr = 0002: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: 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: 264 | S_REGREL32 [size = 16] `w` +CHECK: 280 | S_END [size = 4] +CHECK: 284 | S_END [size = 4] + +CHECK-LABEL: Mod 0002 | `* Linker *`: diff --git a/test/COFF/pdb-source-lines.test b/test/COFF/pdb-source-lines.test index a630ecb22d62..f9e0e5c7487f 100644 --- a/test/COFF/pdb-source-lines.test +++ b/test/COFF/pdb-source-lines.test @@ -23,7 +23,7 @@ RUN: lld-link -debug -entry:main -nodefaultlib -out:%t.exe -pdb:%t.pdb %t.pdb_li RUN: llvm-pdbutil pdb2yaml -modules -module-files -subsections=lines,fc %t.pdb | FileCheck %s CHECK-LABEL: DbiStream: -CHECK-NEXT: VerHeader: V110 +CHECK-NEXT: VerHeader: V70 CHECK-NEXT: Age: 1 CHECK-NEXT: BuildNumber: 0 CHECK-NEXT: PdbDllVersion: 0 diff --git a/test/COFF/pdb-symbol-types.yaml b/test/COFF/pdb-symbol-types.yaml index eceb434f0d0f..8abbc365b34e 100644 --- a/test/COFF/pdb-symbol-types.yaml +++ b/test/COFF/pdb-symbol-types.yaml @@ -22,7 +22,7 @@ # CHECK: frontend = 19.0.24215.1, backend = 19.0.24215.1 # CHECK: flags = security checks | hot patchable # CHECK: 116 | S_GPROC32_ID [size = 44] `main` -# CHECK: parent = 0, end = 0, addr = 0002:0000, code size = 7 +# CHECK: parent = 0, end = 192, addr = 0002: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.test b/test/COFF/pdb.test index 3acb7188df49..a4cd4f7c35b3 100644 --- a/test/COFF/pdb.test +++ b/test/COFF/pdb.test @@ -26,11 +26,11 @@ # CHECK: PdbStream: # CHECK-NEXT: Age: 1 # CHECK-NEXT: Guid: -# CHECK-NEXT: Signature: 0 +# CHECK-NEXT: Signature: # CHECK-NEXT: Features: [ VC140 ] # CHECK-NEXT: Version: VC70 # CHECK-NEXT: DbiStream: -# CHECK-NEXT: VerHeader: V110 +# CHECK-NEXT: VerHeader: V70 # CHECK-NEXT: Age: 1 # CHECK-NEXT: BuildNumber: 0 # CHECK-NEXT: PdbDllVersion: 0 @@ -120,12 +120,15 @@ RAW-NEXT: ============================================================ RAW-NEXT: Mod 0000 | Name: `{{.*}}pdb.test.tmp1.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp1.obj`: RAW-NEXT: debug stream: 9, # files: 1, has ec info: false +RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0001 | Name: `{{.*}}pdb.test.tmp2.obj`: RAW-NEXT: Obj: `{{.*}}pdb.test.tmp2.obj`: RAW-NEXT: debug stream: 10, # files: 1, has ec info: false +RAW-NEXT: pdb file ni: 0 ``, src file ni: 0 `` RAW-NEXT: Mod 0002 | Name: `* Linker *`: RAW-NEXT: Obj: ``: RAW-NEXT: debug stream: 11, # 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: ============================================================ RAW-NEXT: Showing 5 records @@ -183,17 +186,17 @@ RAW-NEXT: IMAGE_SCN_MEM_READ RAW: Section Map RAW-NEXT: ============================================================ RAW-NEXT: Section 0000 | ovl = 0, group = 0, frame = 0, name = 1 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0001 | ovl = 1, group = 0, frame = 0, name = 2 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | execute | 32 bit addr | selector RAW-NEXT: Section 0002 | ovl = 2, group = 0, frame = 0, name = 3 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0003 | ovl = 3, group = 0, frame = 0, name = 4 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = read | 32 bit addr | selector RAW-NEXT: Section 0004 | ovl = 4, group = 0, frame = 0, name = 5 -RAW-NEXT: class = 65535, offset = 0, size = +RAW-NEXT: class = 65535, offset = 0, size = RAW-NEXT: flags = 32 bit addr | absolute addr diff --git a/test/ELF/Inputs/gnu-ifunc-dso.s b/test/ELF/Inputs/gnu-ifunc-dso.s new file mode 100644 index 000000000000..bd82718718be --- /dev/null +++ b/test/ELF/Inputs/gnu-ifunc-dso.s @@ -0,0 +1,3 @@ +.type foo STT_GNU_IFUNC +.globl foo +foo: diff --git a/test/ELF/Inputs/symver-archive1.s b/test/ELF/Inputs/symver-archive1.s new file mode 100644 index 000000000000..be7c64494215 --- /dev/null +++ b/test/ELF/Inputs/symver-archive1.s @@ -0,0 +1,6 @@ +.text +.globl x +.type x, @function +x: + +.symver x, xx@@VER diff --git a/test/ELF/Inputs/symver-archive2.s b/test/ELF/Inputs/symver-archive2.s new file mode 100644 index 000000000000..a9b9d0b0a35b --- /dev/null +++ b/test/ELF/Inputs/symver-archive2.s @@ -0,0 +1 @@ +call xx@PLT diff --git a/test/ELF/Inputs/version-script-no-warn2.s b/test/ELF/Inputs/version-script-no-warn2.s new file mode 100644 index 000000000000..59de9d470b76 --- /dev/null +++ b/test/ELF/Inputs/version-script-no-warn2.s @@ -0,0 +1 @@ +call foo@plt diff --git a/test/ELF/Inputs/version-script-weak.s b/test/ELF/Inputs/version-script-weak.s new file mode 100644 index 000000000000..09f5cf09db7d --- /dev/null +++ b/test/ELF/Inputs/version-script-weak.s @@ -0,0 +1,4 @@ +.text +.globl foo +.type foo,@function +foo: diff --git a/test/ELF/Inputs/wrap-dynamic-undef.s b/test/ELF/Inputs/wrap-dynamic-undef.s new file mode 100644 index 000000000000..ade79556db7b --- /dev/null +++ b/test/ELF/Inputs/wrap-dynamic-undef.s @@ -0,0 +1,2 @@ +.global foo +foo: diff --git a/test/ELF/arm-mov-relocs.s b/test/ELF/arm-mov-relocs.s index 31ccba4cceaf..7e3ce67e0615 100644 --- a/test/ELF/arm-mov-relocs.s +++ b/test/ELF/arm-mov-relocs.s @@ -26,14 +26,9 @@ _start: .section .R_ARM_MOVT_ABS, "ax",%progbits movt r0, :upper16:label movt r1, :upper16:label1 -// FIXME: We shouldn't need to multiply by 65536. -// arguably llvm-mc incorrectly assembles addends for -// SHT_REL relocated movt instructions. When there is a relocation -// the interpretation of the addend for SHT_REL is not shifted - movt r2, :upper16:label2 + (4 * 65536) + movt r2, :upper16:label2 + 4 movt r3, :upper16:label3 -// FIXME: We shouldn't need to multiply by 65536 see comment above. - movt r4, :upper16:label3 + (4 * 65536) + movt r4, :upper16:label3 + 4 // CHECK: Disassembly of section .R_ARM_MOVT_ABS // CHECK: movt r0, #2 // CHECK: movt r1, #2 diff --git a/test/ELF/copy-in-shared.s b/test/ELF/copy-in-shared.s index 1d77eaf3a141..70439853c7c1 100644 --- a/test/ELF/copy-in-shared.s +++ b/test/ELF/copy-in-shared.s @@ -4,7 +4,7 @@ // 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 -// 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 // CHECK: >>> defined in {{.*}}.so // CHECK: >>> referenced by {{.*}}.o:(.text+0x0) diff --git a/test/ELF/defsym.s b/test/ELF/defsym.s index 253d5d8f408d..b821484261b2 100644 --- a/test/ELF/defsym.s +++ b/test/ELF/defsym.s @@ -19,7 +19,7 @@ # CHECK-NEXT: Section: Absolute # CHECK-NEXT: } # CHECK-NEXT: Symbol { -# CHECK-NEXT: Name: foo2 +# CHECK-NEXT: Name: foo1 # CHECK-NEXT: Value: 0x123 # CHECK-NEXT: Size: # CHECK-NEXT: Binding: Global diff --git a/test/ELF/duplicated-synthetic-sym.s b/test/ELF/duplicated-synthetic-sym.s new file mode 100644 index 000000000000..cfd8642d2d17 --- /dev/null +++ b/test/ELF/duplicated-synthetic-sym.s @@ -0,0 +1,10 @@ +// 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 + +// CHECK: duplicate symbol: _binary_duplicated_synthetic_sym_s_start +// CHECK: defined at (internal):(.data+0x0) + + .globl _binary_duplicated_synthetic_sym_s_start +_binary_duplicated_synthetic_sym_s_start: + .long 0 diff --git a/test/ELF/gnu-ifunc-dso.s b/test/ELF/gnu-ifunc-dso.s new file mode 100644 index 000000000000..6ceff3b17d42 --- /dev/null +++ b/test/ELF/gnu-ifunc-dso.s @@ -0,0 +1,13 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %S/Inputs/gnu-ifunc-dso.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 %t2.o +# RUN: ld.lld -shared %t2.o %t.so -o %t +# RUN: llvm-readobj -dyn-relocations %t | FileCheck %s + +# CHECK: Dynamic Relocations { +# CHECK-NEXT: 0x1000 R_X86_64_64 foo 0x0 +# CHECK-NEXT: } + +.data + .quad foo diff --git a/test/ELF/invalid/Inputs/invalid-relocation-x64.elf b/test/ELF/invalid/Inputs/invalid-relocation-x64.elf Binary files differdeleted file mode 100644 index 25df2944614e..000000000000 --- a/test/ELF/invalid/Inputs/invalid-relocation-x64.elf +++ /dev/null diff --git a/test/ELF/invalid/invalid-debug-relocations.test b/test/ELF/invalid/invalid-debug-relocations.test new file mode 100644 index 000000000000..75e41d18514f --- /dev/null +++ b/test/ELF/invalid/invalid-debug-relocations.test @@ -0,0 +1,41 @@ +# REQUIRES: x86 +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld -gdb-index %t.o -o %t.exe 2>&1 | FileCheck %s + +# CHECK: error: {{.*}}.o: error parsing DWARF data: +# CHECK-NEXT: >>> failed to compute relocation: Unknown, Invalid data was encountered while parsing the file + +!ELF +FileHeader: + Class: ELFCLASS32 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_386 +Sections: + - Type: SHT_PROGBITS + Name: .text + Flags: [ ] + AddressAlign: 0x04 + Content: "0000" + - Type: SHT_PROGBITS + Name: .debug_info + Flags: [ ] + AddressAlign: 0x04 + Content: "0000" + - Type: SHT_REL + Name: .rel.debug_info + Link: .symtab + Info: .debug_info + Relocations: + - Offset: 0 + Symbol: _start + Type: 0xFF + - Offset: 4 + Symbol: _start + Type: 0xFF +Symbols: + Global: + - Name: _start + Type: STT_FUNC + Section: .text + Value: 0x0 diff --git a/test/ELF/invalid/invalid-relocation-x64.test b/test/ELF/invalid/invalid-relocation-x64.test index d52cf87c1b35..9b8ebb59e474 100644 --- a/test/ELF/invalid/invalid-relocation-x64.test +++ b/test/ELF/invalid/invalid-relocation-x64.test @@ -1,7 +1,8 @@ -## invalid-relocation-x64.elf contains relocations with invalid relocation number. -## Next yaml code was used to create initial binary. After that it -## was modified with hex-editor to replace known relocations with fake ones, -## that have 0x98 and 0x98 numbers. +# RUN: yaml2obj %s -o %t.o +# RUN: not ld.lld %t.o -o /dev/null 2>&1 | FileCheck %s +# CHECK: {{.*}}.o: unknown relocation type: Unknown (152) +# CHECK: {{.*}}.o: unknown relocation type: Unknown (153) + !ELF FileHeader: Class: ELFCLASS64 @@ -20,11 +21,7 @@ Sections: Relocations: - Offset: 0x0000000000000000 Symbol: '' - Type: R_X86_64_NONE + Type: 0x98 - Offset: 0x0000000000000000 Symbol: '' - Type: R_X86_64_NONE - -# RUN: not ld.lld %p/Inputs/invalid-relocation-x64.elf -o %t2 2>&1 | FileCheck %s -# CHECK: {{.*}}invalid-relocation-x64.elf: unknown relocation type: Unknown (152) -# CHECK: {{.*}}invalid-relocation-x64.elf: unknown relocation type: Unknown (153) + Type: 0x99 diff --git a/test/ELF/linkerscript/locationcountererr2.s b/test/ELF/linkerscript/locationcountererr2.s index 54ee4a34da2e..8968f6740ee4 100644 --- a/test/ELF/linkerscript/locationcountererr2.s +++ b/test/ELF/linkerscript/locationcountererr2.s @@ -2,8 +2,10 @@ # 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: not ld.lld %t.o --script %t.script -o %t -shared 2>&1 | FileCheck %s -# CHECK: {{.*}}.script:2: unable to move location counter backward +# 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 # 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/non-alloc-segment.s b/test/ELF/linkerscript/non-alloc-segment.s new file mode 100644 index 000000000000..229f028a16b2 --- /dev/null +++ b/test/ELF/linkerscript/non-alloc-segment.s @@ -0,0 +1,44 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o + +################################################################################ +## Test that non-alloc section .foo can be assigned to a segment. Check that +## the values of the offset and file size of this segment's PHDR are correct. +## +## This functionality allows non-alloc metadata, which is not required at +## run-time, to be added to a custom segment in a file. This metadata may be +## read/edited by tools/loader using the values of the offset and file size from +## the custom segment's PHDR. This is particularly important if section headers +## have been stripped. +# RUN: echo "PHDRS {text PT_LOAD; foo 0x12345678;} \ +# RUN: SECTIONS { \ +# RUN: .text : {*(.text .text*)} :text \ +# 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-readobj -l %t | FileCheck --check-prefix=PHDR %s + +# CHECK: Program Headers: +# CHECK-NEXT: Type +# CHECK-NEXT: LOAD +# CHECK-NEXT: <unknown>: 0x12345678 + +# CHECK: Section to Segment mapping: +# CHECK-NEXT: Segment Sections... +# CHECK-NEXT: 00 .text +# CHECK-NEXT: 01 .foo + +# PHDR: Type: (0x12345678) +# PHDR-NEXT: Offset: 0x1004 +# PHDR-NEXT: VirtualAddress +# PHDR-NEXT: PhysicalAddress +# PHDR-NEXT: FileSize: 4 + +.global _start +_start: + nop + +.section .foo + .align 4 + .long 0 diff --git a/test/ELF/linkerscript/out-of-order.s b/test/ELF/linkerscript/out-of-order.s index 9c6547a68643..6cfd533c4e14 100644 --- a/test/ELF/linkerscript/out-of-order.s +++ b/test/ELF/linkerscript/out-of-order.s @@ -1,9 +1,18 @@ # 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: not ld.lld -o %t.so --script %t.script %t.o -shared 2>&1 | FileCheck %s +# RUN: ld.lld -o %t.so --script %t.script %t.o -shared +# RUN: llvm-objdump -section-headers %t.so | FileCheck %s -# CHECK: error: {{.*}}.script:1: unable to move location counter backward +# CHECK: Sections: +# CHECK-NEXT: Idx Name Size Address Type +# CHECK-NEXT: 0 00000000 0000000000000000 +# CHECK-NEXT: 1 .data 00000008 0000000000004000 DATA +# 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 .quad 0 .data diff --git a/test/ELF/linkerscript/unused-synthetic.s b/test/ELF/linkerscript/unused-synthetic.s new file mode 100644 index 000000000000..c9295fff7b59 --- /dev/null +++ b/test/ELF/linkerscript/unused-synthetic.s @@ -0,0 +1,18 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "SECTIONS { \ +# RUN: .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 +# CHECK-NOT: .got +# CHECK-NOT: .plt +# CHECK: .text +# CHECK-NEXT: .dynsym + +.global _start +_start: + nop diff --git a/test/ELF/lto/defsym.ll b/test/ELF/lto/defsym.ll index 4c2fe45b3c53..2ce8570f9b68 100644 --- a/test/ELF/lto/defsym.ll +++ b/test/ELF/lto/defsym.ll @@ -1,9 +1,16 @@ ; REQUIRES: x86 +; 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: 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 + ; Call to bar2() should not be inlined and should be routed to bar3() ; Symbol bar3 should not be eliminated @@ -13,6 +20,13 @@ ; CHECK-NEXT: callq{{.*}}<bar3> ; CHECK-NEXT: callq +; THIN: foo +; THIN-NEXT: pushq %rax +; THIN-NEXT: callq +; THIN-NEXT: callq{{.*}}<bar3> +; THIN-NEXT: popq %rax +; THIN-NEXT: jmp + 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/wrap-1.ll b/test/ELF/lto/wrap-1.ll index b61dfaeb5903..1dd9139808b6 100644 --- a/test/ELF/lto/wrap-1.ll +++ b/test/ELF/lto/wrap-1.ll @@ -1,9 +1,16 @@ ; REQUIRES: x86 +; LTO ; RUN: llvm-as %s -o %t.o ; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps ; RUN: llvm-readobj -t %t.out | FileCheck %s ; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s +; ThinLTO +; RUN: opt -module-summary %s -o %t.o +; RUN: ld.lld %t.o -o %t.out -wrap=bar -save-temps +; RUN: llvm-readobj -t %t.out | FileCheck %s +; RUN: cat %t.out.resolution.txt | FileCheck -check-prefix=RESOLS %s + ; CHECK: Name: __wrap_bar ; CHECK-NEXT: Value: ; CHECK-NEXT: Size: diff --git a/test/ELF/lto/wrap-2.ll b/test/ELF/lto/wrap-2.ll index b318b7f65f2d..06ef4064e4d1 100644 --- a/test/ELF/lto/wrap-2.ll +++ b/test/ELF/lto/wrap-2.ll @@ -1,17 +1,31 @@ ; REQUIRES: x86 +; LTO ; RUN: llvm-as %s -o %t.o ; RUN: llvm-as %S/Inputs/wrap-bar.ll -o %t1.o ; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar ; RUN: llvm-objdump -d %t.so | FileCheck %s ; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s +; ThinLTO +; RUN: opt -module-summary %s -o %t.o +; RUN: opt -module-summary %S/Inputs/wrap-bar.ll -o %t1.o +; RUN: ld.lld %t.o %t1.o -shared -o %t.so -wrap=bar +; RUN: llvm-objdump -d %t.so | FileCheck %s -check-prefix=THIN +; RUN: llvm-readobj -t %t.so | FileCheck -check-prefix=BIND %s + ; Make sure that calls in foo() are not eliminated and that bar is ; routed to __wrap_bar and __real_bar is routed to bar. ; CHECK: foo: ; CHECK-NEXT: pushq %rax +; CHECK-NEXT: callq{{.*}}<__wrap_bar> ; CHECK-NEXT: callq{{.*}}<bar> -; CHECK-NEXT: callq{{.*}}<__real_bar> + +; THIN: foo: +; THIN-NEXT: pushq %rax +; THIN-NEXT: callq{{.*}}<__wrap_bar> +; THIN-NEXT: popq %rax +; THIN-NEXT: jmp{{.*}}<bar> ; Check that bar and __wrap_bar retain their original binding. ; BIND: Name: bar diff --git a/test/ELF/symver-archive.s b/test/ELF/symver-archive.s new file mode 100644 index 000000000000..be50503a3f5d --- /dev/null +++ b/test/ELF/symver-archive.s @@ -0,0 +1,15 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t1 +# RUN: rm -f %t.a +# 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 + +.text +.globl x +.type x, @function +x: + +.globl xx +xx = x diff --git a/test/ELF/version-script-no-warn2.s b/test/ELF/version-script-no-warn2.s new file mode 100644 index 000000000000..52beff366bb7 --- /dev/null +++ b/test/ELF/version-script-no-warn2.s @@ -0,0 +1,8 @@ +# 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 + +.global foo +foo: diff --git a/test/ELF/version-script-symver.s b/test/ELF/version-script-symver.s index 7798330b053d..0a4eddd46cec 100644 --- a/test/ELF/version-script-symver.s +++ b/test/ELF/version-script-symver.s @@ -1,8 +1,6 @@ # REQUIRES: x86 - # RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o -# RUN: echo "VERSION { global: *; };" > %t.map -# RUN: ld.lld %t.o --version-script %t.map -o %t +# RUN: ld.lld %t.o -o %t .global _start .global bar diff --git a/test/ELF/version-script-symver2.s b/test/ELF/version-script-symver2.s new file mode 100644 index 000000000000..5961d9a7c3a6 --- /dev/null +++ b/test/ELF/version-script-symver2.s @@ -0,0 +1,28 @@ +# REQUIRES: x86 +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: echo "VER1 { global: foo; local: *; }; VER2 { global: foo; }; VER3 { global: foo; };" > %t.map +# RUN: ld.lld -shared %t.o --version-script %t.map -o %t.so --fatal-warnings +# 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: 3 +# CHECK-NEXT: Name: foo@@VER2 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Version: 2 +# CHECK-NEXT: Name: foo@VER1 +# CHECK-NEXT: } +# CHECK-NEXT: ] + +.global bar +bar: +.symver bar, foo@VER1 + +.global zed +zed: +.symver zed, foo@@VER2 diff --git a/test/ELF/version-script-undef-version.s b/test/ELF/version-script-undef-version.s new file mode 100644 index 000000000000..40dc816f5005 --- /dev/null +++ b/test/ELF/version-script-undef-version.s @@ -0,0 +1,12 @@ +# REQUIRES: x86 + +# Test that we don't error on undefined versions when static linking. +# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o +# RUN: ld.lld %t.o -o %t +# RUN: echo "DEFINED { global: *; };" > %t.map +# RUN: ld.lld %t.o --version-script %t.map -o %t + +.global _start +.global bar +.symver _start, bar@@UNDEFINED +_start: diff --git a/test/ELF/version-script-weak.s b/test/ELF/version-script-weak.s new file mode 100644 index 000000000000..cc3df8da5dc5 --- /dev/null +++ b/test/ELF/version-script-weak.s @@ -0,0 +1,28 @@ +# 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 %S/Inputs/version-script-weak.s -o %tmp.o +# RUN: rm -f %t.a +# RUN: llvm-ar rcs %t.a %tmp.o +# RUN: echo "{ local: *; };" > %t.script +# RUN: ld.lld -shared --version-script %t.script %t.o %t.a -o %t.so +# RUN: llvm-readobj -dyn-symbols -r %t.so | FileCheck %s + +# CHECK: Relocations [ +# CHECK-NEXT: Section ({{.*}}) .rela.plt { +# CHECK-NEXT: 0x2018 R_X86_64_JUMP_SLOT foo +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK: Symbol { +# 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 +# CHECK-NEXT: } + +.text + callq foo@PLT +.weak foo diff --git a/test/ELF/wrap-dynamic-undef.s b/test/ELF/wrap-dynamic-undef.s new file mode 100644 index 000000000000..95b985981013 --- /dev/null +++ b/test/ELF/wrap-dynamic-undef.s @@ -0,0 +1,15 @@ +# 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/wrap-dynamic-undef.s -o %t2.o +# RUN: ld.lld %t2.o -o %t2.so -shared +# RUN: ld.lld %t1.o %t2.so -o %t --wrap foo +# RUN: llvm-readobj -dyn-symbols --elf-output-style=GNU %t | FileCheck %s + +# Test that the dynamic relocation uses foo. We used to produce a +# relocation with __real_foo. + +# CHECK: NOTYPE GLOBAL DEFAULT UND foo + +.global _start +_start: + callq __real_foo@plt diff --git a/test/ELF/wrap.s b/test/ELF/wrap.s index d8d802bb8ca4..3e75fdbad811 100644 --- a/test/ELF/wrap.s +++ b/test/ELF/wrap.s @@ -12,12 +12,16 @@ // CHECK-NEXT: movl $0x11010, %edx // CHECK-NEXT: movl $0x11000, %edx +// This shows an oddity of our implementation. The symbol foo gets +// mapped to __wrap_foo, but stays in the symbol table. This results +// in it showing up twice in the output. + // RUN: llvm-readobj -t -s %t3 | FileCheck -check-prefix=SYM %s -// SYM: Name: __real_foo +// SYM: Name: foo // SYM-NEXT: Value: 0x11000 // SYM: Name: __wrap_foo // SYM-NEXT: Value: 0x11010 -// SYM: Name: foo +// SYM: Name: __wrap_foo // SYM-NEXT: Value: 0x11010 .global _start diff --git a/test/lit.cfg b/test/lit.cfg index cba56c642907..95bf3c0dc434 100644 --- a/test/lit.cfg +++ b/test/lit.cfg @@ -122,8 +122,8 @@ if config.test_exec_root is None: lit_config.fatal('No site specific configuration available!') # Get the source and object roots. - llvm_src_root = lit.util.capture(['llvm-config', '--src-root']).strip() - llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() + llvm_src_root = subprocess.check_output(['llvm-config', '--src-root']).strip() + llvm_obj_root = subprocess.check_output(['llvm-config', '--obj-root']).strip() lld_src_root = os.path.join(llvm_src_root, "tools", "lld") lld_obj_root = os.path.join(llvm_obj_root, "tools", "lld") |