aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-07-13 19:26:06 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-07-13 19:26:06 +0000
commit267829774358b5aebd3e726ae318813bd48129bb (patch)
tree5a8904da0d9716ea10b69258f5d50e0b1ee2ec2c
parent0317860f00ca8e821989c92c8a6cc461fd5f2009 (diff)
downloadsrc-267829774358b5aebd3e726ae318813bd48129bb.tar.gz
src-267829774358b5aebd3e726ae318813bd48129bb.zip
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
-rw-r--r--COFF/Chunks.cpp51
-rw-r--r--COFF/Chunks.h18
-rw-r--r--COFF/Config.h4
-rw-r--r--COFF/Driver.cpp2
-rw-r--r--COFF/DriverUtils.cpp15
-rw-r--r--COFF/Error.cpp5
-rw-r--r--COFF/Error.h1
-rw-r--r--COFF/InputFiles.cpp2
-rw-r--r--COFF/PDB.cpp174
-rw-r--r--COFF/PDB.h3
-rw-r--r--COFF/Symbols.cpp2
-rw-r--r--COFF/Writer.cpp2
-rw-r--r--ELF/Config.h1
-rw-r--r--ELF/Driver.cpp2
-rw-r--r--ELF/Error.cpp5
-rw-r--r--ELF/Error.h1
-rw-r--r--ELF/Filesystem.cpp3
-rw-r--r--ELF/GdbIndex.h1
-rw-r--r--ELF/InputFiles.cpp5
-rw-r--r--ELF/InputSection.cpp6
-rw-r--r--ELF/LinkerScript.cpp308
-rw-r--r--ELF/LinkerScript.h30
-rw-r--r--ELF/OutputSections.cpp98
-rw-r--r--ELF/OutputSections.h7
-rw-r--r--ELF/Relocations.cpp32
-rw-r--r--ELF/Relocations.h9
-rw-r--r--ELF/ScriptParser.cpp3
-rw-r--r--ELF/SymbolTable.cpp49
-rw-r--r--ELF/Symbols.cpp20
-rw-r--r--ELF/Symbols.h6
-rw-r--r--ELF/SyntheticSections.cpp65
-rw-r--r--ELF/SyntheticSections.h5
-rw-r--r--ELF/Thunks.cpp32
-rw-r--r--ELF/Thunks.h4
-rw-r--r--ELF/Writer.cpp167
-rw-r--r--lib/ReaderWriter/MachO/MachONormalizedFileBinaryReader.cpp6
-rw-r--r--test/COFF/Inputs/library-arm64.libbin0 -> 2000 bytes
-rw-r--r--test/COFF/Inputs/pdb-diff-cl.pdbbin0 -> 102400 bytes
-rw-r--r--test/COFF/Inputs/pdb-diff.cpp10
-rw-r--r--test/COFF/Inputs/pdb-diff.objbin0 -> 8602 bytes
-rw-r--r--test/COFF/Inputs/pdb-scopes-a.yaml425
-rw-r--r--test/COFF/Inputs/pdb-scopes-b.yaml365
-rw-r--r--test/COFF/arm64-magic.yaml46
-rw-r--r--test/COFF/arm64-relocs-imports.test136
-rw-r--r--test/COFF/combined-resources.test200
-rw-r--r--test/COFF/pdb-comdat.test6
-rw-r--r--test/COFF/pdb-diff.test212
-rw-r--r--test/COFF/pdb-invalid-func-type.yaml146
-rw-r--r--test/COFF/pdb-lib.s3
-rw-r--r--test/COFF/pdb-linker-module.test18
-rw-r--r--test/COFF/pdb-none.test4
-rw-r--r--test/COFF/pdb-scopes.test75
-rw-r--r--test/COFF/pdb-source-lines.test2
-rw-r--r--test/COFF/pdb-symbol-types.yaml2
-rw-r--r--test/COFF/pdb.test17
-rw-r--r--test/ELF/Inputs/gnu-ifunc-dso.s3
-rw-r--r--test/ELF/Inputs/symver-archive1.s6
-rw-r--r--test/ELF/Inputs/symver-archive2.s1
-rw-r--r--test/ELF/Inputs/version-script-no-warn2.s1
-rw-r--r--test/ELF/Inputs/version-script-weak.s4
-rw-r--r--test/ELF/Inputs/wrap-dynamic-undef.s2
-rw-r--r--test/ELF/arm-mov-relocs.s9
-rw-r--r--test/ELF/copy-in-shared.s2
-rw-r--r--test/ELF/defsym.s2
-rw-r--r--test/ELF/duplicated-synthetic-sym.s10
-rw-r--r--test/ELF/gnu-ifunc-dso.s13
-rw-r--r--test/ELF/invalid/Inputs/invalid-relocation-x64.elfbin559 -> 0 bytes
-rw-r--r--test/ELF/invalid/invalid-debug-relocations.test41
-rw-r--r--test/ELF/invalid/invalid-relocation-x64.test17
-rw-r--r--test/ELF/linkerscript/locationcountererr2.s6
-rw-r--r--test/ELF/linkerscript/non-alloc-segment.s44
-rw-r--r--test/ELF/linkerscript/out-of-order.s13
-rw-r--r--test/ELF/linkerscript/unused-synthetic.s18
-rw-r--r--test/ELF/lto/defsym.ll14
-rw-r--r--test/ELF/lto/wrap-1.ll7
-rw-r--r--test/ELF/lto/wrap-2.ll16
-rw-r--r--test/ELF/symver-archive.s15
-rw-r--r--test/ELF/version-script-no-warn2.s8
-rw-r--r--test/ELF/version-script-symver.s4
-rw-r--r--test/ELF/version-script-symver2.s28
-rw-r--r--test/ELF/version-script-undef-version.s12
-rw-r--r--test/ELF/version-script-weak.s28
-rw-r--r--test/ELF/wrap-dynamic-undef.s15
-rw-r--r--test/ELF/wrap.s8
-rw-r--r--test/lit.cfg4
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
new file mode 100644
index 000000000000..04e193dd16ba
--- /dev/null
+++ b/test/COFF/Inputs/library-arm64.lib
Binary files differ
diff --git a/test/COFF/Inputs/pdb-diff-cl.pdb b/test/COFF/Inputs/pdb-diff-cl.pdb
new file mode 100644
index 000000000000..ba5d8380e7c3
--- /dev/null
+++ b/test/COFF/Inputs/pdb-diff-cl.pdb
Binary files differ
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
new file mode 100644
index 000000000000..a8948bd0c513
--- /dev/null
+++ b/test/COFF/Inputs/pdb-diff.obj
Binary files differ
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
deleted file mode 100644
index 25df2944614e..000000000000
--- a/test/ELF/invalid/Inputs/invalid-relocation-x64.elf
+++ /dev/null
Binary files differ
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")